blob: cdb596cb16d4ca94da8ee63fa88f4ad4fe8e5442 [file] [log] [blame]
Denis Vlasenko77f1ec12007-10-13 03:36:03 +00001/*
2 * bzip2 is written by Julian Seward <jseward@bzip.org>.
3 * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
4 * See README and LICENSE files in this directory for more information.
5 */
6
7/*-------------------------------------------------------------*/
8/*--- Library top-level functions. ---*/
9/*--- bzlib.c ---*/
10/*-------------------------------------------------------------*/
11
12/* ------------------------------------------------------------------
13This file is part of bzip2/libbzip2, a program and library for
14lossless, block-sorting data compression.
15
16bzip2/libbzip2 version 1.0.4 of 20 December 2006
17Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
18
19Please read the WARNING, DISCLAIMER and PATENTS sections in the
20README file.
21
22This program is released under the terms of the license contained
23in the file LICENSE.
24------------------------------------------------------------------ */
25
26/* CHANGES
27 * 0.9.0 -- original version.
28 * 0.9.0a/b -- no changes in this file.
29 * 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress().
30 * fixed bzWrite/bzRead to ignore zero-length requests.
31 * fixed bzread to correctly handle read requests after EOF.
32 * wrong parameter order in call to bzDecompressInit in
33 * bzBuffToBuffDecompress. Fixed.
34 */
35
36/* #include "bzlib_private.h" */
37
38/*---------------------------------------------------*/
39/*--- Compression stuff ---*/
40/*---------------------------------------------------*/
41
42/*---------------------------------------------------*/
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +000043#if BZ_LIGHT_DEBUG
44static
45void bz_assert_fail(int errcode)
Denis Vlasenko77f1ec12007-10-13 03:36:03 +000046{
47 /* if (errcode == 1007) bb_error_msg_and_die("probably bad RAM"); */
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +000048 bb_error_msg_and_die("internal error %d", errcode);
Denis Vlasenko77f1ec12007-10-13 03:36:03 +000049}
50#endif
51
Denis Vlasenko77f1ec12007-10-13 03:36:03 +000052/*---------------------------------------------------*/
53static
54void prepare_new_block(EState* s)
55{
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +000056 int i;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +000057 s->nblock = 0;
58 s->numZ = 0;
59 s->state_out_pos = 0;
60 BZ_INITIALISE_CRC(s->blockCRC);
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +000061 /* inlined memset would be nice to have here */
62 for (i = 0; i < 256; i++)
63 s->inUse[i] = 0;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +000064 s->blockNo++;
65}
66
67
68/*---------------------------------------------------*/
69static
70ALWAYS_INLINE
71void init_RL(EState* s)
72{
73 s->state_in_ch = 256;
74 s->state_in_len = 0;
75}
76
77
78static
79Bool isempty_RL(EState* s)
80{
81 if (s->state_in_ch < 256 && s->state_in_len > 0)
82 return False;
83 return True;
84}
85
86
87/*---------------------------------------------------*/
88static
89void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k)
90{
91 int32_t n;
92 EState* s;
93
94 s = xzalloc(sizeof(EState));
95 s->strm = strm;
96
97 n = 100000 * blockSize100k;
98 s->arr1 = xmalloc(n * sizeof(uint32_t));
99 s->mtfv = (uint16_t*)s->arr1;
100 s->ptr = (uint32_t*)s->arr1;
101 s->arr2 = xmalloc((n + BZ_N_OVERSHOOT) * sizeof(uint32_t));
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000102 s->block = (uint8_t*)s->arr2;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000103 s->ftab = xmalloc(65537 * sizeof(uint32_t));
104
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000105 s->crc32table = crc32_filltable(NULL, 1);
106
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000107 s->state = BZ_S_INPUT;
108 s->mode = BZ_M_RUNNING;
109 s->blockSize100k = blockSize100k;
110 s->nblockMAX = n - 19;
111
112 strm->state = s;
113 /*strm->total_in = 0;*/
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000114 strm->total_out = 0;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000115 init_RL(s);
116 prepare_new_block(s);
117}
118
119
120/*---------------------------------------------------*/
121static
122void add_pair_to_block(EState* s)
123{
124 int32_t i;
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000125 uint8_t ch = (uint8_t)(s->state_in_ch);
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000126 for (i = 0; i < s->state_in_len; i++) {
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000127 BZ_UPDATE_CRC(s, s->blockCRC, ch);
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000128 }
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000129 s->inUse[s->state_in_ch] = 1;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000130 switch (s->state_in_len) {
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000131 case 3:
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000132 s->block[s->nblock] = (uint8_t)ch; s->nblock++;
133 /* fall through */
134 case 2:
135 s->block[s->nblock] = (uint8_t)ch; s->nblock++;
136 /* fall through */
137 case 1:
138 s->block[s->nblock] = (uint8_t)ch; s->nblock++;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000139 break;
140 default:
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000141 s->inUse[s->state_in_len - 4] = 1;
142 s->block[s->nblock] = (uint8_t)ch; s->nblock++;
143 s->block[s->nblock] = (uint8_t)ch; s->nblock++;
144 s->block[s->nblock] = (uint8_t)ch; s->nblock++;
145 s->block[s->nblock] = (uint8_t)ch; s->nblock++;
146 s->block[s->nblock] = (uint8_t)(s->state_in_len - 4);
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000147 s->nblock++;
148 break;
149 }
150}
151
152
153/*---------------------------------------------------*/
154static
155void flush_RL(EState* s)
156{
157 if (s->state_in_ch < 256) add_pair_to_block(s);
158 init_RL(s);
159}
160
161
162/*---------------------------------------------------*/
163#define ADD_CHAR_TO_BLOCK(zs, zchh0) \
164{ \
165 uint32_t zchh = (uint32_t)(zchh0); \
166 /*-- fast track the common case --*/ \
167 if (zchh != zs->state_in_ch && zs->state_in_len == 1) { \
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000168 uint8_t ch = (uint8_t)(zs->state_in_ch); \
169 BZ_UPDATE_CRC(zs, zs->blockCRC, ch); \
170 zs->inUse[zs->state_in_ch] = 1; \
171 zs->block[zs->nblock] = (uint8_t)ch; \
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000172 zs->nblock++; \
173 zs->state_in_ch = zchh; \
174 } \
175 else \
176 /*-- general, uncommon cases --*/ \
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000177 if (zchh != zs->state_in_ch || zs->state_in_len == 255) { \
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000178 if (zs->state_in_ch < 256) \
179 add_pair_to_block(zs); \
180 zs->state_in_ch = zchh; \
181 zs->state_in_len = 1; \
182 } else { \
183 zs->state_in_len++; \
184 } \
185}
186
187
188/*---------------------------------------------------*/
189static
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000190void /*Bool*/ copy_input_until_stop(EState* s)
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000191{
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000192 /*Bool progress_in = False;*/
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000193
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000194#ifdef SAME_CODE_AS_BELOW
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000195 if (s->mode == BZ_M_RUNNING) {
196 /*-- fast track the common case --*/
197 while (1) {
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000198 /*-- no input? --*/
199 if (s->strm->avail_in == 0) break;
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000200 /*-- block full? --*/
201 if (s->nblock >= s->nblockMAX) break;
202 /*progress_in = True;*/
203 ADD_CHAR_TO_BLOCK(s, (uint32_t)(*(uint8_t*)(s->strm->next_in)));
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000204 s->strm->next_in++;
205 s->strm->avail_in--;
206 /*s->strm->total_in++;*/
207 }
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000208 } else
209#endif
210 {
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000211 /*-- general, uncommon case --*/
212 while (1) {
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000213 /*-- no input? --*/
214 if (s->strm->avail_in == 0) break;
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000215 /*-- block full? --*/
216 if (s->nblock >= s->nblockMAX) break;
217 //# /*-- flush/finish end? --*/
218 //# if (s->avail_in_expect == 0) break;
219 /*progress_in = True;*/
220 ADD_CHAR_TO_BLOCK(s, *(uint8_t*)(s->strm->next_in));
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000221 s->strm->next_in++;
222 s->strm->avail_in--;
223 /*s->strm->total_in++;*/
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000224 //# s->avail_in_expect--;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000225 }
226 }
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000227 /*return progress_in;*/
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000228}
229
230
231/*---------------------------------------------------*/
232static
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000233void /*Bool*/ copy_output_until_stop(EState* s)
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000234{
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000235 /*Bool progress_out = False;*/
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000236
237 while (1) {
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000238 /*-- no output space? --*/
239 if (s->strm->avail_out == 0) break;
240
241 /*-- block done? --*/
242 if (s->state_out_pos >= s->numZ) break;
243
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000244 /*progress_out = True;*/
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000245 *(s->strm->next_out) = s->zbits[s->state_out_pos];
246 s->state_out_pos++;
247 s->strm->avail_out--;
248 s->strm->next_out++;
249 s->strm->total_out++;
250 }
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000251 /*return progress_out;*/
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000252}
253
254
255/*---------------------------------------------------*/
256static
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000257void /*Bool*/ handle_compress(bz_stream *strm)
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000258{
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000259 /*Bool progress_in = False;*/
260 /*Bool progress_out = False;*/
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000261 EState* s = strm->state;
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +0000262
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000263 while (1) {
264 if (s->state == BZ_S_OUTPUT) {
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000265 /*progress_out |=*/ copy_output_until_stop(s);
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000266 if (s->state_out_pos < s->numZ) break;
267 if (s->mode == BZ_M_FINISHING
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000268 //# && s->avail_in_expect == 0
269 && s->strm->avail_in == 0
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000270 && isempty_RL(s))
271 break;
272 prepare_new_block(s);
273 s->state = BZ_S_INPUT;
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000274#ifdef FLUSH_IS_UNUSED
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000275 if (s->mode == BZ_M_FLUSHING
276 && s->avail_in_expect == 0
277 && isempty_RL(s))
278 break;
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000279#endif
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000280 }
281
282 if (s->state == BZ_S_INPUT) {
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000283 /*progress_in |=*/ copy_input_until_stop(s);
284 //#if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
285 if (s->mode != BZ_M_RUNNING && s->strm->avail_in == 0) {
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000286 flush_RL(s);
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000287 BZ2_compressBlock(s, (s->mode == BZ_M_FINISHING));
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000288 s->state = BZ_S_OUTPUT;
289 } else
290 if (s->nblock >= s->nblockMAX) {
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000291 BZ2_compressBlock(s, 0);
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000292 s->state = BZ_S_OUTPUT;
293 } else
294 if (s->strm->avail_in == 0) {
295 break;
296 }
297 }
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000298 }
299
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000300 /*return progress_in || progress_out;*/
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000301}
302
303
304/*---------------------------------------------------*/
305static
306int BZ2_bzCompress(bz_stream *strm, int action)
307{
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000308 /*Bool progress;*/
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000309 EState* s;
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000310
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000311 s = strm->state;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000312
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000313 switch (s->mode) {
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000314 case BZ_M_RUNNING:
315 if (action == BZ_RUN) {
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000316 /*progress =*/ handle_compress(strm);
317 /*return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;*/
318 return BZ_RUN_OK;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000319 }
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000320#ifdef FLUSH_IS_UNUSED
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000321 else
322 if (action == BZ_FLUSH) {
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000323 //#s->avail_in_expect = strm->avail_in;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000324 s->mode = BZ_M_FLUSHING;
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000325 goto case_BZ_M_FLUSHING;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000326 }
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000327#endif
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000328 else
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000329 /*if (action == BZ_FINISH)*/ {
330 //#s->avail_in_expect = strm->avail_in;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000331 s->mode = BZ_M_FINISHING;
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000332 goto case_BZ_M_FINISHING;
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000333 }
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000334
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000335#ifdef FLUSH_IS_UNUSED
336case_BZ_M_FLUSHING:
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000337 case BZ_M_FLUSHING:
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000338 /*if (s->avail_in_expect != s->strm->avail_in)
339 return BZ_SEQUENCE_ERROR;*/
340 /*progress =*/ handle_compress(strm);
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000341 if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
342 return BZ_FLUSH_OK;
343 s->mode = BZ_M_RUNNING;
344 return BZ_RUN_OK;
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000345#endif
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000346
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000347 case_BZ_M_FINISHING:
348 /*case BZ_M_FINISHING:*/
349 default:
350 /*if (s->avail_in_expect != s->strm->avail_in)
351 return BZ_SEQUENCE_ERROR;*/
352 /*progress =*/ handle_compress(strm);
353 /*if (!progress) return BZ_SEQUENCE_ERROR;*/
354 //#if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
355 //# return BZ_FINISH_OK;
356 if (s->strm->avail_in > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000357 return BZ_FINISH_OK;
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000358 /*s->mode = BZ_M_IDLE;*/
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000359 return BZ_STREAM_END;
360 }
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000361 /* return BZ_OK; --not reached--*/
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000362}
363
364
365/*---------------------------------------------------*/
Denis Vlasenko686b0ef2007-10-16 14:07:41 +0000366#if ENABLE_FEATURE_CLEAN_UP
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000367static
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000368void BZ2_bzCompressEnd(bz_stream *strm)
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000369{
370 EState* s;
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000371
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000372 s = strm->state;
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000373 free(s->arr1);
374 free(s->arr2);
375 free(s->ftab);
376 free(s->crc32table);
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000377 free(strm->state);
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000378}
Denis Vlasenko686b0ef2007-10-16 14:07:41 +0000379#endif
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000380
381
382/*---------------------------------------------------*/
383/*--- Misc convenience stuff ---*/
384/*---------------------------------------------------*/
385
386/*---------------------------------------------------*/
387#ifdef EXAMPLE_CODE_FOR_MEM_TO_MEM_COMPRESSION
388static
389int BZ2_bzBuffToBuffCompress(char* dest,
390 unsigned int* destLen,
391 char* source,
392 unsigned int sourceLen,
393 int blockSize100k)
394{
395 bz_stream strm;
396 int ret;
397
398 if (dest == NULL || destLen == NULL ||
399 source == NULL ||
400 blockSize100k < 1 || blockSize100k > 9)
401 return BZ_PARAM_ERROR;
402
403 BZ2_bzCompressInit(&strm, blockSize100k);
404
405 strm.next_in = source;
406 strm.next_out = dest;
407 strm.avail_in = sourceLen;
408 strm.avail_out = *destLen;
409
410 ret = BZ2_bzCompress(&strm, BZ_FINISH);
411 if (ret == BZ_FINISH_OK) goto output_overflow;
412 if (ret != BZ_STREAM_END) goto errhandler;
413
414 /* normal termination */
415 *destLen -= strm.avail_out;
416 BZ2_bzCompressEnd(&strm);
417 return BZ_OK;
418
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000419 output_overflow:
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000420 BZ2_bzCompressEnd(&strm);
421 return BZ_OUTBUFF_FULL;
422
Denis Vlasenkoef3aabe2007-10-14 00:43:01 +0000423 errhandler:
Denis Vlasenko77f1ec12007-10-13 03:36:03 +0000424 BZ2_bzCompressEnd(&strm);
425 return ret;
426}
427#endif
428
429/*-------------------------------------------------------------*/
430/*--- end bzlib.c ---*/
431/*-------------------------------------------------------------*/