Botan: src/filters/bzip2/bzip2.cpp Source File

Botan 1.10.17

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 */
95 Bzip_Compression::Bzip_Compression(size_t l) :
96 level((l >= 9) ? 9 : l), buffer(DEFAULT_BUFFERSIZE)
97 {
98 bz = 0;
99 }
100
101 /*
102 * Start Compressing with Bzip
103 */
104 void Bzip_Compression::start_msg()
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 */
132 void Bzip_Compression::end_msg()
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 */
151 void Bzip_Compression::flush()
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 */
184 Bzip_Decompression::Bzip_Decompression(bool s) :
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 */
241 void Bzip_Decompression::start_msg()
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 */
255 void Bzip_Decompression::end_msg()
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 }
Botan::Memory_Exhaustion
Definition: exceptn.h:185
Botan::Bzip_Compression::flush
void flush()
Definition: bzip2.cpp:151
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
Botan::Filter::send
void send(const byte in[], size_t length)
Definition: filter.cpp:28
Botan::Bzip_Compression::write
void write(const byte input[], size_t length)
Definition: bzip2.cpp:115
Botan::Decoding_Error
Definition: exceptn.h:138
Botan::Bzip_Decompression::write
void write(const byte input[], size_t length)
Definition: bzip2.cpp:194
Botan
Definition: algo_base.h:14
Botan::Bzip_Compression::start_msg
void start_msg()
Definition: bzip2.cpp:104
Botan::MemoryRegion::size
size_t size() const
Definition: secmem.h:29
current_allocs
std::map< void *, size_t > current_allocs
Definition: bzip2.cpp:28
Botan::MemoryRegion::begin
T * begin()
Definition: secmem.h:59
Botan::Bzip_Compression::Bzip_Compression
Bzip_Compression(size_t=9)
Definition: bzip2.cpp:95
Botan::Bzip_Decompression::start_msg
void start_msg()
Definition: bzip2.cpp:241
Botan::Bzip_Decompression::end_msg
void end_msg()
Definition: bzip2.cpp:255
Botan::Bzip_Decompression::Bzip_Decompression
Bzip_Decompression(bool=false)
Definition: bzip2.cpp:184
alloc
Allocator * alloc
Definition: bzip2.cpp:29
Botan::zeroise
void zeroise(MemoryRegion< T > &vec)
Definition: secmem.h:428
Botan::Bzip_Compression::end_msg
void end_msg()
Definition: bzip2.cpp:132