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.
7 /*-------------------------------------------------------------*/
8 /*--- Library top-level functions. ---*/
10 /*-------------------------------------------------------------*/
12 /* ------------------------------------------------------------------
13 This file is part of bzip2/libbzip2, a program and library for
14 lossless, block-sorting data compression.
16 bzip2/libbzip2 version 1.0.4 of 20 December 2006
17 Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
19 Please read the WARNING, DISCLAIMER and PATENTS sections in the
22 This program is released under the terms of the license contained
24 ------------------------------------------------------------------ */
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.
36 /* #include "bzlib_private.h" */
38 /*---------------------------------------------------*/
39 /*--- Compression stuff ---*/
40 /*---------------------------------------------------*/
42 /*---------------------------------------------------*/
45 void bz_assert_fail(int errcode
)
47 /* if (errcode == 1007) bb_error_msg_and_die("probably bad RAM"); */
48 bb_error_msg_and_die("internal error %d", errcode
);
52 /*---------------------------------------------------*/
54 void prepare_new_block(EState
* s
)
60 BZ_INITIALISE_CRC(s
->blockCRC
);
61 /* inlined memset would be nice to have here */
62 for (i
= 0; i
< 256; i
++)
68 /*---------------------------------------------------*/
71 void init_RL(EState
* s
)
79 int isempty_RL(EState
* s
)
81 return (s
->state_in_ch
>= 256 || s
->state_in_len
<= 0);
85 /*---------------------------------------------------*/
87 void BZ2_bzCompressInit(bz_stream
*strm
, int blockSize100k
)
92 s
= xzalloc(sizeof(EState
));
95 n
= 100000 * blockSize100k
;
96 s
->arr1
= xmalloc(n
* sizeof(uint32_t));
97 s
->mtfv
= (uint16_t*)s
->arr1
;
98 s
->ptr
= (uint32_t*)s
->arr1
;
99 s
->arr2
= xmalloc((n
+ BZ_N_OVERSHOOT
) * sizeof(uint32_t));
100 s
->block
= (uint8_t*)s
->arr2
;
101 s
->ftab
= xmalloc(65537 * sizeof(uint32_t));
103 s
->crc32table
= crc32_filltable(NULL
, 1);
105 s
->state
= BZ_S_INPUT
;
106 s
->mode
= BZ_M_RUNNING
;
107 s
->blockSize100k
= blockSize100k
;
108 s
->nblockMAX
= n
- 19;
111 /*strm->total_in = 0;*/
114 prepare_new_block(s
);
118 /*---------------------------------------------------*/
120 void add_pair_to_block(EState
* s
)
123 uint8_t ch
= (uint8_t)(s
->state_in_ch
);
124 for (i
= 0; i
< s
->state_in_len
; i
++) {
125 BZ_UPDATE_CRC(s
, s
->blockCRC
, ch
);
127 s
->inUse
[s
->state_in_ch
] = 1;
128 switch (s
->state_in_len
) {
130 s
->block
[s
->nblock
] = (uint8_t)ch
; s
->nblock
++;
133 s
->block
[s
->nblock
] = (uint8_t)ch
; s
->nblock
++;
136 s
->block
[s
->nblock
] = (uint8_t)ch
; s
->nblock
++;
139 s
->inUse
[s
->state_in_len
- 4] = 1;
140 s
->block
[s
->nblock
] = (uint8_t)ch
; s
->nblock
++;
141 s
->block
[s
->nblock
] = (uint8_t)ch
; s
->nblock
++;
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)(s
->state_in_len
- 4);
151 /*---------------------------------------------------*/
153 void flush_RL(EState
* s
)
155 if (s
->state_in_ch
< 256) add_pair_to_block(s
);
160 /*---------------------------------------------------*/
161 #define ADD_CHAR_TO_BLOCK(zs, zchh0) \
163 uint32_t zchh = (uint32_t)(zchh0); \
164 /*-- fast track the common case --*/ \
165 if (zchh != zs->state_in_ch && zs->state_in_len == 1) { \
166 uint8_t ch = (uint8_t)(zs->state_in_ch); \
167 BZ_UPDATE_CRC(zs, zs->blockCRC, ch); \
168 zs->inUse[zs->state_in_ch] = 1; \
169 zs->block[zs->nblock] = (uint8_t)ch; \
171 zs->state_in_ch = zchh; \
174 /*-- general, uncommon cases --*/ \
175 if (zchh != zs->state_in_ch || zs->state_in_len == 255) { \
176 if (zs->state_in_ch < 256) \
177 add_pair_to_block(zs); \
178 zs->state_in_ch = zchh; \
179 zs->state_in_len = 1; \
181 zs->state_in_len++; \
186 /*---------------------------------------------------*/
188 void /*Bool*/ copy_input_until_stop(EState
* s
)
190 /*Bool progress_in = False;*/
192 #ifdef SAME_CODE_AS_BELOW
193 if (s
->mode
== BZ_M_RUNNING
) {
194 /*-- fast track the common case --*/
197 if (s
->strm
->avail_in
== 0) break;
198 /*-- block full? --*/
199 if (s
->nblock
>= s
->nblockMAX
) break;
200 /*progress_in = True;*/
201 ADD_CHAR_TO_BLOCK(s
, (uint32_t)(*(uint8_t*)(s
->strm
->next_in
)));
204 /*s->strm->total_in++;*/
209 /*-- general, uncommon case --*/
212 if (s
->strm
->avail_in
== 0) break;
213 /*-- block full? --*/
214 if (s
->nblock
>= s
->nblockMAX
) break;
215 //# /*-- flush/finish end? --*/
216 //# if (s->avail_in_expect == 0) break;
217 /*progress_in = True;*/
218 ADD_CHAR_TO_BLOCK(s
, *(uint8_t*)(s
->strm
->next_in
));
221 /*s->strm->total_in++;*/
222 //# s->avail_in_expect--;
225 /*return progress_in;*/
229 /*---------------------------------------------------*/
231 void /*Bool*/ copy_output_until_stop(EState
* s
)
233 /*Bool progress_out = False;*/
236 /*-- no output space? --*/
237 if (s
->strm
->avail_out
== 0) break;
239 /*-- block done? --*/
240 if (s
->state_out_pos
>= s
->numZ
) break;
242 /*progress_out = True;*/
243 *(s
->strm
->next_out
) = s
->zbits
[s
->state_out_pos
];
245 s
->strm
->avail_out
--;
247 s
->strm
->total_out
++;
249 /*return progress_out;*/
253 /*---------------------------------------------------*/
255 void /*Bool*/ handle_compress(bz_stream
*strm
)
257 /*Bool progress_in = False;*/
258 /*Bool progress_out = False;*/
259 EState
* s
= strm
->state
;
262 if (s
->state
== BZ_S_OUTPUT
) {
263 /*progress_out |=*/ copy_output_until_stop(s
);
264 if (s
->state_out_pos
< s
->numZ
) break;
265 if (s
->mode
== BZ_M_FINISHING
266 //# && s->avail_in_expect == 0
267 && s
->strm
->avail_in
== 0
270 prepare_new_block(s
);
271 s
->state
= BZ_S_INPUT
;
272 #ifdef FLUSH_IS_UNUSED
273 if (s
->mode
== BZ_M_FLUSHING
274 && s
->avail_in_expect
== 0
280 if (s
->state
== BZ_S_INPUT
) {
281 /*progress_in |=*/ copy_input_until_stop(s
);
282 //#if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
283 if (s
->mode
!= BZ_M_RUNNING
&& s
->strm
->avail_in
== 0) {
285 BZ2_compressBlock(s
, (s
->mode
== BZ_M_FINISHING
));
286 s
->state
= BZ_S_OUTPUT
;
288 if (s
->nblock
>= s
->nblockMAX
) {
289 BZ2_compressBlock(s
, 0);
290 s
->state
= BZ_S_OUTPUT
;
292 if (s
->strm
->avail_in
== 0) {
298 /*return progress_in || progress_out;*/
302 /*---------------------------------------------------*/
304 int BZ2_bzCompress(bz_stream
*strm
, int action
)
313 if (action
== BZ_RUN
) {
314 /*progress =*/ handle_compress(strm
);
315 /*return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;*/
318 #ifdef FLUSH_IS_UNUSED
320 if (action
== BZ_FLUSH
) {
321 //#s->avail_in_expect = strm->avail_in;
322 s
->mode
= BZ_M_FLUSHING
;
323 goto case_BZ_M_FLUSHING
;
327 /*if (action == BZ_FINISH)*/ {
328 //#s->avail_in_expect = strm->avail_in;
329 s
->mode
= BZ_M_FINISHING
;
330 goto case_BZ_M_FINISHING
;
333 #ifdef FLUSH_IS_UNUSED
336 /*if (s->avail_in_expect != s->strm->avail_in)
337 return BZ_SEQUENCE_ERROR;*/
338 /*progress =*/ handle_compress(strm
);
339 if (s
->avail_in_expect
> 0 || !isempty_RL(s
) || s
->state_out_pos
< s
->numZ
)
341 s
->mode
= BZ_M_RUNNING
;
346 /*case BZ_M_FINISHING:*/
348 /*if (s->avail_in_expect != s->strm->avail_in)
349 return BZ_SEQUENCE_ERROR;*/
350 /*progress =*/ handle_compress(strm
);
351 /*if (!progress) return BZ_SEQUENCE_ERROR;*/
352 //#if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
353 //# return BZ_FINISH_OK;
354 if (s
->strm
->avail_in
> 0 || !isempty_RL(s
) || s
->state_out_pos
< s
->numZ
)
356 /*s->mode = BZ_M_IDLE;*/
357 return BZ_STREAM_END
;
359 /* return BZ_OK; --not reached--*/
363 /*---------------------------------------------------*/
364 #if ENABLE_FEATURE_CLEAN_UP
366 void BZ2_bzCompressEnd(bz_stream
*strm
)
380 /*---------------------------------------------------*/
381 /*--- Misc convenience stuff ---*/
382 /*---------------------------------------------------*/
384 /*---------------------------------------------------*/
385 #ifdef EXAMPLE_CODE_FOR_MEM_TO_MEM_COMPRESSION
387 int BZ2_bzBuffToBuffCompress(char* dest
,
388 unsigned int* destLen
,
390 unsigned int sourceLen
,
396 if (dest
== NULL
|| destLen
== NULL
||
398 blockSize100k
< 1 || blockSize100k
> 9)
399 return BZ_PARAM_ERROR
;
401 BZ2_bzCompressInit(&strm
, blockSize100k
);
403 strm
.next_in
= source
;
404 strm
.next_out
= dest
;
405 strm
.avail_in
= sourceLen
;
406 strm
.avail_out
= *destLen
;
408 ret
= BZ2_bzCompress(&strm
, BZ_FINISH
);
409 if (ret
== BZ_FINISH_OK
) goto output_overflow
;
410 if (ret
!= BZ_STREAM_END
) goto errhandler
;
412 /* normal termination */
413 *destLen
-= strm
.avail_out
;
414 BZ2_bzCompressEnd(&strm
);
418 BZ2_bzCompressEnd(&strm
);
419 return BZ_OUTBUFF_FULL
;
422 BZ2_bzCompressEnd(&strm
);
427 /*-------------------------------------------------------------*/
428 /*--- end bzlib.c ---*/
429 /*-------------------------------------------------------------*/