Botan  1.10.9
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 */
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 */
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 */
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 */
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 */
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 */
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 }
BigInt n
Definition: numthry.cpp:26
void write(const byte input[], size_t length)
Definition: zlib.cpp:208
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20
static Allocator * get(bool locking)
Definition: defalloc.cpp:90
unsigned char byte
Definition: types.h:22
void send(const byte in[], size_t length)
Definition: filter.cpp:28
std::map< void *, size_t > current_allocs
Definition: zlib.cpp:27
size_t size() const
Definition: secmem.h:29
void write(const byte input[], size_t length)
Definition: zlib.cpp:114
Zlib_Compression(size_t level=6)
Definition: zlib.cpp:94
void zeroise(MemoryRegion< T > &vec)
Definition: secmem.h:415
Allocator * alloc
Definition: zlib.cpp:28