Botan  1.10.9
bzip2.cpp
Go to the documentation of this file.
1 /*
2 * Bzip 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/bzip2.h>
11 #include <botan/exceptn.h>
12 
13 #include <map>
14 #include <cstring>
15 #define BZ_NO_STDIO
16 #include <bzlib.h>
17 
18 namespace Botan {
19 
20 namespace {
21 
22 /*
23 * Allocation Information for Bzip
24 */
25 class Bzip_Alloc_Info
26  {
27  public:
28  std::map<void*, size_t> current_allocs;
29  Allocator* alloc;
30 
31  Bzip_Alloc_Info() { alloc = Allocator::get(false); }
32  };
33 
34 /*
35 * Allocation Function for Bzip
36 */
37 void* bzip_malloc(void* info_ptr, int n, int size)
38  {
39  Bzip_Alloc_Info* info = static_cast<Bzip_Alloc_Info*>(info_ptr);
40  void* ptr = info->alloc->allocate(n * size);
41  info->current_allocs[ptr] = n * size;
42  return ptr;
43  }
44 
45 /*
46 * Allocation Function for Bzip
47 */
48 void bzip_free(void* info_ptr, void* ptr)
49  {
50  Bzip_Alloc_Info* info = static_cast<Bzip_Alloc_Info*>(info_ptr);
51  std::map<void*, size_t>::const_iterator i = info->current_allocs.find(ptr);
52  if(i == info->current_allocs.end())
53  throw Invalid_Argument("bzip_free: Got pointer not allocated by us");
54  info->alloc->deallocate(ptr, i->second);
55  }
56 
57 }
58 
59 /**
60 * Wrapper Type for Bzip2 Stream
61 */
62 class Bzip_Stream
63  {
64  public:
65  /**
66  * Underlying stream
67  */
68  bz_stream stream;
69 
70  /**
71  * Constructor
72  */
73  Bzip_Stream()
74  {
75  std::memset(&stream, 0, sizeof(bz_stream));
76  stream.bzalloc = bzip_malloc;
77  stream.bzfree = bzip_free;
78  stream.opaque = new Bzip_Alloc_Info;
79  }
80 
81  /**
82  * Destructor
83  */
84  ~Bzip_Stream()
85  {
86  Bzip_Alloc_Info* info = static_cast<Bzip_Alloc_Info*>(stream.opaque);
87  delete info;
88  std::memset(&stream, 0, sizeof(bz_stream));
89  }
90  };
91 
92 /*
93 * Bzip_Compression Constructor
94 */
96  level((l >= 9) ? 9 : l), buffer(DEFAULT_BUFFERSIZE)
97  {
98  bz = 0;
99  }
100 
101 /*
102 * Start Compressing with Bzip
103 */
105  {
106  clear();
107  bz = new Bzip_Stream;
108  if(BZ2_bzCompressInit(&(bz->stream), level, 0, 0) != BZ_OK)
109  throw Memory_Exhaustion();
110  }
111 
112 /*
113 * Compress Input with Bzip
114 */
115 void Bzip_Compression::write(const byte input[], size_t length)
116  {
117  bz->stream.next_in = reinterpret_cast<char*>(const_cast<byte*>(input));
118  bz->stream.avail_in = length;
119 
120  while(bz->stream.avail_in != 0)
121  {
122  bz->stream.next_out = reinterpret_cast<char*>(buffer.begin());
123  bz->stream.avail_out = buffer.size();
124  BZ2_bzCompress(&(bz->stream), BZ_RUN);
125  send(buffer, buffer.size() - bz->stream.avail_out);
126  }
127  }
128 
129 /*
130 * Finish Compressing with Bzip
131 */
133  {
134  bz->stream.next_in = 0;
135  bz->stream.avail_in = 0;
136 
137  int rc = BZ_OK;
138  while(rc != BZ_STREAM_END)
139  {
140  bz->stream.next_out = reinterpret_cast<char*>(buffer.begin());
141  bz->stream.avail_out = buffer.size();
142  rc = BZ2_bzCompress(&(bz->stream), BZ_FINISH);
143  send(buffer, buffer.size() - bz->stream.avail_out);
144  }
145  clear();
146  }
147 
148 /*
149 * Flush the Bzip Compressor
150 */
152  {
153  bz->stream.next_in = 0;
154  bz->stream.avail_in = 0;
155 
156  int rc = BZ_OK;
157  while(rc != BZ_RUN_OK)
158  {
159  bz->stream.next_out = reinterpret_cast<char*>(buffer.begin());
160  bz->stream.avail_out = buffer.size();
161  rc = BZ2_bzCompress(&(bz->stream), BZ_FLUSH);
162  send(buffer, buffer.size() - bz->stream.avail_out);
163  }
164  }
165 
166 /*
167 * Clean up Compression Context
168 */
169 void Bzip_Compression::clear()
170  {
171  zeroise(buffer);
172 
173  if(bz)
174  {
175  BZ2_bzCompressEnd(&(bz->stream));
176  delete bz;
177  bz = 0;
178  }
179  }
180 
181 /*
182 * Bzip_Decompression Constructor
183 */
185  small_mem(s), buffer(DEFAULT_BUFFERSIZE)
186  {
187  no_writes = true;
188  bz = 0;
189  }
190 
191 /*
192 * Decompress Input with Bzip
193 */
194 void Bzip_Decompression::write(const byte input_arr[], size_t length)
195  {
196  if(length) no_writes = false;
197 
198  char* input = reinterpret_cast<char*>(const_cast<byte*>(input_arr));
199 
200  bz->stream.next_in = input;
201  bz->stream.avail_in = length;
202 
203  while(bz->stream.avail_in != 0)
204  {
205  bz->stream.next_out = reinterpret_cast<char*>(buffer.begin());
206  bz->stream.avail_out = buffer.size();
207 
208  int rc = BZ2_bzDecompress(&(bz->stream));
209 
210  if(rc != BZ_OK && rc != BZ_STREAM_END)
211  {
212  clear();
213 
214  if(rc == BZ_DATA_ERROR)
215  throw Decoding_Error("Bzip_Decompression: Data integrity error");
216  else if(rc == BZ_DATA_ERROR_MAGIC)
217  throw Decoding_Error("Bzip_Decompression: Invalid input");
218  else if(rc == BZ_MEM_ERROR)
219  throw Memory_Exhaustion();
220  else
221  throw std::runtime_error("Bzip2 decompression: Unknown error");
222  }
223 
224  send(buffer, buffer.size() - bz->stream.avail_out);
225 
226  if(rc == BZ_STREAM_END)
227  {
228  size_t read_from_block = length - bz->stream.avail_in;
229  start_msg();
230  bz->stream.next_in = input + read_from_block;
231  bz->stream.avail_in = length - read_from_block;
232  input += read_from_block;
233  length -= read_from_block;
234  }
235  }
236  }
237 
238 /*
239 * Start Decompressing with Bzip
240 */
242  {
243  clear();
244  bz = new Bzip_Stream;
245 
246  if(BZ2_bzDecompressInit(&(bz->stream), 0, small_mem) != BZ_OK)
247  throw Memory_Exhaustion();
248 
249  no_writes = true;
250  }
251 
252 /*
253 * Finish Decompressing with Bzip
254 */
256  {
257  if(no_writes) return;
258  bz->stream.next_in = 0;
259  bz->stream.avail_in = 0;
260 
261  int rc = BZ_OK;
262  while(rc != BZ_STREAM_END)
263  {
264  bz->stream.next_out = reinterpret_cast<char*>(buffer.begin());
265  bz->stream.avail_out = buffer.size();
266  rc = BZ2_bzDecompress(&(bz->stream));
267 
268  if(rc != BZ_OK && rc != BZ_STREAM_END)
269  {
270  clear();
271  throw Decoding_Error("Bzip_Decompression: Error finalizing");
272  }
273 
274  send(buffer, buffer.size() - bz->stream.avail_out);
275  }
276 
277  clear();
278  }
279 
280 /*
281 * Clean up Decompression Context
282 */
283 void Bzip_Decompression::clear()
284  {
285  zeroise(buffer);
286 
287  if(bz)
288  {
289  BZ2_bzDecompressEnd(&(bz->stream));
290  delete bz;
291  bz = 0;
292  }
293  }
294 
295 }
BigInt n
Definition: numthry.cpp:26
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
void write(const byte input[], size_t length)
Definition: bzip2.cpp:115
void write(const byte input[], size_t length)
Definition: bzip2.cpp:194
size_t size() const
Definition: secmem.h:29
std::map< void *, size_t > current_allocs
Definition: bzip2.cpp:28
Bzip_Compression(size_t=9)
Definition: bzip2.cpp:95
Bzip_Decompression(bool=false)
Definition: bzip2.cpp:184
Allocator * alloc
Definition: bzip2.cpp:29
void zeroise(MemoryRegion< T > &vec)
Definition: secmem.h:415
size_t s
Definition: numthry.cpp:27