| /* |
| * THIS FILE IS NOT IDENTICAL TO THE ORIGINAL |
| * FROM THE BZIP2 DISTRIBUTION. |
| * |
| * It has been modified, mainly to break the library |
| * into smaller pieces. |
| * |
| * Russ Cox |
| * rsc@plan9.bell-labs.com |
| * July 2000 |
| */ |
| |
| /*-------------------------------------------------------------*/ |
| /*--- Library top-level functions. ---*/ |
| /*--- bzlib.c ---*/ |
| /*-------------------------------------------------------------*/ |
| |
| /*-- |
| This file is a part of bzip2 and/or libbzip2, a program and |
| library for lossless, block-sorting data compression. |
| |
| Copyright (C) 1996-2000 Julian R Seward. All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions |
| are met: |
| |
| 1. Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| |
| 2. The origin of this software must not be misrepresented; you must |
| not claim that you wrote the original software. If you use this |
| software in a product, an acknowledgment in the product |
| documentation would be appreciated but is not required. |
| |
| 3. Altered source versions must be plainly marked as such, and must |
| not be misrepresented as being the original software. |
| |
| 4. The name of the author may not be used to endorse or promote |
| products derived from this software without specific prior written |
| permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS |
| OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
| GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| Julian Seward, Cambridge, UK. |
| jseward@acm.org |
| bzip2/libbzip2 version 1.0 of 21 March 2000 |
| |
| This program is based on (at least) the work of: |
| Mike Burrows |
| David Wheeler |
| Peter Fenwick |
| Alistair Moffat |
| Radford Neal |
| Ian H. Witten |
| Robert Sedgewick |
| Jon L. Bentley |
| |
| For more information on these sources, see the manual. |
| --*/ |
| |
| /*-- |
| CHANGES |
| ~~~~~~~ |
| 0.9.0 -- original version. |
| |
| 0.9.0a/b -- no changes in this file. |
| |
| 0.9.0c |
| * made zero-length BZ_FLUSH work correctly in bzCompress(). |
| * fixed bzWrite/bzRead to ignore zero-length requests. |
| * fixed bzread to correctly handle read requests after EOF. |
| * wrong parameter order in call to bzDecompressInit in |
| bzBuffToBuffDecompress. Fixed. |
| --*/ |
| |
| #include "os.h" |
| #include "bzlib.h" |
| #include "bzlib_private.h" |
| |
| /*---------------------------------------------------*/ |
| /*--- Decompression stuff ---*/ |
| /*---------------------------------------------------*/ |
| |
| /*---------------------------------------------------*/ |
| int BZ_API(BZ2_bzDecompressInit) |
| ( bz_stream* strm, |
| int verbosity, |
| int small ) |
| { |
| DState* s; |
| |
| if (!bz_config_ok()) return BZ_CONFIG_ERROR; |
| |
| if (strm == NULL) return BZ_PARAM_ERROR; |
| if (small != 0 && small != 1) return BZ_PARAM_ERROR; |
| if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; |
| |
| if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; |
| if (strm->bzfree == NULL) strm->bzfree = default_bzfree; |
| |
| s = BZALLOC( sizeof(DState) ); |
| if (s == NULL) return BZ_MEM_ERROR; |
| s->strm = strm; |
| strm->state = s; |
| s->state = BZ_X_MAGIC_1; |
| s->bsLive = 0; |
| s->bsBuff = 0; |
| s->calculatedCombinedCRC = 0; |
| strm->total_in_lo32 = 0; |
| strm->total_in_hi32 = 0; |
| strm->total_out_lo32 = 0; |
| strm->total_out_hi32 = 0; |
| s->smallDecompress = (Bool)small; |
| s->ll4 = NULL; |
| s->ll16 = NULL; |
| s->tt = NULL; |
| s->currBlockNo = 0; |
| s->verbosity = verbosity; |
| |
| return BZ_OK; |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| static |
| void unRLE_obuf_to_output_FAST ( DState* s ) |
| { |
| UChar k1; |
| |
| if (s->blockRandomised) { |
| |
| while (True) { |
| /* try to finish existing run */ |
| while (True) { |
| if (s->strm->avail_out == 0) return; |
| if (s->state_out_len == 0) break; |
| *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; |
| BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); |
| s->state_out_len--; |
| s->strm->next_out++; |
| s->strm->avail_out--; |
| s->strm->total_out_lo32++; |
| if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; |
| } |
| |
| /* can a new run be started? */ |
| if (s->nblock_used == s->save_nblock+1) return; |
| |
| |
| s->state_out_len = 1; |
| s->state_out_ch = s->k0; |
| BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; |
| k1 ^= BZ_RAND_MASK; s->nblock_used++; |
| if (s->nblock_used == s->save_nblock+1) continue; |
| if (k1 != s->k0) { s->k0 = k1; continue; }; |
| |
| s->state_out_len = 2; |
| BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; |
| k1 ^= BZ_RAND_MASK; s->nblock_used++; |
| if (s->nblock_used == s->save_nblock+1) continue; |
| if (k1 != s->k0) { s->k0 = k1; continue; }; |
| |
| s->state_out_len = 3; |
| BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; |
| k1 ^= BZ_RAND_MASK; s->nblock_used++; |
| if (s->nblock_used == s->save_nblock+1) continue; |
| if (k1 != s->k0) { s->k0 = k1; continue; }; |
| |
| BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; |
| k1 ^= BZ_RAND_MASK; s->nblock_used++; |
| s->state_out_len = ((Int32)k1) + 4; |
| BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; |
| s->k0 ^= BZ_RAND_MASK; s->nblock_used++; |
| } |
| |
| } else { |
| |
| /* restore */ |
| UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; |
| UChar c_state_out_ch = s->state_out_ch; |
| Int32 c_state_out_len = s->state_out_len; |
| Int32 c_nblock_used = s->nblock_used; |
| Int32 c_k0 = s->k0; |
| UInt32* c_tt = s->tt; |
| UInt32 c_tPos = s->tPos; |
| char* cs_next_out = s->strm->next_out; |
| unsigned int cs_avail_out = s->strm->avail_out; |
| /* end restore */ |
| |
| UInt32 avail_out_INIT = cs_avail_out; |
| Int32 s_save_nblockPP = s->save_nblock+1; |
| unsigned int total_out_lo32_old; |
| |
| while (True) { |
| |
| /* try to finish existing run */ |
| if (c_state_out_len > 0) { |
| while (True) { |
| if (cs_avail_out == 0) goto return_notr; |
| if (c_state_out_len == 1) break; |
| *( (UChar*)(cs_next_out) ) = c_state_out_ch; |
| BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); |
| c_state_out_len--; |
| cs_next_out++; |
| cs_avail_out--; |
| } |
| s_state_out_len_eq_one: |
| { |
| if (cs_avail_out == 0) { |
| c_state_out_len = 1; goto return_notr; |
| }; |
| *( (UChar*)(cs_next_out) ) = c_state_out_ch; |
| BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); |
| cs_next_out++; |
| cs_avail_out--; |
| } |
| } |
| /* can a new run be started? */ |
| if (c_nblock_used == s_save_nblockPP) { |
| c_state_out_len = 0; goto return_notr; |
| }; |
| c_state_out_ch = c_k0; |
| BZ_GET_FAST_C(k1); c_nblock_used++; |
| if (k1 != c_k0) { |
| c_k0 = k1; goto s_state_out_len_eq_one; |
| }; |
| if (c_nblock_used == s_save_nblockPP) |
| goto s_state_out_len_eq_one; |
| |
| c_state_out_len = 2; |
| BZ_GET_FAST_C(k1); c_nblock_used++; |
| if (c_nblock_used == s_save_nblockPP) continue; |
| if (k1 != c_k0) { c_k0 = k1; continue; }; |
| |
| c_state_out_len = 3; |
| BZ_GET_FAST_C(k1); c_nblock_used++; |
| if (c_nblock_used == s_save_nblockPP) continue; |
| if (k1 != c_k0) { c_k0 = k1; continue; }; |
| |
| BZ_GET_FAST_C(k1); c_nblock_used++; |
| c_state_out_len = ((Int32)k1) + 4; |
| BZ_GET_FAST_C(c_k0); c_nblock_used++; |
| } |
| |
| return_notr: |
| total_out_lo32_old = s->strm->total_out_lo32; |
| s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); |
| if (s->strm->total_out_lo32 < total_out_lo32_old) |
| s->strm->total_out_hi32++; |
| |
| /* save */ |
| s->calculatedBlockCRC = c_calculatedBlockCRC; |
| s->state_out_ch = c_state_out_ch; |
| s->state_out_len = c_state_out_len; |
| s->nblock_used = c_nblock_used; |
| s->k0 = c_k0; |
| s->tt = c_tt; |
| s->tPos = c_tPos; |
| s->strm->next_out = cs_next_out; |
| s->strm->avail_out = cs_avail_out; |
| /* end save */ |
| } |
| } |
| |
| |
| |
| /*---------------------------------------------------*/ |
| __inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) |
| { |
| Int32 nb, na, mid; |
| nb = 0; |
| na = 256; |
| do { |
| mid = (nb + na) >> 1; |
| if (indx >= cftab[mid]) nb = mid; else na = mid; |
| } |
| while (na - nb != 1); |
| return nb; |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| static |
| void unRLE_obuf_to_output_SMALL ( DState* s ) |
| { |
| UChar k1; |
| |
| if (s->blockRandomised) { |
| |
| while (True) { |
| /* try to finish existing run */ |
| while (True) { |
| if (s->strm->avail_out == 0) return; |
| if (s->state_out_len == 0) break; |
| *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; |
| BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); |
| s->state_out_len--; |
| s->strm->next_out++; |
| s->strm->avail_out--; |
| s->strm->total_out_lo32++; |
| if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; |
| } |
| |
| /* can a new run be started? */ |
| if (s->nblock_used == s->save_nblock+1) return; |
| |
| |
| s->state_out_len = 1; |
| s->state_out_ch = s->k0; |
| BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; |
| k1 ^= BZ_RAND_MASK; s->nblock_used++; |
| if (s->nblock_used == s->save_nblock+1) continue; |
| if (k1 != s->k0) { s->k0 = k1; continue; }; |
| |
| s->state_out_len = 2; |
| BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; |
| k1 ^= BZ_RAND_MASK; s->nblock_used++; |
| if (s->nblock_used == s->save_nblock+1) continue; |
| if (k1 != s->k0) { s->k0 = k1; continue; }; |
| |
| s->state_out_len = 3; |
| BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; |
| k1 ^= BZ_RAND_MASK; s->nblock_used++; |
| if (s->nblock_used == s->save_nblock+1) continue; |
| if (k1 != s->k0) { s->k0 = k1; continue; }; |
| |
| BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; |
| k1 ^= BZ_RAND_MASK; s->nblock_used++; |
| s->state_out_len = ((Int32)k1) + 4; |
| BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; |
| s->k0 ^= BZ_RAND_MASK; s->nblock_used++; |
| } |
| |
| } else { |
| |
| while (True) { |
| /* try to finish existing run */ |
| while (True) { |
| if (s->strm->avail_out == 0) return; |
| if (s->state_out_len == 0) break; |
| *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; |
| BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); |
| s->state_out_len--; |
| s->strm->next_out++; |
| s->strm->avail_out--; |
| s->strm->total_out_lo32++; |
| if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; |
| } |
| |
| /* can a new run be started? */ |
| if (s->nblock_used == s->save_nblock+1) return; |
| |
| s->state_out_len = 1; |
| s->state_out_ch = s->k0; |
| BZ_GET_SMALL(k1); s->nblock_used++; |
| if (s->nblock_used == s->save_nblock+1) continue; |
| if (k1 != s->k0) { s->k0 = k1; continue; }; |
| |
| s->state_out_len = 2; |
| BZ_GET_SMALL(k1); s->nblock_used++; |
| if (s->nblock_used == s->save_nblock+1) continue; |
| if (k1 != s->k0) { s->k0 = k1; continue; }; |
| |
| s->state_out_len = 3; |
| BZ_GET_SMALL(k1); s->nblock_used++; |
| if (s->nblock_used == s->save_nblock+1) continue; |
| if (k1 != s->k0) { s->k0 = k1; continue; }; |
| |
| BZ_GET_SMALL(k1); s->nblock_used++; |
| s->state_out_len = ((Int32)k1) + 4; |
| BZ_GET_SMALL(s->k0); s->nblock_used++; |
| } |
| |
| } |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) |
| { |
| DState* s; |
| if (strm == NULL) return BZ_PARAM_ERROR; |
| s = strm->state; |
| if (s == NULL) return BZ_PARAM_ERROR; |
| if (s->strm != strm) return BZ_PARAM_ERROR; |
| |
| while (True) { |
| if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; |
| if (s->state == BZ_X_OUTPUT) { |
| if (s->smallDecompress) |
| unRLE_obuf_to_output_SMALL ( s ); else |
| unRLE_obuf_to_output_FAST ( s ); |
| if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { |
| BZ_FINALISE_CRC ( s->calculatedBlockCRC ); |
| if (s->verbosity >= 3) |
| VPrintf2 ( " {0x%x, 0x%x}", s->storedBlockCRC, |
| s->calculatedBlockCRC ); |
| if (s->verbosity >= 2) VPrintf0 ( "]" ); |
| if (s->calculatedBlockCRC != s->storedBlockCRC) |
| return BZ_DATA_ERROR; |
| s->calculatedCombinedCRC |
| = (s->calculatedCombinedCRC << 1) | |
| (s->calculatedCombinedCRC >> 31); |
| s->calculatedCombinedCRC ^= s->calculatedBlockCRC; |
| s->state = BZ_X_BLKHDR_1; |
| } else { |
| return BZ_OK; |
| } |
| } |
| if (s->state >= BZ_X_MAGIC_1) { |
| Int32 r = BZ2_decompress ( s ); |
| if (r == BZ_STREAM_END) { |
| if (s->verbosity >= 3) |
| VPrintf2 ( "\n combined CRCs: stored = 0x%x, computed = 0x%x", |
| s->storedCombinedCRC, s->calculatedCombinedCRC ); |
| if (s->calculatedCombinedCRC != s->storedCombinedCRC) |
| return BZ_DATA_ERROR; |
| return r; |
| } |
| if (s->state != BZ_X_OUTPUT) return r; |
| } |
| } |
| |
| /* |
| AssertH ( 0, 6001 ); |
| |
| return 0; |
| */ |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) |
| { |
| DState* s; |
| if (strm == NULL) return BZ_PARAM_ERROR; |
| s = strm->state; |
| if (s == NULL) return BZ_PARAM_ERROR; |
| if (s->strm != strm) return BZ_PARAM_ERROR; |
| |
| if (s->tt != NULL) BZFREE(s->tt); |
| if (s->ll16 != NULL) BZFREE(s->ll16); |
| if (s->ll4 != NULL) BZFREE(s->ll4); |
| |
| BZFREE(strm->state); |
| strm->state = NULL; |
| |
| return BZ_OK; |
| } |
| |