1
2 /***************************************************************************
3 * __ __ _ ___________ *
4 * \ \ / /| |____ ____| *
5 * \ \ / / | | | | *
6 * \ \ /\ / / | | | | *
7 * \ \/ \/ / | | | | *
8 * \ /\ / | | | | *
9 * \/ \/ |_| |_| *
10 * *
11 * Wiimms ISO Tools *
12 * http://wit.wiimm.de/ *
13 * *
14 ***************************************************************************
15 * *
16 * This file is part of the WIT project. *
17 * Visit http://wit.wiimm.de/ for project details and sources. *
18 * *
19 * Copyright (c) 2009-2013 by Dirk Clemens <wiimm@wiimm.de> *
20 * *
21 ***************************************************************************
22 * *
23 * This program is free software; you can redistribute it and/or modify *
24 * it under the terms of the GNU General Public License as published by *
25 * the Free Software Foundation; either version 2 of the License, or *
26 * (at your option) any later version. *
27 * *
28 * This program is distributed in the hope that it will be useful, *
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
31 * GNU General Public License for more details. *
32 * *
33 * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt *
34 * *
35 ***************************************************************************/
36
37 #define _GNU_SOURCE 1
38
39 /******************/
40 #ifndef NO_BZIP2
41 /******************/
42
43 //#include <bzlib.h>
44 #include "libbz2/bzlib.h"
45 #include "lib-bzip2.h"
46
47 /************************************************************************
48 ** BZIP2 support: http://www.bzip.org/1.0.5/bzip2-manual-1.0.5.html **
49 ************************************************************************/
50
51 //
52 ///////////////////////////////////////////////////////////////////////////////
53 /////////////// BZIP2 helpers ///////////////
54 ///////////////////////////////////////////////////////////////////////////////
55
GetMessageBZIP2(int err,ccp unkown_error)56 ccp GetMessageBZIP2
57 (
58 int err, // error code
59 ccp unkown_error // result for unkown error codes
60 )
61 {
62 switch (err)
63 {
64 case BZ_OK: return "OK";
65
66 case BZ_CONFIG_ERROR: return "CONFIG ERROR";
67 case BZ_DATA_ERROR: return "DATA ERROR";
68 case BZ_DATA_ERROR_MAGIC: return "DATA ERROR MAGIC";
69 case BZ_IO_ERROR: return "IO ERROR";
70 case BZ_MEM_ERROR: return "MEM ERROR";
71 case BZ_PARAM_ERROR: return "PARAM ERROR";
72 case BZ_SEQUENCE_ERROR: return "SEQUENCE ERROR";
73 case BZ_STREAM_END: return "STREAM END";
74 case BZ_UNEXPECTED_EOF: return "UNEXPECTED EOF";
75 }
76
77 return unkown_error;
78 };
79
80 ///////////////////////////////////////////////////////////////////////////////
81
CalcCompressionLevelBZIP2(int compr_level)82 int CalcCompressionLevelBZIP2
83 (
84 int compr_level // valid are 1..9 / 0: use default value
85 )
86 {
87 return compr_level < 1
88 ? 5
89 : compr_level < 9
90 ? compr_level
91 : 9;
92 }
93
94 ///////////////////////////////////////////////////////////////////////////////
95
CalcMemoryUsageBZIP2(int compr_level,bool is_writing)96 u32 CalcMemoryUsageBZIP2
97 (
98 int compr_level, // valid are 1..9 / 0: use default value
99 bool is_writing // false: reading mode, true: writing mode
100 )
101 {
102 compr_level = CalcCompressionLevelBZIP2(compr_level);
103 return is_writing
104 ? ( 4 + 8 * compr_level ) * 102400
105 : ( 1 + 4 * compr_level ) * 102400;
106 }
107
108 //
109 ///////////////////////////////////////////////////////////////////////////////
110 /////////////// BZIP2 writing ///////////////
111 ///////////////////////////////////////////////////////////////////////////////
112
EncBZIP2_Open(BZIP2_t * bz,File_t * file,int compr_level)113 enumError EncBZIP2_Open
114 (
115 BZIP2_t * bz, // data structure, will be initialized
116 File_t * file, // destination file
117 int compr_level // valid are 1..9 / 0: use default value
118 )
119 {
120 DASSERT(bz);
121 DASSERT(file);
122 DASSERT(file->fp);
123
124 bz->file = file;
125 bz->compr_level = CalcCompressionLevelBZIP2(compr_level);
126
127 int bzerror;
128 bz->handle = BZ2_bzWriteOpen(&bzerror,file->fp,bz->compr_level,0,0);
129 if ( !bz || bzerror != BZ_OK )
130 {
131 if (bz->handle)
132 {
133 BZ2_bzWriteClose(0,bz->handle,0,0,0);
134 bz->handle = 0;
135 }
136
137 return ERROR0(ERR_BZIP2,
138 "Error while opening bzip2 stream: %s\n-> bzip2 error: %s\n",
139 bz->file->fname, GetMessageBZIP2(bzerror,"?") );
140 return 0;
141 }
142
143 return ERR_OK;
144 }
145
146 ///////////////////////////////////////////////////////////////////////////////
147
EncBZIP2_Write(BZIP2_t * bz,const void * data,size_t data_size)148 enumError EncBZIP2_Write
149 (
150 BZIP2_t * bz, // created by EncBZIP2_Open()
151 const void * data, // data to write
152 size_t data_size // size of data to write
153 )
154 {
155 DASSERT(bz);
156 DASSERT(bz->handle);
157
158 if (data_size)
159 {
160 int bzerror;
161 BZ2_bzWrite(&bzerror,bz->handle,(u8*)data,data_size);
162 if ( bzerror != BZ_OK )
163 {
164 BZ2_bzWriteClose(0,bz->handle,0,0,0);
165 bz->handle = 0;
166
167 return ERROR0(ERR_BZIP2,
168 "Error while writing bzip2 stream: %s\n-> bzip2 error: %s\n",
169 bz->file->fname, GetMessageBZIP2(bzerror,"?") );
170 }
171 bz->file->bytes_written += data_size;
172 }
173
174 return ERR_OK;
175 }
176
177 ///////////////////////////////////////////////////////////////////////////////
178
EncBZIP2_Close(BZIP2_t * bz,u32 * bytes_written)179 enumError EncBZIP2_Close
180 (
181 BZIP2_t * bz, // NULL or created by EncBZIP2_Open()
182 u32 * bytes_written // not NULL: store written bytes
183 )
184 {
185 u32 written = 0;
186 if ( bz && bz->handle )
187 {
188 int bzerror;
189 BZ2_bzWriteClose(&bzerror,bz->handle,0,0,&written);
190 bz->handle = 0;
191
192 if ( bzerror != BZ_OK )
193 return ERROR0(ERR_BZIP2,
194 "Error while closing bzip2 stream: %s\n-> bzip2 error: %s\n",
195 bz->file->fname, GetMessageBZIP2(bzerror,"?") );
196
197 }
198
199 if (bytes_written)
200 *bytes_written = written;
201
202 return ERR_OK;
203 }
204
205 //
206 ///////////////////////////////////////////////////////////////////////////////
207 /////////////// BZIP2 reading ///////////////
208 ///////////////////////////////////////////////////////////////////////////////
209
DecBZIP2_Open(BZIP2_t * bz,File_t * file)210 enumError DecBZIP2_Open
211 (
212 BZIP2_t * bz, // data structure, will be initialized
213 File_t * file // source file
214 )
215 {
216 DASSERT(file);
217 DASSERT(file->fp);
218
219 bz->file = file;
220
221 int bzerror;
222 bz->handle = BZ2_bzReadOpen(&bzerror,file->fp,0,0,0,0);
223 if ( !bz->handle || bzerror != BZ_OK )
224 {
225 if (bz->handle)
226 {
227 BZ2_bzReadClose(0,bz->handle);
228 bz->handle = 0;
229 }
230
231 return ERROR0(ERR_BZIP2,
232 "Error while opening bzip2 stream: %s\n-> bzip2 error: %s\n",
233 bz->file->fname, GetMessageBZIP2(bzerror,"?") );
234 }
235
236 return ERR_OK;
237 }
238
239 ///////////////////////////////////////////////////////////////////////////////
240
DecBZIP2_Read(BZIP2_t * bz,void * buf,size_t buf_size,u32 * buf_written)241 enumError DecBZIP2_Read
242 (
243 BZIP2_t * bz, // created by DecBZIP2_Open()
244 void * buf, // destination buffer
245 size_t buf_size, // size of destination buffer
246 u32 * buf_written // not NULL: store bytes written to buf
247 )
248 {
249 DASSERT(bz);
250 DASSERT(bz->handle);
251 DASSERT(buf);
252
253 int bzerror;
254 const u32 written = BZ2_bzRead(&bzerror,bz->handle,buf,buf_size);
255 noPRINT("BZREAD, num=%x, buf_size=%zx, err=%d\n",written,buf_size,bzerror);
256 if ( bzerror != BZ_STREAM_END )
257 {
258 BZ2_bzReadClose(0,bz->handle);
259 bz->handle = 0;
260
261 return ERROR0(ERR_BZIP2,
262 "Error while reading bzip2 stream: %s\n-> bzip2 error: %s\n",
263 bz->file->fname, GetMessageBZIP2(bzerror,"?") );
264 }
265
266 bz->file->bytes_read += written;
267 if (buf_written)
268 *buf_written = written;
269 return ERR_OK;
270 }
271
272 ///////////////////////////////////////////////////////////////////////////////
273
DecBZIP2_Close(BZIP2_t * bz)274 enumError DecBZIP2_Close
275 (
276 BZIP2_t * bz // NULL or created by DecBZIP2_Open()
277 )
278 {
279 if ( bz && bz->handle )
280 {
281 int bzerror;
282 BZ2_bzReadClose(&bzerror,bz->handle);
283 bz->handle = 0;
284
285 if ( bzerror != BZ_OK )
286 return ERROR0(ERR_BZIP2,
287 "Error while closing bzip2 stream: %s\n-> bzip2 error: %s\n",
288 bz->file->fname, GetMessageBZIP2(bzerror,"?") );
289 }
290
291 return ERR_OK;
292 }
293
294 //
295 ///////////////////////////////////////////////////////////////////////////////
296 /////////////// BZIP2 memory conversions ///////////////
297 ///////////////////////////////////////////////////////////////////////////////
298
EncBZIP2buf(void * dest,uint dest_size,uint * dest_written,const void * src,uint src_size,int compr_level)299 enumError EncBZIP2buf
300 (
301 void *dest, // valid destination buffer
302 uint dest_size, // size of 'dest'
303 uint *dest_written, // store num bytes written to 'dest', never NULL
304
305 const void *src, // source buffer
306 uint src_size, // size of source buffer
307
308 int compr_level // valid are 1..9 / 0: use default value
309 )
310 {
311 // http://www.bzip.org/1.0.3/html/util-fns.html#bzbufftobuffcompress
312
313 DASSERT(dest);
314 DASSERT( dest_size > sizeof(u32) );
315 DASSERT(dest_written);
316 DASSERT(src);
317
318 compr_level = CalcCompressionLevelBZIP2(compr_level);
319 PRINT("EncBZIP2buf() %u bytes, level = %u\n",src_size,compr_level);
320
321 *(u32*)dest = htonl(src_size);
322 *dest_written = dest_size - sizeof(u32);
323 int bzerror = BZ2_bzBuffToBuffCompress ( dest+sizeof(u32), dest_written,
324 (char*)src, src_size, compr_level, 0, 0 );
325 *dest_written += 4;
326
327 if ( bzerror != BZ_OK )
328 return ERROR0(ERR_BZIP2,
329 "Error while compressing data.\n-> bzip2 error: %s\n",
330 GetMessageBZIP2(bzerror,"?") );
331
332 return ERR_OK;
333 }
334
335 ///////////////////////////////////////////////////////////////////////////////
336
EncBZIP2(u8 ** dest_ptr,uint * dest_written,bool use_iobuf,const void * src,uint src_size,int compr_level)337 enumError EncBZIP2
338 (
339 u8 **dest_ptr, // result: store destination buffer addr
340 uint *dest_written, // store num bytes written to 'dest', never NULL
341 bool use_iobuf, // true: allow thhe usage of 'iobuf'
342
343 const void *src, // source buffer
344 uint src_size, // size of source buffer
345
346 int compr_level // valid are 1..9 / 0: use default value
347 )
348 {
349 DASSERT(dest_ptr);
350 DASSERT(dest_written);
351 DASSERT(src);
352
353 char *dest;
354 uint dest_size = src_size + src_size/100 + 600 + 20;
355 if ( dest_size <= sizeof(iobuf) && use_iobuf )
356 {
357 dest = iobuf;
358 dest_size = sizeof(iobuf);
359 }
360 else
361 dest = MALLOC(dest_size);
362
363 enumError err = EncBZIP2buf(dest,dest_size,dest_written,src,src_size,compr_level);
364 if (err)
365 {
366 if ( dest != iobuf )
367 FREE(dest);
368 *dest_ptr = 0;
369 *dest_written = 0;
370 }
371 else if ( dest == iobuf )
372 *dest_ptr = MEMDUP(iobuf,*dest_written);
373 else
374 *dest_ptr = REALLOC(dest,*dest_written);
375 return err;
376 }
377
378 ///////////////////////////////////////////////////////////////////////////////
379 ///////////////////////////////////////////////////////////////////////////////
380
DecBZIP2buf(void * dest,uint dest_size,uint * dest_written,const void * src,uint src_size)381 enumError DecBZIP2buf
382 (
383 void *dest, // valid destination buffer
384 uint dest_size, // size of 'dest'
385 uint *dest_written, // store num bytes written to 'dest', never NULL
386
387 const void *src, // source buffer
388 uint src_size // size of source buffer
389 )
390 {
391 // http://www.bzip.org/1.0.3/html/util-fns.html#bzbufftobuffdecompress
392
393 DASSERT(dest);
394 DASSERT( dest_size >= sizeof(u32) );
395 DASSERT(dest_written);
396 DASSERT(src);
397
398 uint dest_need = ntohl(*(u32*)src);
399 *dest_written = dest_need;
400 PRINT("DecBZIP2buf() %u -> %u,%u bytes\n",src_size,dest_size,dest_need);
401
402 int bzerror = BZ2_bzBuffToBuffDecompress ( (char*)dest, dest_written,
403 (char*)src+4, src_size-4, 0, 0 );
404
405 if ( bzerror != BZ_OK )
406 return ERROR0(ERR_BZIP2,
407 "Error while decompressing data.\n-> bzip2 error: %s\n",
408 GetMessageBZIP2(bzerror,"?") );
409
410 return ERR_OK;
411 }
412
413 ///////////////////////////////////////////////////////////////////////////////
414
DecBZIP2(u8 ** dest_ptr,uint * dest_written,const void * src,uint src_size)415 enumError DecBZIP2
416 (
417 u8 **dest_ptr, // result: store destination buffer addr
418 uint *dest_written, // store num bytes written to 'dest', never NULL
419 const void *src, // source buffer
420 uint src_size // size of source buffer
421 )
422 {
423 DASSERT(dest_ptr);
424 DASSERT(dest_written);
425 DASSERT(src);
426 DASSERT( src_size >= sizeof(u32) );
427
428 uint dest_size = ntohl(*(u32*)src);
429 *dest_ptr = MALLOC(dest_size);
430
431 enumError err = DecBZIP2buf(*dest_ptr,dest_size,dest_written,src,src_size);
432 if (err)
433 {
434 FREE(*dest_ptr);
435 *dest_ptr = 0;
436 *dest_written = 0;
437 }
438 return err;
439 }
440
441 //
442 ///////////////////////////////////////////////////////////////////////////////
443 /////////////// END ///////////////
444 ///////////////////////////////////////////////////////////////////////////////
445
446 /*********************/
447 #endif // !NO_BZIP2
448 /*********************/
449
450