Botan 1.10.17

zlib.cpp
Go to the documentation of this file.
1 /*
2 * Zlib Compressor
3 * (C) 2001 Peter J Jones
4 * 2001-2007 Jack Lloyd
5 * 2006 Matt Johnston
6 *
7 * Distributed under the terms of the Botan license
8 */
9
10 #include <botan/zlib.h>
11 #include <botan/exceptn.h>
12
13 #include <cstring>
14 #include <map>
15 #include <zlib.h>
16
17 namespace Botan {
18
19 namespace {
20
21 /*
22 * Allocation Information for Zlib
23 */
24 class Zlib_Alloc_Info
25 {
26 public:
27 std::map<void*, size_t> current_allocs;
28 Allocator* alloc;
29
30 Zlib_Alloc_Info() { alloc = Allocator::get(false); }
31 };
32
33 /*
34 * Allocation Function for Zlib
35 */
36 void* zlib_malloc(void* info_ptr, unsigned int n, unsigned int size)
37 {
38 Zlib_Alloc_Info* info = static_cast<Zlib_Alloc_Info*>(info_ptr);
39 void* ptr = info->alloc->allocate(n * size);
40 info->current_allocs[ptr] = n * size;
41 return ptr;
42 }
43
44 /*
45 * Allocation Function for Zlib
46 */
47 void zlib_free(void* info_ptr, void* ptr)
48 {
49 Zlib_Alloc_Info* info = static_cast<Zlib_Alloc_Info*>(info_ptr);
50 std::map<void*, size_t>::const_iterator i = info->current_allocs.find(ptr);
51 if(i == info->current_allocs.end())
52 throw Invalid_Argument("zlib_free: Got pointer not allocated by us");
53 info->alloc->deallocate(ptr, i->second);
54 }
55
56 }
57
58 /**
59 * Wrapper Type for Zlib z_stream
60 */
61 class Zlib_Stream
62 {
63 public:
64 /**
65 * Underlying stream
66 */
67 z_stream stream;
68
69 /**
70 * Constructor
71 */
72 Zlib_Stream()
73 {
74 std::memset(&stream, 0, sizeof(z_stream));
75 stream.zalloc = zlib_malloc;
76 stream.zfree = zlib_free;
77 stream.opaque = new Zlib_Alloc_Info;
78 }
79
80 /**
81 * Destructor
82 */
83 ~Zlib_Stream()
84 {
85 Zlib_Alloc_Info* info = static_cast<Zlib_Alloc_Info*>(stream.opaque);
86 delete info;
87 std::memset(&stream, 0, sizeof(z_stream));
88 }
89 };
90
91 /*
92 * Zlib_Compression Constructor
93 */
94 Zlib_Compression::Zlib_Compression(size_t l) :
95 level((l >= 9) ? 9 : l), buffer(DEFAULT_BUFFERSIZE)
96 {
97 zlib = 0;
98 }
99
100 /*
101 * Start Compressing with Zlib
102 */
103 void Zlib_Compression::start_msg()
104 {
105 clear();
106 zlib = new Zlib_Stream;
107 if(deflateInit(&(zlib->stream), level) != Z_OK)
108 throw Memory_Exhaustion();
109 }
110
111 /*
112 * Compress Input with Zlib
113 */
114 void Zlib_Compression::write(const byte input[], size_t length)
115 {
116 zlib->stream.next_in = static_cast<Bytef*>(const_cast<byte*>(input));
117 zlib->stream.avail_in = length;
118
119 while(zlib->stream.avail_in != 0)
120 {
121 zlib->stream.next_out = static_cast<Bytef*>(buffer.begin());
122 zlib->stream.avail_out = buffer.size();
123 deflate(&(zlib->stream), Z_NO_FLUSH);
124 send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
125 }
126 }
127
128 /*
129 * Finish Compressing with Zlib
130 */
131 void Zlib_Compression::end_msg()
132 {
133 zlib->stream.next_in = 0;
134 zlib->stream.avail_in = 0;
135
136 int rc = Z_OK;
137 while(rc != Z_STREAM_END)
138 {
139 zlib->stream.next_out = reinterpret_cast<Bytef*>(buffer.begin());
140 zlib->stream.avail_out = buffer.size();
141
142 rc = deflate(&(zlib->stream), Z_FINISH);
143 send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
144 }
145
146 clear();
147 }
148
149 /*
150 * Flush the Zlib Compressor
151 */
152 void Zlib_Compression::flush()
153 {
154 zlib->stream.next_in = 0;
155 zlib->stream.avail_in = 0;
156
157 while(true)
158 {
159 zlib->stream.avail_out = buffer.size();
160 zlib->stream.next_out = reinterpret_cast<Bytef*>(buffer.begin());
161
162 deflate(&(zlib->stream), Z_FULL_FLUSH);
163 send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
164
165 if(zlib->stream.avail_out == buffer.size())
166 break;
167 }
168 }
169
170 /*
171 * Clean up Compression Context
172 */
173 void Zlib_Compression::clear()
174 {
175 zeroise(buffer);
176
177 if(zlib)
178 {
179 deflateEnd(&(zlib->stream));
180 delete zlib;
181 zlib = 0;
182 }
183 }
184
185 /*
186 * Zlib_Decompression Constructor
187 */
188 Zlib_Decompression::Zlib_Decompression() : buffer(DEFAULT_BUFFERSIZE)
189 {
190 zlib = 0;
191 no_writes = true;
192 }
193
194 /*
195 * Start Decompressing with Zlib
196 */
197 void Zlib_Decompression::start_msg()
198 {
199 clear();
200 zlib = new Zlib_Stream;
201 if(inflateInit(&(zlib->stream)) != Z_OK)
202 throw Memory_Exhaustion();
203 }
204
205 /*
206 * Decompress Input with Zlib
207 */
208 void Zlib_Decompression::write(const byte input_arr[], size_t length)
209 {
210 if(length) no_writes = false;
211
212 // non-const needed by zlib api :(
213 Bytef* input = reinterpret_cast<Bytef*>(const_cast<byte*>(input_arr));
214
215 zlib->stream.next_in = input;
216 zlib->stream.avail_in = length;
217
218 while(zlib->stream.avail_in != 0)
219 {
220 zlib->stream.next_out = reinterpret_cast<Bytef*>(buffer.begin());
221 zlib->stream.avail_out = buffer.size();
222
223 int rc = inflate(&(zlib->stream), Z_SYNC_FLUSH);
224
225 if(rc != Z_OK && rc != Z_STREAM_END)
226 {
227 clear();
228 if(rc == Z_DATA_ERROR)
229 throw Decoding_Error("Zlib_Decompression: Data integrity error");
230 else if(rc == Z_NEED_DICT)
231 throw Decoding_Error("Zlib_Decompression: Need preset dictionary");
232 else if(rc == Z_MEM_ERROR)
233 throw Memory_Exhaustion();
234 else
235 throw std::runtime_error("Zlib decompression: Unknown error");
236 }
237
238 send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
239
240 if(rc == Z_STREAM_END)
241 {
242 size_t read_from_block = length - zlib->stream.avail_in;
243 start_msg();
244
245 zlib->stream.next_in = input + read_from_block;
246 zlib->stream.avail_in = length - read_from_block;
247
248 input += read_from_block;
249 length -= read_from_block;
250 }
251 }
252 }
253
254 /*
255 * Finish Decompressing with Zlib
256 */
257 void Zlib_Decompression::end_msg()
258 {
259 if(no_writes) return;
260 zlib->stream.next_in = 0;
261 zlib->stream.avail_in = 0;
262
263 int rc = Z_OK;
264
265 while(rc != Z_STREAM_END)
266 {
267 zlib->stream.next_out = reinterpret_cast<Bytef*>(buffer.begin());
268 zlib->stream.avail_out = buffer.size();
269 rc = inflate(&(zlib->stream), Z_SYNC_FLUSH);
270
271 if(rc != Z_OK && rc != Z_STREAM_END)
272 {
273 clear();
274 throw Decoding_Error("Zlib_Decompression: Error finalizing");
275 }
276
277 send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
278 }
279
280 clear();
281 }
282
283 /*
284 * Clean up Decompression Context
285 */
286 void Zlib_Decompression::clear()
287 {
288 zeroise(buffer);
289
290 no_writes = true;
291
292 if(zlib)
293 {
294 inflateEnd(&(zlib->stream));
295 delete zlib;
296 zlib = 0;
297 }
298 }
299
300 }
Botan::Memory_Exhaustion
Definition: exceptn.h:185
Botan::Zlib_Decompression::write
void write(const byte input[], size_t length)
Definition: zlib.cpp:208
Botan::Zlib_Compression::flush
void flush()
Definition: zlib.cpp:152
Botan::Invalid_Argument
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20
Botan::Allocator::get
static Allocator * get(bool locking)
Definition: defalloc.cpp:90
Botan::byte
unsigned char byte
Definition: types.h:22
zlib.h
Botan::Filter::send
void send(const byte in[], size_t length)
Definition: filter.cpp:28
current_allocs
std::map< void *, size_t > current_allocs
Definition: zlib.cpp:27
Botan::Zlib_Compression::end_msg
void end_msg()
Definition: zlib.cpp:131
Botan::Zlib_Decompression::end_msg
void end_msg()
Definition: zlib.cpp:257
Botan::Zlib_Decompression::Zlib_Decompression
Zlib_Decompression()
Definition: zlib.cpp:188
Botan::Decoding_Error
Definition: exceptn.h:138
Botan
Definition: algo_base.h:14
Botan::Zlib_Compression::write
void write(const byte input[], size_t length)
Definition: zlib.cpp:114
Botan::MemoryRegion::size
size_t size() const
Definition: secmem.h:29
Botan::Zlib_Decompression::start_msg
void start_msg()
Definition: zlib.cpp:197
Botan::Zlib_Compression::Zlib_Compression
Zlib_Compression(size_t level=6)
Definition: zlib.cpp:94
Botan::MemoryRegion::begin
T * begin()
Definition: secmem.h:59
Botan::zeroise
void zeroise(MemoryRegion< T > &vec)
Definition: secmem.h:428
Botan::Zlib_Compression::start_msg
void start_msg()
Definition: zlib.cpp:103
alloc
Allocator * alloc
Definition: zlib.cpp:28