1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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();
}
|