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
17namespace Botan {
18
19namespace {
20
21/*
22* Allocation Information for Zlib
23*/
24class 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*/
36void* 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*/
47void 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*/
61class 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*/
95 level((l >= 9) ? 9 : l), buffer(DEFAULT_BUFFERSIZE)
96 {
97 zlib = 0;
98 }
99
100/*
101* Start Compressing with Zlib
102*/
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*/
114void 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*/
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*/
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*/
173void 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*/
188Zlib_Decompression::Zlib_Decompression() : buffer(DEFAULT_BUFFERSIZE)
189 {
190 zlib = 0;
191 no_writes = true;
192 }
193
194/*
195* Start Decompressing with Zlib
196*/
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*/
208void 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*/
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*/
286void 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}
static Allocator * get(bool locking)
Definition defalloc.cpp:90
void send(const byte in[], size_t length)
Definition filter.cpp:28
void write(const byte input[], size_t length)
Definition zlib.cpp:114
Zlib_Compression(size_t level=6)
Definition zlib.cpp:94
void write(const byte input[], size_t length)
Definition zlib.cpp:208
void zeroise(MemoryRegion< T > &vec)
Definition secmem.h:428
std::invalid_argument Invalid_Argument
Definition exceptn.h:20
Decoding_Error(const std::string &name)
Definition exceptn.h:140