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