summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/base/src/nsMsgCompressOStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/base/src/nsMsgCompressOStream.cpp')
-rw-r--r--comm/mailnews/base/src/nsMsgCompressOStream.cpp128
1 files changed, 128 insertions, 0 deletions
diff --git a/comm/mailnews/base/src/nsMsgCompressOStream.cpp b/comm/mailnews/base/src/nsMsgCompressOStream.cpp
new file mode 100644
index 0000000000..fd490274ca
--- /dev/null
+++ b/comm/mailnews/base/src/nsMsgCompressOStream.cpp
@@ -0,0 +1,128 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsMsgCompressOStream.h"
+#include "prio.h"
+#include "prmem.h"
+
+#define BUFFER_SIZE 16384
+
+nsMsgCompressOStream::nsMsgCompressOStream() : m_zbuf(nullptr) {}
+
+nsMsgCompressOStream::~nsMsgCompressOStream() { Close(); }
+
+NS_IMPL_ISUPPORTS(nsMsgCompressOStream, nsIOutputStream)
+
+nsresult nsMsgCompressOStream::InitOutputStream(nsIOutputStream* rawStream) {
+ // protect against repeat calls
+ if (m_oStream) return NS_ERROR_UNEXPECTED;
+
+ // allocate some memory for a buffer
+ m_zbuf = mozilla::MakeUnique<char[]>(BUFFER_SIZE);
+ if (!m_zbuf) return NS_ERROR_OUT_OF_MEMORY;
+
+ // set up the zlib object
+ m_zstream.zalloc = Z_NULL;
+ m_zstream.zfree = Z_NULL;
+ m_zstream.opaque = Z_NULL;
+
+ // http://zlib.net/manual.html is rather silent on the topic, but
+ // perl's Compress::Raw::Zlib manual says:
+ // -WindowBits [...]
+ // To compress an RFC 1951 data stream, set WindowBits to -MAX_WBITS.
+ if (deflateInit2(&m_zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
+ MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK)
+ return NS_ERROR_FAILURE;
+
+ m_oStream = rawStream;
+
+ return NS_OK;
+}
+
+/* void close (); */
+NS_IMETHODIMP nsMsgCompressOStream::Close() {
+ if (m_oStream) {
+ m_oStream = nullptr;
+ deflateEnd(&m_zstream);
+ }
+ m_zbuf = nullptr;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgCompressOStream::Write(const char* buf, uint32_t count, uint32_t* result) {
+ if (!m_oStream) return NS_BASE_STREAM_CLOSED;
+
+ m_zstream.next_in = (Bytef*)buf;
+ m_zstream.avail_in = count;
+
+ // keep looping until the buffer doesn't get filled
+ do {
+ m_zstream.next_out = (Bytef*)m_zbuf.get();
+ m_zstream.avail_out = BUFFER_SIZE;
+ // Using "Z_SYNC_FLUSH" may cause excess flushes if the calling
+ // code does a lot of small writes. An option with the IMAP
+ // protocol is to check the buffer for "\n" at the end, but
+ // in the interests of keeping this generic, don't optimise
+ // yet. An alternative is to require ->Flush always, but that
+ // is likely to break callers.
+ int zr = deflate(&m_zstream, Z_SYNC_FLUSH);
+ if (zr == Z_STREAM_END || zr == Z_BUF_ERROR)
+ zr = Z_OK; // not an error for our purposes
+ if (zr != Z_OK) return NS_ERROR_FAILURE;
+
+ uint32_t out_size = BUFFER_SIZE - m_zstream.avail_out;
+ const char* out_buf = m_zbuf.get();
+
+ // push everything in the buffer before repeating
+ while (out_size) {
+ uint32_t out_result;
+ nsresult rv = m_oStream->Write(out_buf, out_size, &out_result);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!out_result) return NS_BASE_STREAM_CLOSED;
+ out_size -= out_result;
+ out_buf += out_result;
+ }
+
+ // http://www.zlib.net/manual.html says:
+ // If deflate returns with avail_out == 0, this function must be
+ // called again with the same value of the flush parameter and
+ // more output space (updated avail_out), until the flush is
+ // complete (deflate returns with non-zero avail_out).
+ } while (!m_zstream.avail_out);
+
+ *result = count;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgCompressOStream::Flush(void) {
+ if (!m_oStream) return NS_BASE_STREAM_CLOSED;
+
+ return m_oStream->Flush();
+}
+
+NS_IMETHODIMP
+nsMsgCompressOStream::WriteFrom(nsIInputStream* inStr, uint32_t count,
+ uint32_t* _retval) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsMsgCompressOStream::WriteSegments(nsReadSegmentFun reader, void* closure,
+ uint32_t count, uint32_t* _retval) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* boolean isNonBlocking (); */
+NS_IMETHODIMP nsMsgCompressOStream::IsNonBlocking(bool* aNonBlocking) {
+ *aNonBlocking = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgCompressOStream::StreamStatus() {
+ return m_oStream->StreamStatus();
+}