xref: /plan9/sys/src/cmd/bzip2/lib/bzdecompress.c (revision b85a83648eec38fe82b6f00adfd7828ceec5ee8d)
1*59cc4ca5SDavid du Colombier /*
2*59cc4ca5SDavid du Colombier  * THIS FILE IS NOT IDENTICAL TO THE ORIGINAL
3*59cc4ca5SDavid du Colombier  * FROM THE BZIP2 DISTRIBUTION.
4*59cc4ca5SDavid du Colombier  *
5*59cc4ca5SDavid du Colombier  * It has been modified, mainly to break the library
6*59cc4ca5SDavid du Colombier  * into smaller pieces.
7*59cc4ca5SDavid du Colombier  *
8*59cc4ca5SDavid du Colombier  * Russ Cox
9*59cc4ca5SDavid du Colombier  * rsc@plan9.bell-labs.com
10*59cc4ca5SDavid du Colombier  * July 2000
11*59cc4ca5SDavid du Colombier  */
12*59cc4ca5SDavid du Colombier 
13*59cc4ca5SDavid du Colombier /*-------------------------------------------------------------*/
14*59cc4ca5SDavid du Colombier /*--- Library top-level functions.                          ---*/
15*59cc4ca5SDavid du Colombier /*---                                               bzlib.c ---*/
16*59cc4ca5SDavid du Colombier /*-------------------------------------------------------------*/
17*59cc4ca5SDavid du Colombier 
18*59cc4ca5SDavid du Colombier /*--
19*59cc4ca5SDavid du Colombier   This file is a part of bzip2 and/or libbzip2, a program and
20*59cc4ca5SDavid du Colombier   library for lossless, block-sorting data compression.
21*59cc4ca5SDavid du Colombier 
22*59cc4ca5SDavid du Colombier   Copyright (C) 1996-2000 Julian R Seward.  All rights reserved.
23*59cc4ca5SDavid du Colombier 
24*59cc4ca5SDavid du Colombier   Redistribution and use in source and binary forms, with or without
25*59cc4ca5SDavid du Colombier   modification, are permitted provided that the following conditions
26*59cc4ca5SDavid du Colombier   are met:
27*59cc4ca5SDavid du Colombier 
28*59cc4ca5SDavid du Colombier   1. Redistributions of source code must retain the above copyright
29*59cc4ca5SDavid du Colombier      notice, this list of conditions and the following disclaimer.
30*59cc4ca5SDavid du Colombier 
31*59cc4ca5SDavid du Colombier   2. The origin of this software must not be misrepresented; you must
32*59cc4ca5SDavid du Colombier      not claim that you wrote the original software.  If you use this
33*59cc4ca5SDavid du Colombier      software in a product, an acknowledgment in the product
34*59cc4ca5SDavid du Colombier      documentation would be appreciated but is not required.
35*59cc4ca5SDavid du Colombier 
36*59cc4ca5SDavid du Colombier   3. Altered source versions must be plainly marked as such, and must
37*59cc4ca5SDavid du Colombier      not be misrepresented as being the original software.
38*59cc4ca5SDavid du Colombier 
39*59cc4ca5SDavid du Colombier   4. The name of the author may not be used to endorse or promote
40*59cc4ca5SDavid du Colombier      products derived from this software without specific prior written
41*59cc4ca5SDavid du Colombier      permission.
42*59cc4ca5SDavid du Colombier 
43*59cc4ca5SDavid du Colombier   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
44*59cc4ca5SDavid du Colombier   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45*59cc4ca5SDavid du Colombier   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46*59cc4ca5SDavid du Colombier   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
47*59cc4ca5SDavid du Colombier   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48*59cc4ca5SDavid du Colombier   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
49*59cc4ca5SDavid du Colombier   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50*59cc4ca5SDavid du Colombier   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
51*59cc4ca5SDavid du Colombier   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
52*59cc4ca5SDavid du Colombier   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
53*59cc4ca5SDavid du Colombier   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54*59cc4ca5SDavid du Colombier 
55*59cc4ca5SDavid du Colombier   Julian Seward, Cambridge, UK.
56*59cc4ca5SDavid du Colombier   jseward@acm.org
57*59cc4ca5SDavid du Colombier   bzip2/libbzip2 version 1.0 of 21 March 2000
58*59cc4ca5SDavid du Colombier 
59*59cc4ca5SDavid du Colombier   This program is based on (at least) the work of:
60*59cc4ca5SDavid du Colombier      Mike Burrows
61*59cc4ca5SDavid du Colombier      David Wheeler
62*59cc4ca5SDavid du Colombier      Peter Fenwick
63*59cc4ca5SDavid du Colombier      Alistair Moffat
64*59cc4ca5SDavid du Colombier      Radford Neal
65*59cc4ca5SDavid du Colombier      Ian H. Witten
66*59cc4ca5SDavid du Colombier      Robert Sedgewick
67*59cc4ca5SDavid du Colombier      Jon L. Bentley
68*59cc4ca5SDavid du Colombier 
69*59cc4ca5SDavid du Colombier   For more information on these sources, see the manual.
70*59cc4ca5SDavid du Colombier --*/
71*59cc4ca5SDavid du Colombier 
72*59cc4ca5SDavid du Colombier /*--
73*59cc4ca5SDavid du Colombier    CHANGES
74*59cc4ca5SDavid du Colombier    ~~~~~~~
75*59cc4ca5SDavid du Colombier    0.9.0 -- original version.
76*59cc4ca5SDavid du Colombier 
77*59cc4ca5SDavid du Colombier    0.9.0a/b -- no changes in this file.
78*59cc4ca5SDavid du Colombier 
79*59cc4ca5SDavid du Colombier    0.9.0c
80*59cc4ca5SDavid du Colombier       * made zero-length BZ_FLUSH work correctly in bzCompress().
81*59cc4ca5SDavid du Colombier       * fixed bzWrite/bzRead to ignore zero-length requests.
82*59cc4ca5SDavid du Colombier       * fixed bzread to correctly handle read requests after EOF.
83*59cc4ca5SDavid du Colombier       * wrong parameter order in call to bzDecompressInit in
84*59cc4ca5SDavid du Colombier         bzBuffToBuffDecompress.  Fixed.
85*59cc4ca5SDavid du Colombier --*/
86*59cc4ca5SDavid du Colombier 
87*59cc4ca5SDavid du Colombier #include "os.h"
88*59cc4ca5SDavid du Colombier #include "bzlib.h"
89*59cc4ca5SDavid du Colombier #include "bzlib_private.h"
90*59cc4ca5SDavid du Colombier 
91*59cc4ca5SDavid du Colombier /*---------------------------------------------------*/
92*59cc4ca5SDavid du Colombier /*--- Decompression stuff                         ---*/
93*59cc4ca5SDavid du Colombier /*---------------------------------------------------*/
94*59cc4ca5SDavid du Colombier 
95*59cc4ca5SDavid du Colombier /*---------------------------------------------------*/
BZ_API(BZ2_bzDecompressInit)96*59cc4ca5SDavid du Colombier int BZ_API(BZ2_bzDecompressInit)
97*59cc4ca5SDavid du Colombier                      ( bz_stream* strm,
98*59cc4ca5SDavid du Colombier                        int        verbosity,
99*59cc4ca5SDavid du Colombier                        int        small )
100*59cc4ca5SDavid du Colombier {
101*59cc4ca5SDavid du Colombier    DState* s;
102*59cc4ca5SDavid du Colombier 
103*59cc4ca5SDavid du Colombier    if (!bz_config_ok()) return BZ_CONFIG_ERROR;
104*59cc4ca5SDavid du Colombier 
105*59cc4ca5SDavid du Colombier    if (strm == NULL) return BZ_PARAM_ERROR;
106*59cc4ca5SDavid du Colombier    if (small != 0 && small != 1) return BZ_PARAM_ERROR;
107*59cc4ca5SDavid du Colombier    if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
108*59cc4ca5SDavid du Colombier 
109*59cc4ca5SDavid du Colombier    if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
110*59cc4ca5SDavid du Colombier    if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
111*59cc4ca5SDavid du Colombier 
112*59cc4ca5SDavid du Colombier    s = BZALLOC( sizeof(DState) );
113*59cc4ca5SDavid du Colombier    if (s == NULL) return BZ_MEM_ERROR;
114*59cc4ca5SDavid du Colombier    s->strm                  = strm;
115*59cc4ca5SDavid du Colombier    strm->state              = s;
116*59cc4ca5SDavid du Colombier    s->state                 = BZ_X_MAGIC_1;
117*59cc4ca5SDavid du Colombier    s->bsLive                = 0;
118*59cc4ca5SDavid du Colombier    s->bsBuff                = 0;
119*59cc4ca5SDavid du Colombier    s->calculatedCombinedCRC = 0;
120*59cc4ca5SDavid du Colombier    strm->total_in_lo32      = 0;
121*59cc4ca5SDavid du Colombier    strm->total_in_hi32      = 0;
122*59cc4ca5SDavid du Colombier    strm->total_out_lo32     = 0;
123*59cc4ca5SDavid du Colombier    strm->total_out_hi32     = 0;
124*59cc4ca5SDavid du Colombier    s->smallDecompress       = (Bool)small;
125*59cc4ca5SDavid du Colombier    s->ll4                   = NULL;
126*59cc4ca5SDavid du Colombier    s->ll16                  = NULL;
127*59cc4ca5SDavid du Colombier    s->tt                    = NULL;
128*59cc4ca5SDavid du Colombier    s->currBlockNo           = 0;
129*59cc4ca5SDavid du Colombier    s->verbosity             = verbosity;
130*59cc4ca5SDavid du Colombier 
131*59cc4ca5SDavid du Colombier    return BZ_OK;
132*59cc4ca5SDavid du Colombier }
133*59cc4ca5SDavid du Colombier 
134*59cc4ca5SDavid du Colombier 
135*59cc4ca5SDavid du Colombier /*---------------------------------------------------*/
136*59cc4ca5SDavid du Colombier static
unRLE_obuf_to_output_FAST(DState * s)137*59cc4ca5SDavid du Colombier void unRLE_obuf_to_output_FAST ( DState* s )
138*59cc4ca5SDavid du Colombier {
139*59cc4ca5SDavid du Colombier    UChar k1;
140*59cc4ca5SDavid du Colombier 
141*59cc4ca5SDavid du Colombier    if (s->blockRandomised) {
142*59cc4ca5SDavid du Colombier 
143*59cc4ca5SDavid du Colombier       while (True) {
144*59cc4ca5SDavid du Colombier          /* try to finish existing run */
145*59cc4ca5SDavid du Colombier          while (True) {
146*59cc4ca5SDavid du Colombier             if (s->strm->avail_out == 0) return;
147*59cc4ca5SDavid du Colombier             if (s->state_out_len == 0) break;
148*59cc4ca5SDavid du Colombier             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
149*59cc4ca5SDavid du Colombier             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
150*59cc4ca5SDavid du Colombier             s->state_out_len--;
151*59cc4ca5SDavid du Colombier             s->strm->next_out++;
152*59cc4ca5SDavid du Colombier             s->strm->avail_out--;
153*59cc4ca5SDavid du Colombier             s->strm->total_out_lo32++;
154*59cc4ca5SDavid du Colombier             if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
155*59cc4ca5SDavid du Colombier          }
156*59cc4ca5SDavid du Colombier 
157*59cc4ca5SDavid du Colombier          /* can a new run be started? */
158*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1) return;
159*59cc4ca5SDavid du Colombier 
160*59cc4ca5SDavid du Colombier 
161*59cc4ca5SDavid du Colombier          s->state_out_len = 1;
162*59cc4ca5SDavid du Colombier          s->state_out_ch = s->k0;
163*59cc4ca5SDavid du Colombier          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
164*59cc4ca5SDavid du Colombier          k1 ^= BZ_RAND_MASK; s->nblock_used++;
165*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1) continue;
166*59cc4ca5SDavid du Colombier          if (k1 != s->k0) { s->k0 = k1; continue; };
167*59cc4ca5SDavid du Colombier 
168*59cc4ca5SDavid du Colombier          s->state_out_len = 2;
169*59cc4ca5SDavid du Colombier          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
170*59cc4ca5SDavid du Colombier          k1 ^= BZ_RAND_MASK; s->nblock_used++;
171*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1) continue;
172*59cc4ca5SDavid du Colombier          if (k1 != s->k0) { s->k0 = k1; continue; };
173*59cc4ca5SDavid du Colombier 
174*59cc4ca5SDavid du Colombier          s->state_out_len = 3;
175*59cc4ca5SDavid du Colombier          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
176*59cc4ca5SDavid du Colombier          k1 ^= BZ_RAND_MASK; s->nblock_used++;
177*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1) continue;
178*59cc4ca5SDavid du Colombier          if (k1 != s->k0) { s->k0 = k1; continue; };
179*59cc4ca5SDavid du Colombier 
180*59cc4ca5SDavid du Colombier          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
181*59cc4ca5SDavid du Colombier          k1 ^= BZ_RAND_MASK; s->nblock_used++;
182*59cc4ca5SDavid du Colombier          s->state_out_len = ((Int32)k1) + 4;
183*59cc4ca5SDavid du Colombier          BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK;
184*59cc4ca5SDavid du Colombier          s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
185*59cc4ca5SDavid du Colombier       }
186*59cc4ca5SDavid du Colombier 
187*59cc4ca5SDavid du Colombier    } else {
188*59cc4ca5SDavid du Colombier 
189*59cc4ca5SDavid du Colombier       /* restore */
190*59cc4ca5SDavid du Colombier       UInt32        c_calculatedBlockCRC = s->calculatedBlockCRC;
191*59cc4ca5SDavid du Colombier       UChar         c_state_out_ch       = s->state_out_ch;
192*59cc4ca5SDavid du Colombier       Int32         c_state_out_len      = s->state_out_len;
193*59cc4ca5SDavid du Colombier       Int32         c_nblock_used        = s->nblock_used;
194*59cc4ca5SDavid du Colombier       Int32         c_k0                 = s->k0;
195*59cc4ca5SDavid du Colombier       UInt32*       c_tt                 = s->tt;
196*59cc4ca5SDavid du Colombier       UInt32        c_tPos               = s->tPos;
197*59cc4ca5SDavid du Colombier       char*         cs_next_out          = s->strm->next_out;
198*59cc4ca5SDavid du Colombier       unsigned int  cs_avail_out         = s->strm->avail_out;
199*59cc4ca5SDavid du Colombier       /* end restore */
200*59cc4ca5SDavid du Colombier 
201*59cc4ca5SDavid du Colombier       UInt32       avail_out_INIT = cs_avail_out;
202*59cc4ca5SDavid du Colombier       Int32        s_save_nblockPP = s->save_nblock+1;
203*59cc4ca5SDavid du Colombier       unsigned int total_out_lo32_old;
204*59cc4ca5SDavid du Colombier 
205*59cc4ca5SDavid du Colombier       while (True) {
206*59cc4ca5SDavid du Colombier 
207*59cc4ca5SDavid du Colombier          /* try to finish existing run */
208*59cc4ca5SDavid du Colombier          if (c_state_out_len > 0) {
209*59cc4ca5SDavid du Colombier             while (True) {
210*59cc4ca5SDavid du Colombier                if (cs_avail_out == 0) goto return_notr;
211*59cc4ca5SDavid du Colombier                if (c_state_out_len == 1) break;
212*59cc4ca5SDavid du Colombier                *( (UChar*)(cs_next_out) ) = c_state_out_ch;
213*59cc4ca5SDavid du Colombier                BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
214*59cc4ca5SDavid du Colombier                c_state_out_len--;
215*59cc4ca5SDavid du Colombier                cs_next_out++;
216*59cc4ca5SDavid du Colombier                cs_avail_out--;
217*59cc4ca5SDavid du Colombier             }
218*59cc4ca5SDavid du Colombier             s_state_out_len_eq_one:
219*59cc4ca5SDavid du Colombier             {
220*59cc4ca5SDavid du Colombier                if (cs_avail_out == 0) {
221*59cc4ca5SDavid du Colombier                   c_state_out_len = 1; goto return_notr;
222*59cc4ca5SDavid du Colombier                };
223*59cc4ca5SDavid du Colombier                *( (UChar*)(cs_next_out) ) = c_state_out_ch;
224*59cc4ca5SDavid du Colombier                BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
225*59cc4ca5SDavid du Colombier                cs_next_out++;
226*59cc4ca5SDavid du Colombier                cs_avail_out--;
227*59cc4ca5SDavid du Colombier             }
228*59cc4ca5SDavid du Colombier          }
229*59cc4ca5SDavid du Colombier          /* can a new run be started? */
230*59cc4ca5SDavid du Colombier          if (c_nblock_used == s_save_nblockPP) {
231*59cc4ca5SDavid du Colombier             c_state_out_len = 0; goto return_notr;
232*59cc4ca5SDavid du Colombier          };
233*59cc4ca5SDavid du Colombier          c_state_out_ch = c_k0;
234*59cc4ca5SDavid du Colombier          BZ_GET_FAST_C(k1); c_nblock_used++;
235*59cc4ca5SDavid du Colombier          if (k1 != c_k0) {
236*59cc4ca5SDavid du Colombier             c_k0 = k1; goto s_state_out_len_eq_one;
237*59cc4ca5SDavid du Colombier          };
238*59cc4ca5SDavid du Colombier          if (c_nblock_used == s_save_nblockPP)
239*59cc4ca5SDavid du Colombier             goto s_state_out_len_eq_one;
240*59cc4ca5SDavid du Colombier 
241*59cc4ca5SDavid du Colombier          c_state_out_len = 2;
242*59cc4ca5SDavid du Colombier          BZ_GET_FAST_C(k1); c_nblock_used++;
243*59cc4ca5SDavid du Colombier          if (c_nblock_used == s_save_nblockPP) continue;
244*59cc4ca5SDavid du Colombier          if (k1 != c_k0) { c_k0 = k1; continue; };
245*59cc4ca5SDavid du Colombier 
246*59cc4ca5SDavid du Colombier          c_state_out_len = 3;
247*59cc4ca5SDavid du Colombier          BZ_GET_FAST_C(k1); c_nblock_used++;
248*59cc4ca5SDavid du Colombier          if (c_nblock_used == s_save_nblockPP) continue;
249*59cc4ca5SDavid du Colombier          if (k1 != c_k0) { c_k0 = k1; continue; };
250*59cc4ca5SDavid du Colombier 
251*59cc4ca5SDavid du Colombier          BZ_GET_FAST_C(k1); c_nblock_used++;
252*59cc4ca5SDavid du Colombier          c_state_out_len = ((Int32)k1) + 4;
253*59cc4ca5SDavid du Colombier          BZ_GET_FAST_C(c_k0); c_nblock_used++;
254*59cc4ca5SDavid du Colombier       }
255*59cc4ca5SDavid du Colombier 
256*59cc4ca5SDavid du Colombier       return_notr:
257*59cc4ca5SDavid du Colombier       total_out_lo32_old = s->strm->total_out_lo32;
258*59cc4ca5SDavid du Colombier       s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
259*59cc4ca5SDavid du Colombier       if (s->strm->total_out_lo32 < total_out_lo32_old)
260*59cc4ca5SDavid du Colombier          s->strm->total_out_hi32++;
261*59cc4ca5SDavid du Colombier 
262*59cc4ca5SDavid du Colombier       /* save */
263*59cc4ca5SDavid du Colombier       s->calculatedBlockCRC = c_calculatedBlockCRC;
264*59cc4ca5SDavid du Colombier       s->state_out_ch       = c_state_out_ch;
265*59cc4ca5SDavid du Colombier       s->state_out_len      = c_state_out_len;
266*59cc4ca5SDavid du Colombier       s->nblock_used        = c_nblock_used;
267*59cc4ca5SDavid du Colombier       s->k0                 = c_k0;
268*59cc4ca5SDavid du Colombier       s->tt                 = c_tt;
269*59cc4ca5SDavid du Colombier       s->tPos               = c_tPos;
270*59cc4ca5SDavid du Colombier       s->strm->next_out     = cs_next_out;
271*59cc4ca5SDavid du Colombier       s->strm->avail_out    = cs_avail_out;
272*59cc4ca5SDavid du Colombier       /* end save */
273*59cc4ca5SDavid du Colombier    }
274*59cc4ca5SDavid du Colombier }
275*59cc4ca5SDavid du Colombier 
276*59cc4ca5SDavid du Colombier 
277*59cc4ca5SDavid du Colombier 
278*59cc4ca5SDavid du Colombier /*---------------------------------------------------*/
BZ2_indexIntoF(Int32 indx,Int32 * cftab)279*59cc4ca5SDavid du Colombier __inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
280*59cc4ca5SDavid du Colombier {
281*59cc4ca5SDavid du Colombier    Int32 nb, na, mid;
282*59cc4ca5SDavid du Colombier    nb = 0;
283*59cc4ca5SDavid du Colombier    na = 256;
284*59cc4ca5SDavid du Colombier    do {
285*59cc4ca5SDavid du Colombier       mid = (nb + na) >> 1;
286*59cc4ca5SDavid du Colombier       if (indx >= cftab[mid]) nb = mid; else na = mid;
287*59cc4ca5SDavid du Colombier    }
288*59cc4ca5SDavid du Colombier    while (na - nb != 1);
289*59cc4ca5SDavid du Colombier    return nb;
290*59cc4ca5SDavid du Colombier }
291*59cc4ca5SDavid du Colombier 
292*59cc4ca5SDavid du Colombier 
293*59cc4ca5SDavid du Colombier /*---------------------------------------------------*/
294*59cc4ca5SDavid du Colombier static
unRLE_obuf_to_output_SMALL(DState * s)295*59cc4ca5SDavid du Colombier void unRLE_obuf_to_output_SMALL ( DState* s )
296*59cc4ca5SDavid du Colombier {
297*59cc4ca5SDavid du Colombier    UChar k1;
298*59cc4ca5SDavid du Colombier 
299*59cc4ca5SDavid du Colombier    if (s->blockRandomised) {
300*59cc4ca5SDavid du Colombier 
301*59cc4ca5SDavid du Colombier       while (True) {
302*59cc4ca5SDavid du Colombier          /* try to finish existing run */
303*59cc4ca5SDavid du Colombier          while (True) {
304*59cc4ca5SDavid du Colombier             if (s->strm->avail_out == 0) return;
305*59cc4ca5SDavid du Colombier             if (s->state_out_len == 0) break;
306*59cc4ca5SDavid du Colombier             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
307*59cc4ca5SDavid du Colombier             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
308*59cc4ca5SDavid du Colombier             s->state_out_len--;
309*59cc4ca5SDavid du Colombier             s->strm->next_out++;
310*59cc4ca5SDavid du Colombier             s->strm->avail_out--;
311*59cc4ca5SDavid du Colombier             s->strm->total_out_lo32++;
312*59cc4ca5SDavid du Colombier             if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
313*59cc4ca5SDavid du Colombier          }
314*59cc4ca5SDavid du Colombier 
315*59cc4ca5SDavid du Colombier          /* can a new run be started? */
316*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1) return;
317*59cc4ca5SDavid du Colombier 
318*59cc4ca5SDavid du Colombier 
319*59cc4ca5SDavid du Colombier          s->state_out_len = 1;
320*59cc4ca5SDavid du Colombier          s->state_out_ch = s->k0;
321*59cc4ca5SDavid du Colombier          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
322*59cc4ca5SDavid du Colombier          k1 ^= BZ_RAND_MASK; s->nblock_used++;
323*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1) continue;
324*59cc4ca5SDavid du Colombier          if (k1 != s->k0) { s->k0 = k1; continue; };
325*59cc4ca5SDavid du Colombier 
326*59cc4ca5SDavid du Colombier          s->state_out_len = 2;
327*59cc4ca5SDavid du Colombier          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
328*59cc4ca5SDavid du Colombier          k1 ^= BZ_RAND_MASK; s->nblock_used++;
329*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1) continue;
330*59cc4ca5SDavid du Colombier          if (k1 != s->k0) { s->k0 = k1; continue; };
331*59cc4ca5SDavid du Colombier 
332*59cc4ca5SDavid du Colombier          s->state_out_len = 3;
333*59cc4ca5SDavid du Colombier          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
334*59cc4ca5SDavid du Colombier          k1 ^= BZ_RAND_MASK; s->nblock_used++;
335*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1) continue;
336*59cc4ca5SDavid du Colombier          if (k1 != s->k0) { s->k0 = k1; continue; };
337*59cc4ca5SDavid du Colombier 
338*59cc4ca5SDavid du Colombier          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
339*59cc4ca5SDavid du Colombier          k1 ^= BZ_RAND_MASK; s->nblock_used++;
340*59cc4ca5SDavid du Colombier          s->state_out_len = ((Int32)k1) + 4;
341*59cc4ca5SDavid du Colombier          BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK;
342*59cc4ca5SDavid du Colombier          s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
343*59cc4ca5SDavid du Colombier       }
344*59cc4ca5SDavid du Colombier 
345*59cc4ca5SDavid du Colombier    } else {
346*59cc4ca5SDavid du Colombier 
347*59cc4ca5SDavid du Colombier       while (True) {
348*59cc4ca5SDavid du Colombier          /* try to finish existing run */
349*59cc4ca5SDavid du Colombier          while (True) {
350*59cc4ca5SDavid du Colombier             if (s->strm->avail_out == 0) return;
351*59cc4ca5SDavid du Colombier             if (s->state_out_len == 0) break;
352*59cc4ca5SDavid du Colombier             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
353*59cc4ca5SDavid du Colombier             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
354*59cc4ca5SDavid du Colombier             s->state_out_len--;
355*59cc4ca5SDavid du Colombier             s->strm->next_out++;
356*59cc4ca5SDavid du Colombier             s->strm->avail_out--;
357*59cc4ca5SDavid du Colombier             s->strm->total_out_lo32++;
358*59cc4ca5SDavid du Colombier             if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
359*59cc4ca5SDavid du Colombier          }
360*59cc4ca5SDavid du Colombier 
361*59cc4ca5SDavid du Colombier          /* can a new run be started? */
362*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1) return;
363*59cc4ca5SDavid du Colombier 
364*59cc4ca5SDavid du Colombier          s->state_out_len = 1;
365*59cc4ca5SDavid du Colombier          s->state_out_ch = s->k0;
366*59cc4ca5SDavid du Colombier          BZ_GET_SMALL(k1); s->nblock_used++;
367*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1) continue;
368*59cc4ca5SDavid du Colombier          if (k1 != s->k0) { s->k0 = k1; continue; };
369*59cc4ca5SDavid du Colombier 
370*59cc4ca5SDavid du Colombier          s->state_out_len = 2;
371*59cc4ca5SDavid du Colombier          BZ_GET_SMALL(k1); s->nblock_used++;
372*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1) continue;
373*59cc4ca5SDavid du Colombier          if (k1 != s->k0) { s->k0 = k1; continue; };
374*59cc4ca5SDavid du Colombier 
375*59cc4ca5SDavid du Colombier          s->state_out_len = 3;
376*59cc4ca5SDavid du Colombier          BZ_GET_SMALL(k1); s->nblock_used++;
377*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1) continue;
378*59cc4ca5SDavid du Colombier          if (k1 != s->k0) { s->k0 = k1; continue; };
379*59cc4ca5SDavid du Colombier 
380*59cc4ca5SDavid du Colombier          BZ_GET_SMALL(k1); s->nblock_used++;
381*59cc4ca5SDavid du Colombier          s->state_out_len = ((Int32)k1) + 4;
382*59cc4ca5SDavid du Colombier          BZ_GET_SMALL(s->k0); s->nblock_used++;
383*59cc4ca5SDavid du Colombier       }
384*59cc4ca5SDavid du Colombier 
385*59cc4ca5SDavid du Colombier    }
386*59cc4ca5SDavid du Colombier }
387*59cc4ca5SDavid du Colombier 
388*59cc4ca5SDavid du Colombier 
389*59cc4ca5SDavid du Colombier /*---------------------------------------------------*/
BZ_API(BZ2_bzDecompress)390*59cc4ca5SDavid du Colombier int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
391*59cc4ca5SDavid du Colombier {
392*59cc4ca5SDavid du Colombier    DState* s;
393*59cc4ca5SDavid du Colombier    if (strm == NULL) return BZ_PARAM_ERROR;
394*59cc4ca5SDavid du Colombier    s = strm->state;
395*59cc4ca5SDavid du Colombier    if (s == NULL) return BZ_PARAM_ERROR;
396*59cc4ca5SDavid du Colombier    if (s->strm != strm) return BZ_PARAM_ERROR;
397*59cc4ca5SDavid du Colombier 
398*59cc4ca5SDavid du Colombier    while (True) {
399*59cc4ca5SDavid du Colombier       if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
400*59cc4ca5SDavid du Colombier       if (s->state == BZ_X_OUTPUT) {
401*59cc4ca5SDavid du Colombier          if (s->smallDecompress)
402*59cc4ca5SDavid du Colombier             unRLE_obuf_to_output_SMALL ( s ); else
403*59cc4ca5SDavid du Colombier             unRLE_obuf_to_output_FAST  ( s );
404*59cc4ca5SDavid du Colombier          if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
405*59cc4ca5SDavid du Colombier             BZ_FINALISE_CRC ( s->calculatedBlockCRC );
406*59cc4ca5SDavid du Colombier             if (s->verbosity >= 3)
407*59cc4ca5SDavid du Colombier                VPrintf2 ( " {0x%x, 0x%x}", s->storedBlockCRC,
408*59cc4ca5SDavid du Colombier                           s->calculatedBlockCRC );
409*59cc4ca5SDavid du Colombier             if (s->verbosity >= 2) VPrintf0 ( "]" );
410*59cc4ca5SDavid du Colombier             if (s->calculatedBlockCRC != s->storedBlockCRC)
411*59cc4ca5SDavid du Colombier                return BZ_DATA_ERROR;
412*59cc4ca5SDavid du Colombier             s->calculatedCombinedCRC
413*59cc4ca5SDavid du Colombier                = (s->calculatedCombinedCRC << 1) |
414*59cc4ca5SDavid du Colombier                     (s->calculatedCombinedCRC >> 31);
415*59cc4ca5SDavid du Colombier             s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
416*59cc4ca5SDavid du Colombier             s->state = BZ_X_BLKHDR_1;
417*59cc4ca5SDavid du Colombier          } else {
418*59cc4ca5SDavid du Colombier             return BZ_OK;
419*59cc4ca5SDavid du Colombier          }
420*59cc4ca5SDavid du Colombier       }
421*59cc4ca5SDavid du Colombier       if (s->state >= BZ_X_MAGIC_1) {
422*59cc4ca5SDavid du Colombier          Int32 r = BZ2_decompress ( s );
423*59cc4ca5SDavid du Colombier          if (r == BZ_STREAM_END) {
424*59cc4ca5SDavid du Colombier             if (s->verbosity >= 3)
425*59cc4ca5SDavid du Colombier                VPrintf2 ( "\n    combined CRCs: stored = 0x%x, computed = 0x%x",
426*59cc4ca5SDavid du Colombier                           s->storedCombinedCRC, s->calculatedCombinedCRC );
427*59cc4ca5SDavid du Colombier             if (s->calculatedCombinedCRC != s->storedCombinedCRC)
428*59cc4ca5SDavid du Colombier                return BZ_DATA_ERROR;
429*59cc4ca5SDavid du Colombier             return r;
430*59cc4ca5SDavid du Colombier          }
431*59cc4ca5SDavid du Colombier          if (s->state != BZ_X_OUTPUT) return r;
432*59cc4ca5SDavid du Colombier       }
433*59cc4ca5SDavid du Colombier    }
434*59cc4ca5SDavid du Colombier }
435*59cc4ca5SDavid du Colombier 
436*59cc4ca5SDavid du Colombier 
437*59cc4ca5SDavid du Colombier /*---------------------------------------------------*/
BZ_API(BZ2_bzDecompressEnd)438*59cc4ca5SDavid du Colombier int BZ_API(BZ2_bzDecompressEnd)  ( bz_stream *strm )
439*59cc4ca5SDavid du Colombier {
440*59cc4ca5SDavid du Colombier    DState* s;
441*59cc4ca5SDavid du Colombier    if (strm == NULL) return BZ_PARAM_ERROR;
442*59cc4ca5SDavid du Colombier    s = strm->state;
443*59cc4ca5SDavid du Colombier    if (s == NULL) return BZ_PARAM_ERROR;
444*59cc4ca5SDavid du Colombier    if (s->strm != strm) return BZ_PARAM_ERROR;
445*59cc4ca5SDavid du Colombier 
446*59cc4ca5SDavid du Colombier    if (s->tt   != NULL) BZFREE(s->tt);
447*59cc4ca5SDavid du Colombier    if (s->ll16 != NULL) BZFREE(s->ll16);
448*59cc4ca5SDavid du Colombier    if (s->ll4  != NULL) BZFREE(s->ll4);
449*59cc4ca5SDavid du Colombier 
450*59cc4ca5SDavid du Colombier    BZFREE(strm->state);
451*59cc4ca5SDavid du Colombier    strm->state = NULL;
452*59cc4ca5SDavid du Colombier 
453*59cc4ca5SDavid du Colombier    return BZ_OK;
454*59cc4ca5SDavid du Colombier }
455*59cc4ca5SDavid du Colombier 
456