From cda45ed7dd0d80203a4a63a75428c77073b46cd2 Mon Sep 17 00:00:00 2001 From: henrypp Date: Thu, 17 Dec 2015 21:28:19 +0600 Subject: [PATCH] v1.5 released --- CHANGELOG.md | 6 + README.md | 83 +- bin/History.txt | 6 + bin/Readme.txt | 83 +- bin/chrlauncher.ini | 69 +- chrlauncher.vcxproj | 40 +- chrlauncher.vcxproj.filters | 44 +- src/include/blocksort.c | 1094 ++++++++++++++++++++++++ src/include/bzlib.c | 1587 +++++++++++++++++++++++++++++++++++ src/include/bzlib.h | 282 +++++++ src/include/bzlib_private.h | 503 +++++++++++ src/include/compress.c | 672 +++++++++++++++ src/include/crctable.c | 104 +++ src/include/decompress.c | 626 ++++++++++++++ src/include/huffman.c | 205 +++++ src/include/mar.h | 198 +++++ src/include/mar_private.h | 79 ++ src/include/mar_read.c | 574 +++++++++++++ src/include/randtable.c | 84 ++ src/main.cpp | Bin 26370 -> 36178 bytes src/main.h | Bin 1312 -> 980 bytes src/res/101.ico | Bin 0 -> 85989 bytes src/resource.h | 23 +- src/resource.rc | Bin 5646 -> 5468 bytes 24 files changed, 6283 insertions(+), 79 deletions(-) create mode 100644 src/include/blocksort.c create mode 100644 src/include/bzlib.c create mode 100644 src/include/bzlib.h create mode 100644 src/include/bzlib_private.h create mode 100644 src/include/compress.c create mode 100644 src/include/crctable.c create mode 100644 src/include/decompress.c create mode 100644 src/include/huffman.c create mode 100644 src/include/mar.h create mode 100644 src/include/mar_private.h create mode 100644 src/include/mar_read.c create mode 100644 src/include/randtable.c create mode 100644 src/res/101.ico diff --git a/CHANGELOG.md b/CHANGELOG.md index 2af30fd..6e3117f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v1.5 (17 December 2015) ++ added "Mozilla Firefox" support ++ added new settings ++ added command line for run specified browser +- fixed CreateProcess current directory parameter + v1.4 (4 December 2015) + added "ChromiumDirectory" setting - fixed statusbar flickering diff --git a/README.md b/README.md index 4cffdfe..a217f34 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,87 @@ # chrlauncher -Small and very fast portable Chromium launcher and updater. +Small and very fast portable launcher and updater for Chromium and Mozilla Firefox. #### Supported browser -- Launcher - all Chromium based browsers (see "Folder structure"). -- Updater - only Chromium. +- Launcher - Chromium, Mozilla Firefox and their clones (hi Google Chrome!). +- Updater - Chromium, Mozilla Firefox. #### Folder structure -- \bin - Chromium binaries directory. -- \profile - Chromium profile directory. +- chromium\bin - Chromium binaries directory. +- firefox\bin - Mozilla Firefox binaries directory. + +#### Command line: +- /browser chromium - run Chromium +- /browser firefox - run Mozilla Firefox #### Settings ~~~ [chrlauncher] -# Select Chromium architecture: +# Set binary architecture: +# +# 0 -> autodetect (default) +# 64 -> 64-bit +# 32 -> 32-bit +# +BrowserArchitecture=0 + +# Last update checking timestamp: # -# 0 -> auto detected -# 64 -> check for 64-bit Chromium -# 32 -> check for 32-bit Chromium -ChromiumArchitecture=0 +BrowserCheckDate=0 -# Check for new version once in X days: +# Check for new browser version once in X days: +# +# 0 -> disable update checking +# 1 -> once in day (default) # -# 0 -> disable update checking -# 1 -> once in day -ChromiumCheckDays=1 +BrowserCheckPeriod=1 -# Command line for run Chromium -# See here: http://peter.sh/experiments/chromium-command-line-switches/ +# Select internet browser: +# +# chromium -> Chromium (default) +# firefox -> Firefox # -#ChromiumCommandLine=--user-data-dir=..\profile --no-default-browser-check +BrowserName=chromium + +# Command line for Chromium +# +# See here: +# http://peter.sh/experiments/chromium-command-line-switches/ +# +ChromiumCommandLine=--user-data-dir=..\profile --no-default-browser-check # Chromium binaries directory # -#ChromiumDirectory=bin +ChromiumDirectory=.\chromium\bin + +# Command line for Firefox +# +# See here: +# https://developer.mozilla.org/docs/Mozilla/Command_Line_Options +# +FirefoxCommandLine=-profile "..\profile" -no-remote + +# Firefox binaries directory +# +FirefoxDirectory=.\firefox\bin + +# Firefox update channel +# +# release -> Release channel (default) +# esr -> ESR (Extended Support Release) +# +FirefoxChannel=release + +# Localization: +# +# en-US -> english (default) +# ru -> russian +# +# See here: +# https://ftp.mozilla.org/pub/firefox/releases/latest/README.txt +# +FirefoxLocalization=en-US ~~~ Website: www.henrypp.org
Support: support@henrypp.org
diff --git a/bin/History.txt b/bin/History.txt index 0a2bcd4..9a22420 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -1,3 +1,9 @@ +v1.5 (17 December 2015) ++ added "Mozilla Firefox" support ++ added new settings ++ added command line for run specified browser +- fixed CreateProcess current directory parameter + v1.4 (4 December 2015) + added "ChromiumDirectory" setting - fixed statusbar flickering diff --git a/bin/Readme.txt b/bin/Readme.txt index a84fd39..d103a62 100644 --- a/bin/Readme.txt +++ b/bin/Readme.txt @@ -1,39 +1,86 @@ chrlauncher -Small and very fast portable Chromium launcher and updater. +Small and very fast portable launcher and updater for Chromium and Mozilla Firefox. Supported browser: -- Launcher - all Chromium based browsers (see "Folder structure"). -- Updater - only Chromium. +- Launcher - Chromium, Mozilla Firefox and their clones (hi Google Chrome!). +- Updater - Chromium, Mozilla Firefox. Folder structure: -- \bin - Chromium binaries directory. -- \profile - Chromium profile directory. +- chromium\bin - Chromium binaries directory. +- firefox\bin - Mozilla Firefox binaries directory. + +Command line: +- /browser chromium - run Chromium +- /browser firefox - run Mozilla Firefox Settings: [chrlauncher] -# Select Chromium architecture: +# Set binary architecture: +# +# 0 -> autodetect (default) +# 64 -> 64-bit +# 32 -> 32-bit +# +BrowserArchitecture=0 + +# Last update checking timestamp: # -# 0 -> auto detected -# 64 -> check for 64-bit Chromium -# 32 -> check for 32-bit Chromium -ChromiumArchitecture=0 +BrowserCheckDate=0 -# Check for new version once in X days: +# Check for new browser version once in X days: +# +# 0 -> disable update checking +# 1 -> once in day (default) # -# 0 -> disable update checking -# 1 -> once in day -ChromiumCheckDays=1 +BrowserCheckPeriod=1 -# Command line for run Chromium -# See here: http://peter.sh/experiments/chromium-command-line-switches/ +# Select internet browser: +# +# chromium -> Chromium (default) +# firefox -> Firefox # -#ChromiumCommandLine=--user-data-dir=..\profile --no-default-browser-check +BrowserName=chromium + +# Command line for Chromium +# +# See here: +# http://peter.sh/experiments/chromium-command-line-switches/ +# +ChromiumCommandLine=--user-data-dir=..\profile --no-default-browser-check # Chromium binaries directory # -#ChromiumDirectory=bin +ChromiumDirectory=.\chromium\bin + +# Command line for Firefox +# +# See here: +# https://developer.mozilla.org/docs/Mozilla/Command_Line_Options +# +FirefoxCommandLine=-profile "..\profile" -no-remote + +# Firefox binaries directory +# +FirefoxDirectory=.\firefox\bin + +# Firefox update channel +# +# release -> Release channel (default) +# esr -> ESR (Extended Support Release) +# +FirefoxChannel=release + +# Localization: +# +# en-US -> english (default) +# ru -> russian +# +# See here: +# https://ftp.mozilla.org/pub/firefox/releases/latest/README.txt +# +FirefoxLocalization=en-US Website: www.henrypp.org Support: support@henrypp.org diff --git a/bin/chrlauncher.ini b/bin/chrlauncher.ini index 469c380..c335240 100644 --- a/bin/chrlauncher.ini +++ b/bin/chrlauncher.ini @@ -1,23 +1,66 @@ [chrlauncher] -# Select Chromium architecture: +# Set binary architecture: # -# 0 -> auto detected -# 64 -> check for 64-bit Chromium -# 32 -> check for 32-bit Chromium -ChromiumArchitecture=0 +# 0 -> autodetect (default) +# 64 -> 64-bit +# 32 -> 32-bit +# +BrowserArchitecture=0 + +# Last update checking timestamp: +# +BrowserCheckDate=0 + +# Check for new browser version once in X days: +# +# 0 -> disable update checking +# 1 -> once in day (default) +# +BrowserCheckPeriod=1 -# Check for new version once in X days: +# Select internet browser: +# +# chromium -> Chromium (default) +# firefox -> Firefox # -# 0 -> disable update checking -# 1 -> once in day -ChromiumCheckDays=1 +BrowserName=chromium -# Command line for run Chromium -# See here: http://peter.sh/experiments/chromium-command-line-switches/ +# Command line for Chromium +# +# See here: +# http://peter.sh/experiments/chromium-command-line-switches/ # -#ChromiumCommandLine=--user-data-dir=..\profile --no-default-browser-check +ChromiumCommandLine=--user-data-dir=..\profile --no-default-browser-check # Chromium binaries directory # -#ChromiumDirectory=bin +ChromiumDirectory=.\chromium\bin + +# Command line for Firefox +# +# See here: +# https://developer.mozilla.org/docs/Mozilla/Command_Line_Options +# +FirefoxCommandLine=-profile "..\profile" -no-remote + +# Firefox binaries directory +# +FirefoxDirectory=.\firefox\bin + +# Firefox update channel +# +# release -> Release channel (default) +# esr -> ESR (Extended Support Release) +# +FirefoxChannel=release + +# Localization: +# +# en-US -> english (default) +# ru -> russian +# +# See here: +# https://ftp.mozilla.org/pub/firefox/releases/latest/README.txt +# +FirefoxLocalization=en-US diff --git a/chrlauncher.vcxproj b/chrlauncher.vcxproj index 00c2796..c4cfc1d 100644 --- a/chrlauncher.vcxproj +++ b/chrlauncher.vcxproj @@ -70,8 +70,8 @@ - $(SolutionDir)bin\ - $(ProjectName)$(PlatformArchitecture) + $(SolutionDir)bin\$(PlatformArchitecture)\ + $(ProjectName) $(VC_IncludePath);$(WindowsSDK_IncludePath);.\..\routine\;.\src\include\;.\src\; $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;.\src\lib\32\ false @@ -79,8 +79,8 @@ false - $(SolutionDir)bin\ - $(ProjectName)$(PlatformArchitecture) + $(SolutionDir)bin\$(PlatformArchitecture)\ + $(ProjectName) $(VC_IncludePath);$(WindowsSDK_IncludePath);.\..\routine\;.\src\include\;.\src\; $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;.\src\lib\32\ false @@ -88,8 +88,8 @@ false - $(SolutionDir)bin\ - $(ProjectName)$(PlatformArchitecture) + $(SolutionDir)bin\$(PlatformArchitecture)\ + $(ProjectName) $(VC_IncludePath);$(WindowsSDK_IncludePath);.\..\routine\;.\src\include\;.\src\; $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;.\src\lib\64\ false @@ -97,8 +97,8 @@ false - $(SolutionDir)bin\ - $(ProjectName)$(PlatformArchitecture) + $(SolutionDir)bin\$(PlatformArchitecture)\ + $(ProjectName) $(VC_IncludePath);$(WindowsSDK_IncludePath);.\..\routine\;.\src\include\;.\src\; $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;.\src\lib\64\ false @@ -118,7 +118,7 @@ false false true - _UNICODE;UNICODE;_CRT_SECURE_NO_WARNINGS;APPLICATION_NO_ABOUT; APPLICATION_NO_SETTINGS; APPLICATION_NO_UPDATES;%(PreprocessorDefinitions) + XP_WIN;_UNICODE;UNICODE;_CRT_SECURE_NO_WARNINGS;_APP_NO_SETTINGS;_APP_NO_UPDATES;%(PreprocessorDefinitions) true false ProgramDatabase @@ -147,7 +147,7 @@ false false true - _UNICODE;UNICODE;_CRT_SECURE_NO_WARNINGS;APPLICATION_NO_ABOUT; APPLICATION_NO_SETTINGS; APPLICATION_NO_UPDATES;%(PreprocessorDefinitions) + XP_WIN;_UNICODE;UNICODE;_CRT_SECURE_NO_WARNINGS;_APP_NO_SETTINGS;_APP_NO_UPDATES;%(PreprocessorDefinitions) true false ProgramDatabase @@ -180,7 +180,7 @@ false true None - _UNICODE;UNICODE;_CRT_SECURE_NO_WARNINGS;APPLICATION_NO_SETTINGS;APPLICATION_NO_UPDATES;%(PreprocessorDefinitions) + XP_WIN;_UNICODE;UNICODE;_CRT_SECURE_NO_WARNINGS;_APP_NO_SETTINGS;_APP_NO_UPDATES;%(PreprocessorDefinitions) true false false @@ -214,7 +214,7 @@ true true None - _UNICODE;UNICODE;_CRT_SECURE_NO_WARNINGS;APPLICATION_NO_SETTINGS;APPLICATION_NO_UPDATES;%(PreprocessorDefinitions) + XP_WIN;_UNICODE;UNICODE;_CRT_SECURE_NO_WARNINGS;_APP_NO_SETTINGS;_APP_NO_UPDATES;%(PreprocessorDefinitions) false false @@ -234,14 +234,26 @@ - + + + + + + + + + - + + + + + diff --git a/chrlauncher.vcxproj.filters b/chrlauncher.vcxproj.filters index 5ecd332..8e3e59d 100644 --- a/chrlauncher.vcxproj.filters +++ b/chrlauncher.vcxproj.filters @@ -21,10 +21,34 @@ Source Files - + Source Files - + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + Source Files @@ -38,10 +62,22 @@ Header Files - + Header Files - + + Header Files + + + Header Files + + + Header Files + + + Header Files + + Header Files diff --git a/src/include/blocksort.c b/src/include/blocksort.c new file mode 100644 index 0000000..8535c93 --- /dev/null +++ b/src/include/blocksort.c @@ -0,0 +1,1094 @@ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +void fallbackSimpleSort ( UInt32* fmap, + UInt32* eclass, + Int32 lo, + Int32 hi ) +{ + Int32 i, j, tmp; + UInt32 ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for ( i = hi-4; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for ( i = hi-1; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define fvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + fswap(fmap[yyp1], fmap[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + + +#define fmin(a,b) ((a) < (b)) ? (a) : (b) + +#define fpush(lz,hz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; } + +#define fpop(lz,hz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; } + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + + +static +void fallbackQSort3 ( UInt32* fmap, + UInt32* eclass, + Int32 loSt, + Int32 hiSt ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m; + Int32 sp, lo, hi; + UInt32 med, r, r3; + Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; + Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush ( loSt, hiSt ); + + while (sp > 0) { + + AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); + + fpop ( lo, hi ); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort ( fmap, eclass, lo, hi ); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + avoid bad cases. Median of 9 seems to help but + looks rather expensive. This too seems to work but + is cheaper. Guidance for the magic constants + 7621 and 32768 is taken from Sedgewick's algorithms + book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) med = eclass[fmap[lo]]; else + if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unLo]] - (Int32)med; + if (n == 0) { + fswap(fmap[unLo], fmap[ltLo]); + ltLo++; unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unHi]] - (Int32)med; + if (n == 0) { + fswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); + + if (gtHi < ltLo) continue; + + n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); + m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush ( lo, n ); + fpush ( m, hi ); + } else { + fpush ( m, hi ); + fpush ( lo, n ); + } + } +} + +#undef fmin +#undef fpush +#undef fpop +#undef fswap +#undef fvswap +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + eclass exists for [0 .. nblock-1] + ((UChar*)eclass) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)eclass) [0 .. nblock-1] holds block + All other areas of eclass destroyed + fmap [0 .. nblock-1] holds sorted order + bhtab [ 0 .. 2+(nblock/32) ] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort ( UInt32* fmap, + UInt32* eclass, + UInt32* bhtab, + Int32 nblock, + Int32 verb ) +{ + Int32 ftab[257]; + Int32 ftabCopy[256]; + Int32 H, i, j, k, l, r, cc, cc1; + Int32 nNotDone; + Int32 nBhtab; + UChar* eclass8 = (UChar*)eclass; + + /*-- + Initial 1-char radix sort to generate + initial fmap and initial BH bits. + --*/ + if (verb >= 4) + VPrintf0 ( " bucket sorting ...\n" ); + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + (nblock / 32); + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /*-- + Inductively refine the buckets. Kind-of an + "exponential radix sort" (!), inspired by the + Manber-Myers suffix array construction algorithm. + --*/ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + + if (verb >= 4) + VPrintf1 ( " depth %6d has ", H ); + + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) j = i; + k = fmap[i] - H; if (k < 0) k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3 ( fmap, eclass, l, r ); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { SET_BH(i); cc = cc1; }; + } + } + } + + if (verb >= 4) + VPrintf1 ( "%6d unresolved strings\n", nNotDone ); + + H *= 2; + if (H > nblock || nNotDone == 0) break; + } + + /*-- + Reconstruct the original block in + eclass8 [0 .. nblock-1], since the + previous phase destroyed it. + --*/ + if (verb >= 4) + VPrintf0 ( " reconstructing block ...\n" ); + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (UChar)j; + } + AssertH ( j < 256, 1005 ); +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +Bool mainGtU ( UInt32 i1, + UInt32 i2, + UChar* block, + UInt16* quadrant, + UInt32 nblock, + Int32* budget ) +{ + Int32 k; + UChar c1, c2; + UInt16 s1, s2; + + AssertD ( i1 != i2, "mainGtU" ); + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 9 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 10 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 11 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 12 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + + k = nblock + 8; + + do { + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + k -= 8; + (*budget)--; + } + while (k >= 0); + + return False; +} + + +/*---------------------------------------------*/ +/*-- + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. +--*/ +static +Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + +static +void mainSimpleSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 lo, + Int32 hi, + Int32 d, + Int32* budget ) +{ + Int32 i, j, h, bigN, hp; + UInt32 v; + + bigN = hi - lo + 1; + if (bigN < 2) return; + + hp = 0; + while (incs[hp] < bigN) hp++; + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (True) { + + /*-- copy 1 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + if (*budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/*-- + The following is an implementation of + an elegant 3-way quicksort for strings, + described in a paper "Fast Algorithms for + Sorting and Searching Strings", by Robert + Sedgewick and Jon L. Bentley. +--*/ + +#define mswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define mvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + mswap(ptr[yyp1], ptr[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + +static +__inline__ +UChar mmed3 ( UChar a, UChar b, UChar c ) +{ + UChar t; + if (a > b) { t = a; a = b; b = t; }; + if (b > c) { + b = c; + if (a > b) b = a; + } + return b; +} + +#define mmin(a,b) ((a) < (b)) ? (a) : (b) + +#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; } + +#define mpop(lz,hz,dz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; } + + +#define mnextsize(az) (nextHi[az]-nextLo[az]) + +#define mnextswap(az,bz) \ + { Int32 tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } + + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static +void mainQSort3 ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 loSt, + Int32 hiSt, + Int32 dSt, + Int32* budget ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m, med; + Int32 sp, lo, hi, d; + + Int32 stackLo[MAIN_QSORT_STACK_SIZE]; + Int32 stackHi[MAIN_QSORT_STACK_SIZE]; + Int32 stackD [MAIN_QSORT_STACK_SIZE]; + + Int32 nextLo[3]; + Int32 nextHi[3]; + Int32 nextD [3]; + + sp = 0; + mpush ( loSt, hiSt, dSt ); + + while (sp > 0) { + + AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); + + mpop ( lo, hi, d ); + if (hi - lo < MAIN_QSORT_SMALL_THRESH || + d > MAIN_QSORT_DEPTH_THRESH) { + mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); + if (*budget < 0) return; + continue; + } + + med = (Int32) + mmed3 ( block[ptr[ lo ]+d], + block[ptr[ hi ]+d], + block[ptr[ (lo+hi)>>1 ]+d] ); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (True) { + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; unLo++; continue; + }; + if (n > 0) break; + unLo++; + } + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; unHi--; continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "mainQSort3(2)" ); + + if (gtHi < ltLo) { + mpush(lo, hi, d+1 ); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); + + mpush (nextLo[0], nextHi[0], nextD[0]); + mpush (nextLo[1], nextHi[1], nextD[1]); + mpush (nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mswap +#undef mvswap +#undef mpush +#undef mpop +#undef mmin +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > N_OVERSHOOT + block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)block32) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)block32) [0 .. nblock-1] holds block + All other areas of block32 destroyed + ftab [0 .. 65536 ] destroyed + ptr [0 .. nblock-1] holds sorted order + if (*budget < 0), sorting was abandoned +*/ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static +void mainSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + UInt32* ftab, + Int32 nblock, + Int32 verb, + Int32* budget ) +{ + Int32 i, j, k, ss, sb; + Int32 runningOrder[256]; + Bool bigDone[256]; + Int32 copyStart[256]; + Int32 copyEnd [256]; + UChar c1; + Int32 numQSorted; + UInt16 s; + if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); + + /*-- set up the 2-byte frequency table --*/ + for (i = 65536; i >= 0; i--) ftab[i] = 0; + + j = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); + ftab[j]++; + } + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); + + /*-- Complete the initial radix sort --*/ + for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; + + s = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-3; + } + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + } + + /*-- + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + --*/ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + Int32 vv; + Int32 h = 1; + do h = 3 * h + 1; while (h <= 256); + do { + h = h / 3; + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { + runningOrder[j] = runningOrder[j-h]; + j = j - h; + if (j <= (h - 1)) goto zero; + } + zero: + runningOrder[j] = vv; + } + } while (h != 1); + } + + /*-- + The main sorting loop. + --*/ + + numQSorted = 0; + + for (i = 0; i <= 255; i++) { + + /*-- + Process big buckets, starting with the least full. + Basically this is a 3-step process in which we call + mainQSort3 to sort the small buckets [ss, j], but + also make a big effort to avoid the calls if we can. + --*/ + ss = runningOrder[i]; + + /*-- + Step 1: + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j], for j != ss. + Hopefully previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + --*/ + for (j = 0; j <= 255; j++) { + if (j != ss) { + sb = (ss << 8) + j; + if ( ! (ftab[sb] & SETMASK) ) { + Int32 lo = ftab[sb] & CLEARMASK; + Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + if (verb >= 4) + VPrintf4 ( " qsort [0x%x, 0x%x] " + "done %d this %d\n", + ss, j, numQSorted, hi - lo + 1 ); + mainQSort3 ( + ptr, block, quadrant, nblock, + lo, hi, BZ_N_RADIX, budget + ); + numQSorted += (hi - lo + 1); + if (*budget < 0) return; + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH ( !bigDone[ss], 1006 ); + + /*-- + Step 2: + Now scan this big bucket [ss] so as to synthesise the + sorted order for small buckets [t, ss] for all t, + including, magically, the bucket [ss,ss] too. + This will avoid doing Real Work in subsequent Step 1's. + --*/ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyStart[c1]++ ] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyEnd[c1]-- ] = k; + } + } + + AssertH ( (copyStart[ss]-1 == copyEnd[ss]) + || + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + Necessity for this case is demonstrated by compressing + a sequence of approximately 48.5 million of character + 251; 1.0.0/1.0.1 will then die here. */ + (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), + 1007 ) + + for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; + + /*-- + Step 3: + The [ss] big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + + The quadrant array provides a way to incrementally + cache sort orderings, as they appear, so as to + make subsequent comparisons in fullGtU() complete + faster. For repetitive blocks this makes a big + difference (but not big enough to be able to avoid + the fallback sorting mechanism, exponential radix sort). + + The precise meaning is: at all times: + + for 0 <= i < nblock and 0 <= j <= nblock + + if block[i] != block[j], + + then the relative values of quadrant[i] and + quadrant[j] are meaningless. + + else { + if quadrant[i] < quadrant[j] + then the string starting at i lexicographically + precedes the string starting at j + + else if quadrant[i] > quadrant[j] + then the string starting at j lexicographically + precedes the string starting at i + + else + the relative ordering of the strings starting + at i and j has not yet been determined. + } + --*/ + bigDone[ss] = True; + + if (i < 255) { + Int32 bbStart = ftab[ss << 8] & CLEARMASK; + Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + Int32 shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + Int32 a2update = ptr[bbStart + j]; + UInt16 qVal = (UInt16)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); + } + + } + + if (verb >= 4) + VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", + nblock, numQSorted, nblock - numQSorted ); +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)arr2) [0 .. nblock-1] holds block + arr1 exists for [0 .. nblock-1] + + Post: + ((UChar*)arr2) [0 .. nblock-1] holds block + All other areas of block destroyed + ftab [ 0 .. 65536 ] destroyed + arr1 [0 .. nblock-1] holds sorted order +*/ +void BZ2_blockSort ( EState* s ) +{ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt32* ftab = s->ftab; + Int32 nblock = s->nblock; + Int32 verb = s->verbosity; + Int32 wfact = s->workFactor; + UInt16* quadrant; + Int32 budget; + Int32 budgetInit; + Int32 i; + + if (nblock < 10000) { + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } else { + /* Calculate the location for quadrant, remembering to get + the alignment right. Assumes that &(block[0]) is at least + 2-byte aligned -- this should be ok since block is really + the first section of arr2. + */ + i = nblock+BZ_N_OVERSHOOT; + if (i & 1) i++; + quadrant = (UInt16*)(&(block[i])); + + /* (wfact-1) / 3 puts the default-factor-30 + transition point at very roughly the same place as + with v0.1 and v0.9.0. + Not that it particularly matters any more, since the + resulting compressed stream is now the same regardless + of whether or not we use the main sort or fallback sort. + */ + if (wfact < 1 ) wfact = 1; + if (wfact > 100) wfact = 100; + budgetInit = nblock * ((wfact-1) / 3); + budget = budgetInit; + + mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); + if (verb >= 3) + VPrintf3 ( " %d work, %d block, ratio %5.2f\n", + budgetInit - budget, + nblock, + (float)(budgetInit - budget) / + (float)(nblock==0 ? 1 : nblock) ); + if (budget < 0) { + if (verb >= 2) + VPrintf0 ( " too repetitive; using fallback" + " sorting algorithm\n" ); + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } + } + + s->origPtr = -1; + for (i = 0; i < s->nblock; i++) + if (ptr[i] == 0) + { s->origPtr = i; break; }; + + AssertH( s->origPtr != -1, 1003 ); +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/include/bzlib.c b/src/include/bzlib.c new file mode 100644 index 0000000..e6fc6db --- /dev/null +++ b/src/include/bzlib.c @@ -0,0 +1,1587 @@ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + +/* 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 "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------------*/ +#ifndef BZ_NO_STDIO +void BZ2_bz__AssertH__fail ( int errcode ) +{ + fprintf(stderr, + "\n\nbzip2/libbzip2: internal error number %d.\n" + "This is a bug in bzip2/libbzip2, %s.\n" + "Please report it to me at: jseward@bzip.org. If this happened\n" + "when you were using some program which uses libbzip2 as a\n" + "component, you should also report this bug to the author(s)\n" + "of that program. Please make an effort to report this bug;\n" + "timely and accurate bug reports eventually lead to higher\n" + "quality software. Thanks. Julian Seward, 15 February 2005.\n\n", + errcode, + BZ2_bzlibVersion() + ); + + if (errcode == 1007) { + fprintf(stderr, + "\n*** A special note about internal error number 1007 ***\n" + "\n" + "Experience suggests that a common cause of i.e. 1007\n" + "is unreliable memory or other hardware. The 1007 assertion\n" + "just happens to cross-check the results of huge numbers of\n" + "memory reads/writes, and so acts (unintendedly) as a stress\n" + "test of your memory system.\n" + "\n" + "I suggest the following: try compressing the file again,\n" + "possibly monitoring progress in detail with the -vv flag.\n" + "\n" + "* If the error cannot be reproduced, and/or happens at different\n" + " points in compression, you may have a flaky memory system.\n" + " Try a memory-test program. I have used Memtest86\n" + " (www.memtest86.com). At the time of writing it is free (GPLd).\n" + " Memtest86 tests memory much more thorougly than your BIOSs\n" + " power-on test, and may find failures that the BIOS doesn't.\n" + "\n" + "* If the error can be repeatably reproduced, this is a bug in\n" + " bzip2, and I would very much like to hear about it. Please\n" + " let me know, and, ideally, save a copy of the file causing the\n" + " problem -- without which I will be unable to investigate it.\n" + "\n" + ); + } + + exit(3); +} +#endif + + +/*---------------------------------------------------*/ +static +int bz_config_ok ( void ) +{ + if (sizeof(int) != 4) return 0; + if (sizeof(short) != 2) return 0; + if (sizeof(char) != 1) return 0; + return 1; +} + + +/*---------------------------------------------------*/ +static +void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) +{ + void* v = malloc ( items * size ); + return v; +} + +static +void default_bzfree ( void* opaque, void* addr ) +{ + if (addr != NULL) free ( addr ); +} + + +/*---------------------------------------------------*/ +static +void prepare_new_block ( EState* s ) +{ + Int32 i; + s->nblock = 0; + s->numZ = 0; + s->state_out_pos = 0; + BZ_INITIALISE_CRC ( s->blockCRC ); + for (i = 0; i < 256; i++) s->inUse[i] = False; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +void init_RL ( EState* s ) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +Bool isempty_RL ( EState* s ) +{ + if (s->state_in_ch < 256 && s->state_in_len > 0) + return False; else + return True; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressInit) + ( bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 n; + EState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL || + blockSize100k < 1 || blockSize100k > 9 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(EState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + + s->arr1 = NULL; + s->arr2 = NULL; + s->ftab = NULL; + + n = 100000 * blockSize100k; + s->arr1 = BZALLOC( n * sizeof(UInt32) ); + s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); + s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); + + if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + if (s != NULL) BZFREE(s); + return BZ_MEM_ERROR; + } + + s->blockNo = 0; + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->combinedCRC = 0; + s->blockSize100k = blockSize100k; + s->nblockMAX = 100000 * blockSize100k - 19; + s->verbosity = verbosity; + s->workFactor = workFactor; + + s->block = (UChar*)s->arr2; + s->mtfv = (UInt16*)s->arr1; + s->zbits = NULL; + s->ptr = (UInt32*)s->arr1; + + strm->state = s; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + init_RL ( s ); + prepare_new_block ( s ); + return BZ_OK; +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block ( EState* s ) +{ + Int32 i; + UChar ch = (UChar)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC( s->blockCRC, ch ); + } + s->inUse[s->state_in_ch] = True; + switch (s->state_in_len) { + case 1: + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 2: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 3: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len-4] = True; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = ((UChar)(s->state_in_len-4)); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL ( EState* s ) +{ + if (s->state_in_ch < 256) add_pair_to_block ( s ); + init_RL ( s ); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ +{ \ + UInt32 zchh = (UInt32)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && \ + zs->state_in_len == 1) { \ + UChar ch = (UChar)(zs->state_in_ch); \ + BZ_UPDATE_CRC( zs->blockCRC, ch ); \ + zs->inUse[zs->state_in_ch] = True; \ + zs->block[zs->nblock] = (UChar)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || \ + zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block ( zs ); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +Bool copy_input_until_stop ( EState* s ) +{ + Bool progress_in = False; + + if (s->mode == BZ_M_RUNNING) { + + /*-- fast track the common case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + } + + } else { + + /*-- general, uncommon case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- flush/finish end? --*/ + if (s->avail_in_expect == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + s->avail_in_expect--; + } + } + return progress_in; +} + + +/*---------------------------------------------------*/ +static +Bool copy_output_until_stop ( EState* s ) +{ + Bool progress_out = False; + + while (True) { + + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->numZ) break; + + progress_out = True; + *(s->strm->next_out) = s->zbits[s->state_out_pos]; + s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + return progress_out; +} + + +/*---------------------------------------------------*/ +static +Bool handle_compress ( bz_stream* strm ) +{ + Bool progress_in = False; + Bool progress_out = False; + EState* s = strm->state; + + while (True) { + + if (s->state == BZ_S_OUTPUT) { + progress_out |= copy_output_until_stop ( s ); + if (s->state_out_pos < s->numZ) break; + if (s->mode == BZ_M_FINISHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + prepare_new_block ( s ); + s->state = BZ_S_INPUT; + if (s->mode == BZ_M_FLUSHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + } + + if (s->state == BZ_S_INPUT) { + progress_in |= copy_input_until_stop ( s ); + if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + flush_RL ( s ); + BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); + s->state = BZ_S_OUTPUT; + } + else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock ( s, False ); + s->state = BZ_S_OUTPUT; + } + else + if (s->strm->avail_in == 0) { + break; + } + } + + } + + return progress_in || progress_out; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) +{ + Bool progress; + EState* 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; + + preswitch: + switch (s->mode) { + + case BZ_M_IDLE: + return BZ_SEQUENCE_ERROR; + + case BZ_M_RUNNING: + if (action == BZ_RUN) { + progress = handle_compress ( strm ); + return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; + } + else + if (action == BZ_FLUSH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto preswitch; + } + else + if (action == BZ_FINISH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto preswitch; + } + else + return BZ_PARAM_ERROR; + + case BZ_M_FLUSHING: + if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; + + case BZ_M_FINISHING: + if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (!progress) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FINISH_OK; + s->mode = BZ_M_IDLE; + return BZ_STREAM_END; + } + return BZ_OK; /*--not reached--*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) +{ + EState* 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->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + BZFREE(strm->state); + + strm->state = NULL; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/*--- 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; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool 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 False; + 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 False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + 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--; + } + } + /* Only caused by corrupt data stream? */ + if (c_nblock_used > s_save_nblockPP) + return True; + + /* 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 */ + } + return False; +} + + + +/*---------------------------------------------------*/ +__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; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool 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 False; + 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 False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + 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 False; + 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 False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + 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 ) +{ + Bool corrupt; + 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) + corrupt = unRLE_obuf_to_output_SMALL ( s ); else + corrupt = unRLE_obuf_to_output_FAST ( s ); + if (corrupt) return BZ_DATA_ERROR; + if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { + BZ_FINALISE_CRC ( s->calculatedBlockCRC ); + if (s->verbosity >= 3) + VPrintf2 ( " {0x%08x, 0x%08x}", 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%08x, computed = 0x%08x", + 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; /*NOTREACHED*/ +} + + +/*---------------------------------------------------*/ +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; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ +/*--- File I/O stuff ---*/ +/*---------------------------------------------------*/ + +#define BZ_SETERR(eee) \ +{ \ + if (bzerror != NULL) *bzerror = eee; \ + if (bzf != NULL) bzf->lastErr = eee; \ +} + +typedef + struct { + FILE* handle; + Char buf[BZ_MAX_UNUSED]; + Int32 bufN; + Bool writing; + bz_stream strm; + Int32 lastErr; + Bool initialisedOk; + } + bzFile; + + +/*---------------------------------------------*/ +static Bool myfeof ( FILE* f ) +{ + Int32 c = fgetc ( f ); + if (c == EOF) return True; + ungetc ( c, f ); + return False; +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzWriteOpen) + ( int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 ret; + bzFile* bzf = NULL; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (blockSize100k < 1 || blockSize100k > 9) || + (workFactor < 0 || workFactor > 250) || + (verbosity < 0 || verbosity > 4)) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + bzf->initialisedOk = False; + bzf->bufN = 0; + bzf->handle = f; + bzf->writing = True; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + if (workFactor == 0) workFactor = 30; + ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = 0; + bzf->initialisedOk = True; + return bzf; +} + + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWrite) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return; }; + + bzf->strm.avail_in = len; + bzf->strm.next_in = buf; + + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); + if (ret != BZ_RUN_OK) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (bzf->strm.avail_in == 0) + { BZ_SETERR(BZ_OK); return; }; + } +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWriteClose) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out ) +{ + BZ2_bzWriteClose64 ( bzerror, b, abandon, + nbytes_in, NULL, nbytes_out, NULL ); +} + + +void BZ_API(BZ2_bzWriteClose64) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; + if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; + if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; + if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; + + if ((!abandon) && bzf->lastErr == BZ_OK) { + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (ret == BZ_STREAM_END) break; + } + } + + if ( !abandon && !ferror ( bzf->handle ) ) { + fflush ( bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (nbytes_in_lo32 != NULL) + *nbytes_in_lo32 = bzf->strm.total_in_lo32; + if (nbytes_in_hi32 != NULL) + *nbytes_in_hi32 = bzf->strm.total_in_hi32; + if (nbytes_out_lo32 != NULL) + *nbytes_out_lo32 = bzf->strm.total_out_lo32; + if (nbytes_out_hi32 != NULL) + *nbytes_out_hi32 = bzf->strm.total_out_hi32; + + BZ_SETERR(BZ_OK); + BZ2_bzCompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzReadOpen) + ( int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused ) +{ + bzFile* bzf = NULL; + int ret; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (small != 0 && small != 1) || + (verbosity < 0 || verbosity > 4) || + (unused == NULL && nUnused != 0) || + (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + + bzf->initialisedOk = False; + bzf->handle = f; + bzf->bufN = 0; + bzf->writing = False; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + while (nUnused > 0) { + bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; + unused = ((void*)( 1 + ((UChar*)(unused)) )); + nUnused--; + } + + ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + + bzf->initialisedOk = True; + return bzf; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) +{ + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + + if (bzf->initialisedOk) + (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzRead) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return 0; }; + + bzf->strm.avail_out = len; + bzf->strm.next_out = buf; + + while (True) { + + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + + if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { + n = fread ( bzf->buf, sizeof(UChar), + BZ_MAX_UNUSED, bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + bzf->bufN = n; + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + } + + ret = BZ2_bzDecompress ( &(bzf->strm) ); + + if (ret != BZ_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return 0; }; + + if (ret == BZ_OK && myfeof(bzf->handle) && + bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) + { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; + + if (ret == BZ_STREAM_END) + { BZ_SETERR(BZ_STREAM_END); + return len - bzf->strm.avail_out; }; + if (bzf->strm.avail_out == 0) + { BZ_SETERR(BZ_OK); return len; }; + + } + + return 0; /*not reached*/ +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadGetUnused) + ( int* bzerror, + BZFILE* b, + void** unused, + int* nUnused ) +{ + bzFile* bzf = (bzFile*)b; + if (bzf == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (bzf->lastErr != BZ_STREAM_END) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (unused == NULL || nUnused == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + + BZ_SETERR(BZ_OK); + *nUnused = bzf->strm.avail_in; + *unused = bzf->strm.next_in; +} +#endif + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffCompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + blockSize100k < 1 || blockSize100k > 9 || + verbosity < 0 || verbosity > 4 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzCompressInit ( &strm, blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress ( &strm, BZ_FINISH ); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd ( &strm ); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffDecompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + (small != 0 && small != 1) || + verbosity < 0 || verbosity > 4) + return BZ_PARAM_ERROR; + + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzDecompress ( &strm ); + if (ret == BZ_OK) goto output_overflow_or_eof; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzDecompressEnd ( &strm ); + return BZ_OK; + + output_overflow_or_eof: + if (strm.avail_out > 0) { + BZ2_bzDecompressEnd ( &strm ); + return BZ_UNEXPECTED_EOF; + } else { + BZ2_bzDecompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + }; + + errhandler: + BZ2_bzDecompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +/*-- + return version like "0.9.5d, 4-Sept-1999". +--*/ +const char * BZ_API(BZ2_bzlibVersion)(void) +{ + return BZ_VERSION; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ + +#ifdef WINCE +#ifndef setmode +#define setmode _setmode +#endif +#ifndef O_BINARY +#define O_BINARY _O_BINARY +#endif +static +FILE * fdopen(int fd, const char *mode) +{ + wchar_t wMode[10]; + MultiByteToWideChar(CP_ACP, 0, mode, -1, wMode, 10); + return _wfdopen((void*)fd, wMode); +} +#endif + +#if (defined(_WIN32) || defined(OS2) || defined(MSDOS)) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif +static +BZFILE * bzopen_or_bzdopen + ( const char *path, /* no use when bzdopen */ + int fd, /* no use when bzdopen */ + const char *mode, + int open_mode) /* bzopen: 0, bzdopen:1 */ +{ + int bzerr; + char unused[BZ_MAX_UNUSED]; + int blockSize100k = 9; + int writing = 0; + char mode2[10] = ""; + FILE *fp = NULL; + BZFILE *bzfp = NULL; + int verbosity = 0; + int workFactor = 30; + int smallMode = 0; + int nUnused = 0; + + if (mode == NULL) return NULL; + while (*mode) { + switch (*mode) { + case 'r': + writing = 0; break; + case 'w': + writing = 1; break; + case 's': + smallMode = 1; break; + default: + if (isdigit((int)(*mode))) { + blockSize100k = *mode-BZ_HDR_0; + } + } + mode++; + } + strcat(mode2, writing ? "w" : "r" ); + strcat(mode2,"b"); /* binary mode */ + + if (open_mode==0) { + if (path==NULL || strcmp(path,"")==0) { + fp = (writing ? stdout : stdin); + SET_BINARY_MODE(fp); + } else { + fp = fopen(path,mode2); + } + } else { +#ifdef BZ_STRICT_ANSI + fp = NULL; +#else + fp = fdopen(fd,mode2); +#endif + } + if (fp == NULL) return NULL; + + if (writing) { + /* Guard against total chaos and anarchy -- JRS */ + if (blockSize100k < 1) blockSize100k = 1; + if (blockSize100k > 9) blockSize100k = 9; + bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, + verbosity,workFactor); + } else { + bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, + unused,nUnused); + } + if (bzfp == NULL) { + if (fp != stdin && fp != stdout) fclose(fp); + return NULL; + } + return bzfp; +} + + +/*---------------------------------------------------*/ +/*-- + open file for read or write. + ex) bzopen("file","w9") + case path="" or NULL => use stdin or stdout. +--*/ +BZFILE * BZ_API(BZ2_bzopen) + ( const char *path, + const char *mode ) +{ + return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); +} + + +/*---------------------------------------------------*/ +BZFILE * BZ_API(BZ2_bzdopen) + ( int fd, + const char *mode ) +{ + return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) +{ + int bzerr, nread; + if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; + nread = BZ2_bzRead(&bzerr,b,buf,len); + if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { + return nread; + } else { + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) +{ + int bzerr; + + BZ2_bzWrite(&bzerr,b,buf,len); + if(bzerr == BZ_OK){ + return len; + }else{ + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzflush) (BZFILE *b) +{ + /* do nothing now... */ + return 0; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzclose) (BZFILE* b) +{ + int bzerr; + FILE *fp; + + if (b==NULL) {return;} + fp = ((bzFile *)b)->handle; + if(((bzFile*)b)->writing){ + BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); + if(bzerr != BZ_OK){ + BZ2_bzWriteClose(NULL,b,1,NULL,NULL); + } + }else{ + BZ2_bzReadClose(&bzerr,b); + } + if(fp!=stdin && fp!=stdout){ + fclose(fp); + } +} + + +/*---------------------------------------------------*/ +/*-- + return last error code +--*/ +static const char *bzerrorstrings[] = { + "OK" + ,"SEQUENCE_ERROR" + ,"PARAM_ERROR" + ,"MEM_ERROR" + ,"DATA_ERROR" + ,"DATA_ERROR_MAGIC" + ,"IO_ERROR" + ,"UNEXPECTED_EOF" + ,"OUTBUFF_FULL" + ,"CONFIG_ERROR" + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ +}; + + +const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) +{ + int err = ((bzFile *)b)->lastErr; + + if(err>0) err = 0; + *errnum = err; + return bzerrorstrings[err*-1]; +} +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/include/bzlib.h b/src/include/bzlib.h new file mode 100644 index 0000000..fdb0dbe --- /dev/null +++ b/src/include/bzlib.h @@ -0,0 +1,282 @@ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_H +#define _BZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef + struct { + char *next_in; + unsigned int avail_in; + unsigned int total_in_lo32; + unsigned int total_in_hi32; + + char *next_out; + unsigned int avail_out; + unsigned int total_out_lo32; + unsigned int total_out_hi32; + + void *state; + + void *(*bzalloc)(void *,int,int); + void (*bzfree)(void *,void *); + void *opaque; + } + bz_stream; + + +#ifndef BZ_IMPORT +#define BZ_EXPORT +#endif + +#ifndef BZ_NO_STDIO +/* Need a definitition for FILE */ +#include +#endif + +#ifdef _WIN32 +# include +# ifdef small + /* windows.h define small to char */ +# undef small +# endif +# ifdef BZ_EXPORT +# define BZ_API(func) WINAPI func +# define BZ_EXTERN extern +# else + /* import windows dll dynamically */ +# define BZ_API(func) (WINAPI * func) +# define BZ_EXTERN +# endif +#else +# define BZ_API(func) func +# define BZ_EXTERN extern +#endif + + +/*-- Core (low-level) library functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( + bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompress) ( + bz_stream* strm, + int action + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( + bz_stream *strm, + int verbosity, + int small + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( + bz_stream *strm + ); + + + +/*-- High(er) level library functions --*/ + +#ifndef BZ_NO_STDIO +#define BZ_MAX_UNUSED 5000 + +typedef void BZFILE; + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( + int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( + int* bzerror, + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( + int* bzerror, + BZFILE* b, + void** unused, + int* nUnused + ); + +BZ_EXTERN int BZ_API(BZ2_bzRead) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( + int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN void BZ_API(BZ2_bzWrite) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 + ); +#endif + + +/*-- Utility functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity + ); + + +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ + +BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( + void + ); + +#ifndef BZ_NO_STDIO +BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( + const char *path, + const char *mode + ); + +BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( + int fd, + const char *mode + ); + +BZ_EXTERN int BZ_API(BZ2_bzread) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzwrite) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzflush) ( + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzclose) ( + BZFILE* b + ); + +BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( + BZFILE *b, + int *errnum + ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/include/bzlib_private.h b/src/include/bzlib_private.h new file mode 100644 index 0000000..d0a0554 --- /dev/null +++ b/src/include/bzlib_private.h @@ -0,0 +1,503 @@ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_PRIVATE_H +#define _BZLIB_PRIVATE_H + +#include + +#ifndef BZ_NO_STDIO +#include +#include +#include +#endif + +#include "bzlib.h" + + + +/*-- General stuff. --*/ + +#define BZ_VERSION "1.0.4, 20-Dec-2006" + +typedef char Char; +typedef unsigned char Bool; +typedef unsigned char UChar; +typedef int Int32; +typedef unsigned int UInt32; +typedef short Int16; +typedef unsigned short UInt16; + +#define True ((Bool)1) +#define False ((Bool)0) + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef BZ_NO_STDIO + +extern void BZ2_bz__AssertH__fail ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } + +#if BZ_DEBUG +#define AssertD(cond,msg) \ + { if (!(cond)) { \ + fprintf ( stderr, \ + "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ + exit(1); \ + }} +#else +#define AssertD(cond,msg) /* */ +#endif + +#define VPrintf0(zf) \ + fprintf(stderr,zf) +#define VPrintf1(zf,za1) \ + fprintf(stderr,zf,za1) +#define VPrintf2(zf,za1,za2) \ + fprintf(stderr,zf,za1,za2) +#define VPrintf3(zf,za1,za2,za3) \ + fprintf(stderr,zf,za1,za2,za3) +#define VPrintf4(zf,za1,za2,za3,za4) \ + fprintf(stderr,zf,za1,za2,za3,za4) +#define VPrintf5(zf,za1,za2,za3,za4,za5) \ + fprintf(stderr,zf,za1,za2,za3,za4,za5) + +#else + +extern void bz_internal_error ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) bz_internal_error ( errcode ); } +#define AssertD(cond,msg) do { } while (0) +#define VPrintf0(zf) do { } while (0) +#define VPrintf1(zf,za1) do { } while (0) +#define VPrintf2(zf,za1,za2) do { } while (0) +#define VPrintf3(zf,za1,za2,za3) do { } while (0) +#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) +#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) + +#endif + + +#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) +#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + + +/*-- Stuff for randomising repetitive blocks. --*/ + +extern Int32 BZ2_rNums[512]; + +#define BZ_RAND_DECLS \ + Int32 rNToGo; \ + Int32 rTPos \ + +#define BZ_RAND_INIT_MASK \ + s->rNToGo = 0; \ + s->rTPos = 0 \ + +#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) + +#define BZ_RAND_UPD_MASK \ + if (s->rNToGo == 0) { \ + s->rNToGo = BZ2_rNums[s->rTPos]; \ + s->rTPos++; \ + if (s->rTPos == 512) s->rTPos = 0; \ + } \ + s->rNToGo--; + + + +/*-- Stuff for doing CRCs. --*/ + +extern UInt32 BZ2_crc32Table[256]; + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + BZ2_crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + Int32 mode; + Int32 state; + + /* remembers avail_in when flush/finish requested */ + UInt32 avail_in_expect; + + /* for doing the block sorting */ + UInt32* arr1; + UInt32* arr2; + UInt32* ftab; + Int32 origPtr; + + /* aliases for arr1 and arr2 */ + UInt32* ptr; + UChar* block; + UInt16* mtfv; + UChar* zbits; + + /* for deciding when to use the fallback sorting algorithm */ + Int32 workFactor; + + /* run-length-encoding of the input */ + UInt32 state_in_ch; + Int32 state_in_len; + BZ_RAND_DECLS; + + /* input and output limits and current posns */ + Int32 nblock; + Int32 nblockMAX; + Int32 numZ; + Int32 state_out_pos; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + UChar unseqToSeq[256]; + + /* the buffer for bit stream creation */ + UInt32 bsBuff; + Int32 bsLive; + + /* block and combined CRCs */ + UInt32 blockCRC; + UInt32 combinedCRC; + + /* misc administratium */ + Int32 verbosity; + Int32 blockNo; + Int32 blockSize100k; + + /* stuff for coding the MTF values */ + Int32 nMTF; + Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + /* second dimension: only 3 needed; 4 makes index calculations faster */ + UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; + + } + EState; + + + +/*-- externs for compression. --*/ + +extern void +BZ2_blockSort ( EState* ); + +extern void +BZ2_compressBlock ( EState*, Bool ); + +extern void +BZ2_bsInitWrite ( EState* ); + +extern void +BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); + +extern void +BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); + + + +/*-- states for decompression. --*/ + +#define BZ_X_IDLE 1 +#define BZ_X_OUTPUT 2 + +#define BZ_X_MAGIC_1 10 +#define BZ_X_MAGIC_2 11 +#define BZ_X_MAGIC_3 12 +#define BZ_X_MAGIC_4 13 +#define BZ_X_BLKHDR_1 14 +#define BZ_X_BLKHDR_2 15 +#define BZ_X_BLKHDR_3 16 +#define BZ_X_BLKHDR_4 17 +#define BZ_X_BLKHDR_5 18 +#define BZ_X_BLKHDR_6 19 +#define BZ_X_BCRC_1 20 +#define BZ_X_BCRC_2 21 +#define BZ_X_BCRC_3 22 +#define BZ_X_BCRC_4 23 +#define BZ_X_RANDBIT 24 +#define BZ_X_ORIGPTR_1 25 +#define BZ_X_ORIGPTR_2 26 +#define BZ_X_ORIGPTR_3 27 +#define BZ_X_MAPPING_1 28 +#define BZ_X_MAPPING_2 29 +#define BZ_X_SELECTOR_1 30 +#define BZ_X_SELECTOR_2 31 +#define BZ_X_SELECTOR_3 32 +#define BZ_X_CODING_1 33 +#define BZ_X_CODING_2 34 +#define BZ_X_CODING_3 35 +#define BZ_X_MTF_1 36 +#define BZ_X_MTF_2 37 +#define BZ_X_MTF_3 38 +#define BZ_X_MTF_4 39 +#define BZ_X_MTF_5 40 +#define BZ_X_MTF_6 41 +#define BZ_X_ENDHDR_2 42 +#define BZ_X_ENDHDR_3 43 +#define BZ_X_ENDHDR_4 44 +#define BZ_X_ENDHDR_5 45 +#define BZ_X_ENDHDR_6 46 +#define BZ_X_CCRC_1 47 +#define BZ_X_CCRC_2 48 +#define BZ_X_CCRC_3 49 +#define BZ_X_CCRC_4 50 + + + +/*-- Constants for the fast MTF decoder. --*/ + +#define MTFA_SIZE 4096 +#define MTFL_SIZE 16 + + + +/*-- Structure holding all the decompression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* state indicator for this stream */ + Int32 state; + + /* for doing the final run-length decoding */ + UChar state_out_ch; + Int32 state_out_len; + Bool blockRandomised; + BZ_RAND_DECLS; + + /* the buffer for bit stream reading */ + UInt32 bsBuff; + Int32 bsLive; + + /* misc administratium */ + Int32 blockSize100k; + Bool smallDecompress; + Int32 currBlockNo; + Int32 verbosity; + + /* for undoing the Burrows-Wheeler transform */ + Int32 origPtr; + UInt32 tPos; + Int32 k0; + Int32 unzftab[256]; + Int32 nblock_used; + Int32 cftab[257]; + Int32 cftabCopy[257]; + + /* for undoing the Burrows-Wheeler transform (FAST) */ + UInt32 *tt; + + /* for undoing the Burrows-Wheeler transform (SMALL) */ + UInt16 *ll16; + UChar *ll4; + + /* stored and calculated CRCs */ + UInt32 storedBlockCRC; + UInt32 storedCombinedCRC; + UInt32 calculatedBlockCRC; + UInt32 calculatedCombinedCRC; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + Bool inUse16[16]; + UChar seqToUnseq[256]; + + /* for decoding the MTF values */ + UChar mtfa [MTFA_SIZE]; + Int32 mtfbase[256 / MTFL_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 minLens[BZ_N_GROUPS]; + + /* save area for scalars in the main decompress code */ + Int32 save_i; + Int32 save_j; + Int32 save_t; + Int32 save_alphaSize; + Int32 save_nGroups; + Int32 save_nSelectors; + Int32 save_EOB; + Int32 save_groupNo; + Int32 save_groupPos; + Int32 save_nextSym; + Int32 save_nblockMAX; + Int32 save_nblock; + Int32 save_es; + Int32 save_N; + Int32 save_curr; + Int32 save_zt; + Int32 save_zn; + Int32 save_zvec; + Int32 save_zj; + Int32 save_gSel; + Int32 save_gMinlen; + Int32* save_gLimit; + Int32* save_gBase; + Int32* save_gPerm; + + } + DState; + + + +/*-- Macros for decompression. --*/ + +#define BZ_GET_FAST(cccc) \ + s->tPos = s->tt[s->tPos]; \ + cccc = (UChar)(s->tPos & 0xff); \ + s->tPos >>= 8; + +#define BZ_GET_FAST_C(cccc) \ + c_tPos = c_tt[c_tPos]; \ + cccc = (UChar)(c_tPos & 0xff); \ + c_tPos >>= 8; + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + +#define GET_LL4(i) \ + ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) + +#define SET_LL(i,n) \ + { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + +#define GET_LL(i) \ + (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) + +#define BZ_GET_SMALL(cccc) \ + cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ + s->tPos = GET_LL(s->tPos); + + +/*-- externs for decompression. --*/ + +extern Int32 +BZ2_indexIntoF ( Int32, Int32* ); + +extern Int32 +BZ2_decompress ( DState* ); + +extern void +BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, + Int32, Int32, Int32 ); + + +#endif + + +/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ + +#ifdef BZ_NO_STDIO +#ifndef NULL +#define NULL 0 +#endif +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/include/compress.c b/src/include/compress.c new file mode 100644 index 0000000..d98d5c0 --- /dev/null +++ b/src/include/compress.c @@ -0,0 +1,672 @@ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- changed setting of nGroups in sendMTFValues() + so as to do a bit better on small files +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +void BZ2_bsInitWrite ( EState* s ) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static +void bsFinishWrite ( EState* s ) +{ + while (s->bsLive > 0) { + s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +#define bsNEEDW(nz) \ +{ \ + while (s->bsLive >= 8) { \ + s->zbits[s->numZ] \ + = (UChar)(s->bsBuff >> 24); \ + s->numZ++; \ + s->bsBuff <<= 8; \ + s->bsLive -= 8; \ + } \ +} + + +/*---------------------------------------------------*/ +static +__inline__ +void bsW ( EState* s, Int32 n, UInt32 v ) +{ + bsNEEDW ( n ); + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} + + +/*---------------------------------------------------*/ +static +void bsPutUInt32 ( EState* s, UInt32 u ) +{ + bsW ( s, 8, (u >> 24) & 0xffL ); + bsW ( s, 8, (u >> 16) & 0xffL ); + bsW ( s, 8, (u >> 8) & 0xffL ); + bsW ( s, 8, u & 0xffL ); +} + + +/*---------------------------------------------------*/ +static +void bsPutUChar ( EState* s, UChar c ) +{ + bsW( s, 8, (UInt32)c ); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e ( EState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->unseqToSeq[i] = s->nInUse; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +static +void generateMTFValues ( EState* s ) +{ + UChar yy[256]; + Int32 i, j; + Int32 zPend; + Int32 wr; + Int32 EOB; + + /* + After sorting (eg, here), + s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, + and + ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] + holds the original block data. + + The first thing to do is generate the MTF values, + and put them in + ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. + Because there are strictly fewer or equal MTF values + than block values, ptr values in this area are overwritten + with MTF values only when they are no longer needed. + + The final compressed bitstream is generated into the + area starting at + (UChar*) (&((UChar*)s->arr2)[s->nblock]) + + These storage aliases are set up in bzCompressInit(), + except for the last one, which is arranged in + compressBlock(). + */ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt16* mtfv = s->mtfv; + + makeMaps_e ( s ); + EOB = s->nInUse+1; + + for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; + + wr = 0; + zPend = 0; + for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; + + for (i = 0; i < s->nblock; i++) { + UChar ll_i; + AssertD ( wr <= i, "generateMTFValues(1)" ); + j = ptr[i]-1; if (j < 0) j += s->nblock; + ll_i = s->unseqToSeq[block[j]]; + AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); + + if (yy[0] == ll_i) { + zPend++; + } else { + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + { + register UChar rtmp; + register UChar* ryy_j; + register UChar rll_i; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + rll_i = ll_i; + while ( rll_i != rtmp ) { + register UChar rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + }; + yy[0] = rtmp; + j = ryy_j - &(yy[0]); + mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; + } + + } + } + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + + mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static +void sendMTFValues ( EState* s ) +{ + Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; + Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; + Int32 nGroups, nBytes; + + /*-- + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + is a global since the decoder also needs it. + + Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + are also globals only used in this proc. + Made global to keep stack frame size small. + --*/ + + + UInt16 cost[BZ_N_GROUPS]; + Int32 fave[BZ_N_GROUPS]; + + UInt16* mtfv = s->mtfv; + + if (s->verbosity >= 3) + VPrintf3( " %d in block, %d after MTF & 1-2 coding, " + "%d+2 syms in use\n", + s->nblock, s->nMTF, s->nInUse ); + + alphaSize = s->nInUse+2; + for (t = 0; t < BZ_N_GROUPS; t++) + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + + /*--- Decide how many coding tables to use ---*/ + AssertH ( s->nMTF > 0, 3001 ); + if (s->nMTF < 200) nGroups = 2; else + if (s->nMTF < 600) nGroups = 3; else + if (s->nMTF < 1200) nGroups = 4; else + if (s->nMTF < 2400) nGroups = 5; else + nGroups = 6; + + /*--- Generate an initial set of coding tables ---*/ + { + Int32 nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs-1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize-1) { + ge++; + aFreq += s->mtfFreq[ge]; + } + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups-nPart) % 2 == 1)) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + if (s->verbosity >= 3) + VPrintf5( " initial group %d, [%d .. %d], " + "has %d syms (%4.1f%%)\n", + nPart, gs, ge, aFreq, + (100.0 * (float)aFreq) / (float)(s->nMTF) ); + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge+1; + remF -= aFreq; + } + } + + /*--- + Iterate up to BZ_N_ITERS times to improve the tables. + ---*/ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + + for (t = 0; t < nGroups; t++) fave[t] = 0; + + for (t = 0; t < nGroups; t++) + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + + /*--- + Set up an auxiliary length table which is used to fast-track + the common case (nGroups == 6). + ---*/ + if (nGroups == 6) { + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (True) { + + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + + /*-- + Calculate the cost of this group as coded + by each of the coding tables. + --*/ + for (t = 0; t < nGroups; t++) cost[t] = 0; + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register UInt32 cost01, cost23, cost45; + register UInt16 icv; + cost01 = cost23 = cost45 = 0; + +# define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; \ + + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); + +# undef BZ_ITER + + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + UInt16 icv = mtfv[i]; + for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; + } + } + + /*-- + Find the coding table which is best for this group, + and record its identity in the selector table. + --*/ + bc = 999999999; bt = -1; + for (t = 0; t < nGroups; t++) + if (cost[t] < bc) { bc = cost[t]; bt = t; }; + totc += bc; + fave[bt]++; + s->selector[nSelectors] = bt; + nSelectors++; + + /*-- + Increment the symbol frequencies for the selected table. + --*/ + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + +# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ + + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); + +# undef BZ_ITUR + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) + s->rfreq[bt][ mtfv[i] ]++; + } + + gs = ge+1; + } + if (s->verbosity >= 3) { + VPrintf2 ( " pass %d: size is %d, grp uses are ", + iter+1, totc/8 ); + for (t = 0; t < nGroups; t++) + VPrintf1 ( "%d ", fave[t] ); + VPrintf0 ( "\n" ); + } + + /*-- + Recompute the tables based on the accumulated frequencies. + --*/ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), + alphaSize, 17 /*20*/ ); + } + + + AssertH( nGroups < 8, 3002 ); + AssertH( nSelectors < 32768 && + nSelectors <= (2 + (900000 / BZ_G_SIZE)), + 3003 ); + + + /*--- Compute MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) pos[i] = i; + for (i = 0; i < nSelectors; i++) { + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while ( ll_i != tmp ) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + }; + pos[0] = tmp; + s->selectorMtf[i] = j; + } + }; + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); + AssertH ( !(minLen < 1), 3005 ); + BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), + minLen, maxLen, alphaSize ); + } + + /*--- Transmit the mapping table. ---*/ + { + Bool inUse16[16]; + for (i = 0; i < 16; i++) { + inUse16[i] = False; + for (j = 0; j < 16; j++) + if (s->inUse[i * 16 + j]) inUse16[i] = True; + } + + nBytes = s->numZ; + for (i = 0; i < 16; i++) + if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) { + if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); + } + + if (s->verbosity >= 3) + VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); + } + + /*--- Now the selectors. ---*/ + nBytes = s->numZ; + bsW ( s, 3, nGroups ); + bsW ( s, 15, nSelectors ); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); + bsW(s,1,0); + } + if (s->verbosity >= 3) + VPrintf1( "selectors %d, ", s->numZ-nBytes ); + + /*--- Now the coding tables. ---*/ + nBytes = s->numZ; + + for (t = 0; t < nGroups; t++) { + Int32 curr = s->len[t][0]; + bsW ( s, 5, curr ); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; + while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; + bsW ( s, 1, 0 ); + } + } + + if (s->verbosity >= 3) + VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); + + /*--- And finally, the block data proper ---*/ + nBytes = s->numZ; + selCtr = 0; + gs = 0; + while (True) { + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + AssertH ( s->selector[selCtr] < nGroups, 3006 ); + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + UInt16 mtfv_i; + UChar* s_len_sel_selCtr + = &(s->len[s->selector[selCtr]][0]); + Int32* s_code_sel_selCtr + = &(s->code[s->selector[selCtr]][0]); + +# define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW ( s, \ + s_len_sel_selCtr[mtfv_i], \ + s_code_sel_selCtr[mtfv_i] ) + + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); + +# undef BZ_ITAH + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + bsW ( s, + s->len [s->selector[selCtr]] [mtfv[i]], + s->code [s->selector[selCtr]] [mtfv[i]] ); + } + } + + + gs = ge+1; + selCtr++; + } + AssertH( selCtr == nSelectors, 3007 ); + + if (s->verbosity >= 3) + VPrintf1( "codes %d\n", s->numZ-nBytes ); +} + + +/*---------------------------------------------------*/ +void BZ2_compressBlock ( EState* s, Bool is_last_block ) +{ + if (s->nblock > 0) { + + BZ_FINALISE_CRC ( s->blockCRC ); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) s->numZ = 0; + + if (s->verbosity >= 2) + VPrintf4( " block %d: crc = 0x%08x, " + "combined CRC = 0x%08x, size = %d\n", + s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); + + BZ2_blockSort ( s ); + } + + s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite ( s ); + bsPutUChar ( s, BZ_HDR_B ); + bsPutUChar ( s, BZ_HDR_Z ); + bsPutUChar ( s, BZ_HDR_h ); + bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); + } + + if (s->nblock > 0) { + + bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); + bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); + bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutUInt32 ( s, s->blockCRC ); + + /*-- + Now a single bit indicating (non-)randomisation. + As of version 0.9.5, we use a better sorting algorithm + which makes randomisation unnecessary. So always set + the randomised bit to 'no'. Of course, the decoder + still needs to be able to handle randomised blocks + so as to maintain backwards compatibility with + older versions of bzip2. + --*/ + bsW(s,1,0); + + bsW ( s, 24, s->origPtr ); + generateMTFValues ( s ); + sendMTFValues ( s ); + } + + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + + bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); + bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); + bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); + bsPutUInt32 ( s, s->combinedCRC ); + if (s->verbosity >= 2) + VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); + bsFinishWrite ( s ); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/include/crctable.c b/src/include/crctable.c new file mode 100644 index 0000000..bc7e2ae --- /dev/null +++ b/src/include/crctable.c @@ -0,0 +1,104 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for doing CRCs ---*/ +/*--- crctable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +UInt32 BZ2_crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, + 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, + 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, + 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, + 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, + 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, + 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, + 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, + 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, + 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, + 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, + 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, + 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, + 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, + 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, + 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, + 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, + 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, + 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, + 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, + 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, + 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, + 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, + 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, + 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, + 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, + 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, + 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, + 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, + 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, + 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, + 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, + 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, + 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, + 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, + 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, + 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, + 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, + 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, + 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, + 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, + 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, + 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, + 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, + 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, + 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, + 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, + 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, + 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, + 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, + 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, + 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, + 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, + 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, + 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, + 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, + 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, + 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, + 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, + 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, + 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, + 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, + 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, + 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L +}; + + +/*-------------------------------------------------------------*/ +/*--- end crctable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/include/decompress.c b/src/include/decompress.c new file mode 100644 index 0000000..124cc8d --- /dev/null +++ b/src/include/decompress.c @@ -0,0 +1,626 @@ + +/*-------------------------------------------------------------*/ +/*--- Decompression machinery ---*/ +/*--- decompress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +static +void makeMaps_d ( DState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->seqToUnseq[s->nInUse] = i; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +#define RETURN(rrr) \ + { retVal = rrr; goto save_state_and_return; }; + +#define GET_BITS(lll,vvv,nnn) \ + case lll: s->state = lll; \ + while (True) { \ + if (s->bsLive >= nnn) { \ + UInt32 v; \ + v = (s->bsBuff >> \ + (s->bsLive-nnn)) & ((1 << nnn)-1); \ + s->bsLive -= nnn; \ + vvv = v; \ + break; \ + } \ + if (s->strm->avail_in == 0) RETURN(BZ_OK); \ + s->bsBuff \ + = (s->bsBuff << 8) | \ + ((UInt32) \ + (*((UChar*)(s->strm->next_in)))); \ + s->bsLive += 8; \ + s->strm->next_in++; \ + s->strm->avail_in--; \ + s->strm->total_in_lo32++; \ + if (s->strm->total_in_lo32 == 0) \ + s->strm->total_in_hi32++; \ + } + +#define GET_UCHAR(lll,uuu) \ + GET_BITS(lll,uuu,8) + +#define GET_BIT(lll,uuu) \ + GET_BITS(lll,uuu,1) + +/*---------------------------------------------------*/ +#define GET_MTF_VAL(label1,label2,lval) \ +{ \ + if (groupPos == 0) { \ + groupNo++; \ + if (groupNo >= nSelectors) \ + RETURN(BZ_DATA_ERROR); \ + groupPos = BZ_G_SIZE; \ + gSel = s->selector[groupNo]; \ + gMinlen = s->minLens[gSel]; \ + gLimit = &(s->limit[gSel][0]); \ + gPerm = &(s->perm[gSel][0]); \ + gBase = &(s->base[gSel][0]); \ + } \ + groupPos--; \ + zn = gMinlen; \ + GET_BITS(label1, zvec, zn); \ + while (1) { \ + if (zn > 20 /* the longest code */) \ + RETURN(BZ_DATA_ERROR); \ + if (zvec <= gLimit[zn]) break; \ + zn++; \ + GET_BIT(label2, zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + if (zvec - gBase[zn] < 0 \ + || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ + RETURN(BZ_DATA_ERROR); \ + lval = gPerm[zvec - gBase[zn]]; \ +} + + +/*---------------------------------------------------*/ +Int32 BZ2_decompress ( DState* s ) +{ + UChar uc; + Int32 retVal; + Int32 minLen, maxLen; + bz_stream* strm = s->strm; + + /* stuff that needs to be saved/restored */ + Int32 i; + Int32 j; + Int32 t; + Int32 alphaSize; + Int32 nGroups; + Int32 nSelectors; + Int32 EOB; + Int32 groupNo; + Int32 groupPos; + Int32 nextSym; + Int32 nblockMAX; + Int32 nblock; + Int32 es; + Int32 N; + Int32 curr; + Int32 zt; + Int32 zn; + Int32 zvec; + Int32 zj; + Int32 gSel; + Int32 gMinlen; + Int32* gLimit; + Int32* gBase; + Int32* gPerm; + + if (s->state == BZ_X_MAGIC_1) { + /*initialise the save area*/ + s->save_i = 0; + s->save_j = 0; + s->save_t = 0; + s->save_alphaSize = 0; + s->save_nGroups = 0; + s->save_nSelectors = 0; + s->save_EOB = 0; + s->save_groupNo = 0; + s->save_groupPos = 0; + s->save_nextSym = 0; + s->save_nblockMAX = 0; + s->save_nblock = 0; + s->save_es = 0; + s->save_N = 0; + s->save_curr = 0; + s->save_zt = 0; + s->save_zn = 0; + s->save_zvec = 0; + s->save_zj = 0; + s->save_gSel = 0; + s->save_gMinlen = 0; + s->save_gLimit = NULL; + s->save_gBase = NULL; + s->save_gPerm = NULL; + } + + /*restore from the save area*/ + i = s->save_i; + j = s->save_j; + t = s->save_t; + alphaSize = s->save_alphaSize; + nGroups = s->save_nGroups; + nSelectors = s->save_nSelectors; + EOB = s->save_EOB; + groupNo = s->save_groupNo; + groupPos = s->save_groupPos; + nextSym = s->save_nextSym; + nblockMAX = s->save_nblockMAX; + nblock = s->save_nblock; + es = s->save_es; + N = s->save_N; + curr = s->save_curr; + zt = s->save_zt; + zn = s->save_zn; + zvec = s->save_zvec; + zj = s->save_zj; + gSel = s->save_gSel; + gMinlen = s->save_gMinlen; + gLimit = s->save_gLimit; + gBase = s->save_gBase; + gPerm = s->save_gPerm; + + retVal = BZ_OK; + + switch (s->state) { + + GET_UCHAR(BZ_X_MAGIC_1, uc); + if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_2, uc); + if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_3, uc) + if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) + if (s->blockSize100k < (BZ_HDR_0 + 1) || + s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); + s->blockSize100k -= BZ_HDR_0; + + if (s->smallDecompress) { + s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); + s->ll4 = BZALLOC( + ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) + ); + if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); + } else { + s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); + if (s->tt == NULL) RETURN(BZ_MEM_ERROR); + } + + GET_UCHAR(BZ_X_BLKHDR_1, uc); + + if (uc == 0x17) goto endhdr_2; + if (uc != 0x31) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_2, uc); + if (uc != 0x41) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_3, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_4, uc); + if (uc != 0x26) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_5, uc); + if (uc != 0x53) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_6, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + + s->currBlockNo++; + if (s->verbosity >= 2) + VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); + + s->storedBlockCRC = 0; + GET_UCHAR(BZ_X_BCRC_1, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_2, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_3, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_4, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + + GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); + + s->origPtr = 0; + GET_UCHAR(BZ_X_ORIGPTR_1, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_2, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_3, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + + if (s->origPtr < 0) + RETURN(BZ_DATA_ERROR); + if (s->origPtr > 10 + 100000*s->blockSize100k) + RETURN(BZ_DATA_ERROR); + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) { + GET_BIT(BZ_X_MAPPING_1, uc); + if (uc == 1) + s->inUse16[i] = True; else + s->inUse16[i] = False; + } + + for (i = 0; i < 256; i++) s->inUse[i] = False; + + for (i = 0; i < 16; i++) + if (s->inUse16[i]) + for (j = 0; j < 16; j++) { + GET_BIT(BZ_X_MAPPING_2, uc); + if (uc == 1) s->inUse[i * 16 + j] = True; + } + makeMaps_d ( s ); + if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); + alphaSize = s->nInUse+2; + + /*--- Now the selectors ---*/ + GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); + if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); + GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); + if (nSelectors < 1) RETURN(BZ_DATA_ERROR); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (True) { + GET_BIT(BZ_X_SELECTOR_3, uc); + if (uc == 0) break; + j++; + if (j >= nGroups) RETURN(BZ_DATA_ERROR); + } + s->selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = s->selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + s->selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + GET_BITS(BZ_X_CODING_1, curr, 5); + for (i = 0; i < alphaSize; i++) { + while (True) { + if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); + GET_BIT(BZ_X_CODING_2, uc); + if (uc == 0) break; + GET_BIT(BZ_X_CODING_3, uc); + if (uc == 0) curr++; else curr--; + } + s->len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + BZ2_hbCreateDecodeTables ( + &(s->limit[t][0]), + &(s->base[t][0]), + &(s->perm[t][0]), + &(s->len[t][0]), + minLen, maxLen, alphaSize + ); + s->minLens[t] = minLen; + } + + /*--- Now the MTF values ---*/ + + EOB = s->nInUse+1; + nblockMAX = 100000 * s->blockSize100k; + groupNo = -1; + groupPos = 0; + + for (i = 0; i <= 255; i++) s->unzftab[i] = 0; + + /*-- MTF init --*/ + { + Int32 ii, jj, kk; + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + /*-- end MTF init --*/ + + nblock = 0; + GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { + + es = -1; + N = 1; + do { + if (nextSym == BZ_RUNA) es = es + (0+1) * N; else + if (nextSym == BZ_RUNB) es = es + (1+1) * N; + N = N * 2; + GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); + } + while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); + + es++; + uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; + s->unzftab[uc] += es; + + if (s->smallDecompress) + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->ll16[nblock] = (UInt16)uc; + nblock++; + es--; + } + else + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->tt[nblock] = (UInt32)uc; + nblock++; + es--; + }; + + continue; + + } else { + + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + + /*-- uc = MTF ( nextSym-1 ) --*/ + { + Int32 ii, jj, kk, pp, lno, off; + UInt32 nn; + nn = (UInt32)(nextSym - 1); + + if (nn < MTFL_SIZE) { + /* avoid general-case expense */ + pp = s->mtfbase[0]; + uc = s->mtfa[pp+nn]; + while (nn > 3) { + Int32 z = pp+nn; + s->mtfa[(z) ] = s->mtfa[(z)-1]; + s->mtfa[(z)-1] = s->mtfa[(z)-2]; + s->mtfa[(z)-2] = s->mtfa[(z)-3]; + s->mtfa[(z)-3] = s->mtfa[(z)-4]; + nn -= 4; + } + while (nn > 0) { + s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; + }; + s->mtfa[pp] = uc; + } else { + /* general case */ + lno = nn / MTFL_SIZE; + off = nn % MTFL_SIZE; + pp = s->mtfbase[lno] + off; + uc = s->mtfa[pp]; + while (pp > s->mtfbase[lno]) { + s->mtfa[pp] = s->mtfa[pp-1]; pp--; + }; + s->mtfbase[lno]++; + while (lno > 0) { + s->mtfbase[lno]--; + s->mtfa[s->mtfbase[lno]] + = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; + lno--; + } + s->mtfbase[0]--; + s->mtfa[s->mtfbase[0]] = uc; + if (s->mtfbase[0] == 0) { + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + } + } + /*-- end uc = MTF ( nextSym-1 ) --*/ + + s->unzftab[s->seqToUnseq[uc]]++; + if (s->smallDecompress) + s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else + s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); + nblock++; + + GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); + continue; + } + } + + /* Now we know what nblock is, we can do a better sanity + check on s->origPtr. + */ + if (s->origPtr < 0 || s->origPtr >= nblock) + RETURN(BZ_DATA_ERROR); + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + s->cftab[0] = 0; + for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; + for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; + for (i = 0; i <= 256; i++) { + if (s->cftab[i] < 0 || s->cftab[i] > nblock) { + /* s->cftab[i] can legitimately be == nblock */ + RETURN(BZ_DATA_ERROR); + } + } + + s->state_out_len = 0; + s->state_out_ch = 0; + BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); + s->state = BZ_X_OUTPUT; + if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); + + if (s->smallDecompress) { + + /*-- Make a copy of cftab, used in generation of T --*/ + for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->ll16[i]); + SET_LL(i, s->cftabCopy[uc]); + s->cftabCopy[uc]++; + } + + /*-- Compute T^(-1) by pointer reversal on T --*/ + i = s->origPtr; + j = GET_LL(i); + do { + Int32 tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != s->origPtr); + + s->tPos = s->origPtr; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_SMALL(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } else { + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->tt[i] & 0xff); + s->tt[s->cftab[uc]] |= (i << 8); + s->cftab[uc]++; + } + + s->tPos = s->tt[s->origPtr] >> 8; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_FAST(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_FAST(s->k0); s->nblock_used++; + } + + } + + RETURN(BZ_OK); + + + + endhdr_2: + + GET_UCHAR(BZ_X_ENDHDR_2, uc); + if (uc != 0x72) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_3, uc); + if (uc != 0x45) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_4, uc); + if (uc != 0x38) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_5, uc); + if (uc != 0x50) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_6, uc); + if (uc != 0x90) RETURN(BZ_DATA_ERROR); + + s->storedCombinedCRC = 0; + GET_UCHAR(BZ_X_CCRC_1, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_2, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_3, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_4, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + + s->state = BZ_X_IDLE; + RETURN(BZ_STREAM_END); + + default: AssertH ( False, 4001 ); + } + + AssertH ( False, 4002 ); + + save_state_and_return: + + s->save_i = i; + s->save_j = j; + s->save_t = t; + s->save_alphaSize = alphaSize; + s->save_nGroups = nGroups; + s->save_nSelectors = nSelectors; + s->save_EOB = EOB; + s->save_groupNo = groupNo; + s->save_groupPos = groupPos; + s->save_nextSym = nextSym; + s->save_nblockMAX = nblockMAX; + s->save_nblock = nblock; + s->save_es = es; + s->save_N = N; + s->save_curr = curr; + s->save_zt = zt; + s->save_zn = zn; + s->save_zvec = zvec; + s->save_zj = zj; + s->save_gSel = gSel; + s->save_gMinlen = gMinlen; + s->save_gLimit = gLimit; + s->save_gBase = gBase; + s->save_gPerm = gPerm; + + return retVal; +} + + +/*-------------------------------------------------------------*/ +/*--- end decompress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/include/huffman.c b/src/include/huffman.c new file mode 100644 index 0000000..be4dc02 --- /dev/null +++ b/src/include/huffman.c @@ -0,0 +1,205 @@ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + Int32 zz, tmp; \ + zz = z; tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + +#define DOWNHEAP(z) \ +{ \ + Int32 zz, yy, tmp; \ + zz = z; tmp = heap[zz]; \ + while (True) { \ + yy = zz << 1; \ + if (yy > nHeap) break; \ + if (yy < nHeap && \ + weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + + +/*---------------------------------------------------*/ +void BZ2_hbMakeCodeLengths ( UChar *len, + Int32 *freq, + Int32 alphaSize, + Int32 maxLen ) +{ + /*-- + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + --*/ + Int32 nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; + Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; + Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (True) { + + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { k = parent[k]; j++; } + len[i-1] = j; + if (j > maxLen) tooLong = True; + } + + if (! tooLong) break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbAssignCodes ( Int32 *code, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) + if (length[i] == n) { code[i] = vec; vec++; }; + vec <<= 1; + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/include/mar.h b/src/include/mar.h new file mode 100644 index 0000000..dc69fa4 --- /dev/null +++ b/src/include/mar.h @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MAR_H__ +#define MAR_H__ + +//#include "mozilla/Assertions.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* We have a MAX_SIGNATURES limit so that an invalid MAR will never + * waste too much of either updater's or signmar's time. + * It is also used at various places internally and will affect memory usage. + * If you want to increase this value above 9 then you need to adjust parsing + * code in tool/mar.c. +*/ +#define MAX_SIGNATURES 8 +#ifdef __cplusplus +static_assert(MAX_SIGNATURES <= 9, "too many signatures"); +#else +//MOZ_STATIC_ASSERT(MAX_SIGNATURES <= 9, "too many signatures"); +#endif + +struct ProductInformationBlock { + const char *MARChannelID; + const char *productVersion; +}; + +/** + * The MAR item data structure. + */ +typedef struct MarItem_ { + struct MarItem_ *next; /* private field */ + uint32_t offset; /* offset into archive */ + uint32_t length; /* length of data in bytes */ + uint32_t flags; /* contains file mode bits */ + char name[1]; /* file path */ +} MarItem; + +#define TABLESIZE 256 + +struct MarFile_ { + FILE *fp; + MarItem *item_table[TABLESIZE]; +}; + +typedef struct MarFile_ MarFile; + +/** + * Signature of callback function passed to mar_enum_items. + * @param mar The MAR file being visited. + * @param item The MAR item being visited. + * @param data The data parameter passed by the caller of mar_enum_items. + * @return A non-zero value to stop enumerating. + */ +typedef int (* MarItemCallback)(MarFile *mar, const MarItem *item, void *data); + +/** + * Open a MAR file for reading. + * @param path Specifies the path to the MAR file to open. This path must + * be compatible with fopen. + * @return NULL if an error occurs. + */ +MarFile *mar_open(const char *path); + +#ifdef XP_WIN +MarFile *mar_wopen(const wchar_t *path); +#endif + +/** + * Close a MAR file that was opened using mar_open. + * @param mar The MarFile object to close. + */ +void mar_close(MarFile *mar); + +/** + * Find an item in the MAR file by name. + * @param mar The MarFile object to query. + * @param item The name of the item to query. + * @return A const reference to a MAR item or NULL if not found. + */ +const MarItem *mar_find_item(MarFile *mar, const char *item); + +/** + * Enumerate all MAR items via callback function. + * @param mar The MAR file to enumerate. + * @param callback The function to call for each MAR item. + * @param data A caller specified value that is passed along to the + * callback function. + * @return 0 if the enumeration ran to completion. Otherwise, any + * non-zero return value from the callback is returned. + */ +int mar_enum_items(MarFile *mar, MarItemCallback callback, void *data); + +/** + * Read from MAR item at given offset up to bufsize bytes. + * @param mar The MAR file to read. + * @param item The MAR item to read. + * @param offset The byte offset relative to the start of the item. + * @param buf A pointer to a buffer to copy the data into. + * @param bufsize The length of the buffer to copy the data into. + * @return The number of bytes written or a negative value if an + * error occurs. + */ +int mar_read(MarFile *mar, const MarItem *item, int offset, char *buf, + int bufsize); + +/** + * Create a MAR file from a set of files. + * @param dest The path to the file to create. This path must be + * compatible with fopen. + * @param numfiles The number of files to store in the archive. + * @param files The list of null-terminated file paths. Each file + * path must be compatible with fopen. + * @param infoBlock The information to store in the product information block. + * @return A non-zero value if an error occurs. + */ +int mar_create(const char *dest, + int numfiles, + char **files, + struct ProductInformationBlock *infoBlock); + +/** + * Extract a MAR file to the current working directory. + * @param path The path to the MAR file to extract. This path must be + * compatible with fopen. + * @return A non-zero value if an error occurs. + */ +int mar_extract(const char *path); + +#define MAR_MAX_CERT_SIZE (16*1024) // Way larger than necessary + +/* Read the entire file (not a MAR file) into a newly-allocated buffer. + * This function does not write to stderr. Instead, the caller should + * write whatever error messages it sees fit. The caller must free the returned + * buffer using free(). + * + * @param filePath The path to the file that should be read. + * @param maxSize The maximum valid file size. + * @param data On success, *data will point to a newly-allocated buffer + * with the file's contents in it. + * @param size On success, *size will be the size of the created buffer. + * + * @return 0 on success, -1 on error + */ +int mar_read_entire_file(const char * filePath, + uint32_t maxSize, + /*out*/ const uint8_t * *data, + /*out*/ uint32_t *size); + +/** + * Verifies a MAR file by verifying each signature with the corresponding + * certificate. That is, the first signature will be verified using the first + * certificate given, the second signature will be verified using the second + * certificate given, etc. The signature count must exactly match the number of + * certificates given, and all signature verifications must succeed. + * We do not check that the certificate was issued by any trusted authority. + * We assume it to be self-signed. We do not check whether the certificate + * is valid for this usage. + * + * @param mar The already opened MAR file. + * @param certData Pointer to the first element in an array of certificate + * file data. + * @param certDataSizes Pointer to the first element in an array for size of + * the cert data. + * @param certCount The number of elements in certData and certDataSizes + * @return 0 on success + * a negative number if there was an error + * a positive number if the signature does not verify + */ +int mar_verify_signatures(MarFile *mar, + const uint8_t * const *certData, + const uint32_t *certDataSizes, + uint32_t certCount); + +/** + * Reads the product info block from the MAR file's additional block section. + * The caller is responsible for freeing the fields in infoBlock + * if the return is successful. + * + * @param infoBlock Out parameter for where to store the result to + * @return 0 on success, -1 on failure +*/ +int +mar_read_product_info_block(MarFile *mar, + struct ProductInformationBlock *infoBlock); + +#ifdef __cplusplus +} +#endif + +#endif /* MAR_H__ */ diff --git a/src/include/mar_private.h b/src/include/mar_private.h new file mode 100644 index 0000000..4052648 --- /dev/null +++ b/src/include/mar_private.h @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MAR_PRIVATE_H__ +#define MAR_PRIVATE_H__ + +#include "limits.h" +//#include "mozilla/Assertions.h" +#include + +#define BLOCKSIZE 4096 +#define ROUND_UP(n, incr) (((n) / (incr) + 1) * (incr)) + +#define MAR_ID "MAR1" +#define MAR_ID_SIZE 4 + +/* The signature block comes directly after the header block + which is 16 bytes */ +#define SIGNATURE_BLOCK_OFFSET 16 + +/* Make sure the file is less than 500MB. We do this to protect against + invalid MAR files. */ +#define MAX_SIZE_OF_MAR_FILE ((int64_t)524288000) + +/* Existing code makes assumptions that the file size is + smaller than LONG_MAX. */ +/*MOZ_STATIC_ASSERT(MAX_SIZE_OF_MAR_FILE < ((int64_t)LONG_MAX), + "max mar file size is too big");*/ + +/* We store at most the size up to the signature block + 4 + bytes per BLOCKSIZE bytes */ +/*MOZ_STATIC_ASSERT(sizeof(BLOCKSIZE) < \ + (SIGNATURE_BLOCK_OFFSET + sizeof(uint32_t)), + "BLOCKSIZE is too big");*/ + +/* The maximum size of any signature supported by current and future + implementations of the signmar program. */ +#define MAX_SIGNATURE_LENGTH 2048 + +/* Each additional block has a unique ID. + The product information block has an ID of 1. */ +#define PRODUCT_INFO_BLOCK_ID 1 + +#define MAR_ITEM_SIZE(namelen) (3*sizeof(uint32_t) + (namelen) + 1) + +/* Product Information Block (PIB) constants */ +#define PIB_MAX_MAR_CHANNEL_ID_SIZE 63 +#define PIB_MAX_PRODUCT_VERSION_SIZE 31 + +/* The mar program is compiled as a host bin so we don't have access to NSPR at + runtime. For that reason we use ntohl, htonl, and define HOST_TO_NETWORK64 + instead of the NSPR equivalents. */ +#ifdef XP_WIN +#include +#define ftello _ftelli64 +#define fseeko _fseeki64 +#else +#define _FILE_OFFSET_BITS 64 +#include +#include +#endif + +#include + +#define HOST_TO_NETWORK64(x) ( \ + ((((uint64_t) x) & 0xFF) << 56) | \ + ((((uint64_t) x) >> 8) & 0xFF) << 48) | \ + (((((uint64_t) x) >> 16) & 0xFF) << 40) | \ + (((((uint64_t) x) >> 24) & 0xFF) << 32) | \ + (((((uint64_t) x) >> 32) & 0xFF) << 24) | \ + (((((uint64_t) x) >> 40) & 0xFF) << 16) | \ + (((((uint64_t) x) >> 48) & 0xFF) << 8) | \ + (((uint64_t) x) >> 56) +#define NETWORK_TO_HOST64 HOST_TO_NETWORK64 + +#endif /* MAR_PRIVATE_H__ */ diff --git a/src/include/mar_read.c b/src/include/mar_read.c new file mode 100644 index 0000000..abed4b7 --- /dev/null +++ b/src/include/mar_read.c @@ -0,0 +1,574 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include +#include +#include +#include "mar_private.h" +#include "mar.h" + +#ifdef XP_WIN +#include +#else +#include +#endif + + +/* this is the same hash algorithm used by nsZipArchive.cpp */ +static uint32_t mar_hash_name(const char *name) { + uint32_t val = 0; + unsigned char* c; + + for (c = (unsigned char *) name; *c; ++c) + val = val*37 + *c; + + return val % TABLESIZE; +} + +static int mar_insert_item(MarFile *mar, const char *name, int namelen, + uint32_t offset, uint32_t length, uint32_t flags) { + MarItem *item, *root; + uint32_t hash; + + item = (MarItem *) malloc(sizeof(MarItem) + namelen); + if (!item) + return -1; + item->next = NULL; + item->offset = offset; + item->length = length; + item->flags = flags; + memcpy(item->name, name, namelen + 1); + + hash = mar_hash_name(name); + + root = mar->item_table[hash]; + if (!root) { + mar->item_table[hash] = item; + } else { + /* append item */ + while (root->next) + root = root->next; + root->next = item; + } + return 0; +} + +static int mar_consume_index(MarFile *mar, char **buf, const char *buf_end) { + /* + * Each item has the following structure: + * uint32_t offset (network byte order) + * uint32_t length (network byte order) + * uint32_t flags (network byte order) + * char name[N] (where N >= 1) + * char null_byte; + */ + uint32_t offset; + uint32_t length; + uint32_t flags; + const char *name; + int namelen; + + if ((buf_end - *buf) < (int)(3*sizeof(uint32_t) + 2)) + return -1; + + memcpy(&offset, *buf, sizeof(offset)); + *buf += sizeof(offset); + + memcpy(&length, *buf, sizeof(length)); + *buf += sizeof(length); + + memcpy(&flags, *buf, sizeof(flags)); + *buf += sizeof(flags); + + offset = ntohl(offset); + length = ntohl(length); + flags = ntohl(flags); + + name = *buf; + /* find namelen; must take care not to read beyond buf_end */ + while (**buf) { + if (*buf == buf_end) + return -1; + ++(*buf); + } + namelen = (*buf - name); + /* must ensure that namelen is valid */ + if (namelen < 0) { + return -1; + } + /* consume null byte */ + if (*buf == buf_end) + return -1; + ++(*buf); + + return mar_insert_item(mar, name, namelen, offset, length, flags); +} + +static int mar_read_index(MarFile *mar) { + char id[MAR_ID_SIZE], *buf, *bufptr, *bufend; + uint32_t offset_to_index, size_of_index; + + /* verify MAR ID */ + if (fread(id, MAR_ID_SIZE, 1, mar->fp) != 1) + return -1; + if (memcmp(id, MAR_ID, MAR_ID_SIZE) != 0) + return -1; + + if (fread(&offset_to_index, sizeof(uint32_t), 1, mar->fp) != 1) + return -1; + offset_to_index = ntohl(offset_to_index); + + if (fseek(mar->fp, offset_to_index, SEEK_SET)) + return -1; + if (fread(&size_of_index, sizeof(uint32_t), 1, mar->fp) != 1) + return -1; + size_of_index = ntohl(size_of_index); + + buf = (char *) malloc(size_of_index); + if (!buf) + return -1; + if (fread(buf, size_of_index, 1, mar->fp) != 1) { + free(buf); + return -1; + } + + bufptr = buf; + bufend = buf + size_of_index; + while (bufptr < bufend && mar_consume_index(mar, &bufptr, bufend) == 0); + + free(buf); + return (bufptr == bufend) ? 0 : -1; +} + +/** + * Internal shared code for mar_open and mar_wopen. + * On failure, will fclose(fp). + */ +static MarFile *mar_fpopen(FILE *fp) +{ + MarFile *mar; + + mar = (MarFile *) malloc(sizeof(*mar)); + if (!mar) { + fclose(fp); + return NULL; + } + + mar->fp = fp; + memset(mar->item_table, 0, sizeof(mar->item_table)); + if (mar_read_index(mar)) { + mar_close(mar); + return NULL; + } + + return mar; +} + +MarFile *mar_open(const char *path) { + FILE *fp; + + fp = fopen(path, "rb"); + if (!fp) { + fprintf(stderr, "ERROR: could not open file in mar_open()\n"); + perror(path); + return NULL; + } + + return mar_fpopen(fp); +} + +#ifdef XP_WIN +MarFile *mar_wopen(const wchar_t *path) { + FILE *fp; + + _wfopen_s(&fp, path, L"rb"); + if (!fp) { + fprintf(stderr, "ERROR: could not open file in mar_wopen()\n"); + _wperror(path); + return NULL; + } + + return mar_fpopen(fp); +} +#endif + +void mar_close(MarFile *mar) { + MarItem *item; + int i; + + fclose(mar->fp); + + for (i = 0; i < TABLESIZE; ++i) { + item = mar->item_table[i]; + while (item) { + MarItem *temp = item; + item = item->next; + free(temp); + } + } + + free(mar); +} + +/** + * Determines the MAR file information. + * + * @param fp An opened MAR file in read mode. + * @param hasSignatureBlock Optional out parameter specifying if the MAR + * file has a signature block or not. + * @param numSignatures Optional out parameter for storing the number + * of signatures in the MAR file. + * @param hasAdditionalBlocks Optional out parameter specifying if the MAR + * file has additional blocks or not. + * @param offsetAdditionalBlocks Optional out parameter for the offset to the + * first additional block. Value is only valid if + * hasAdditionalBlocks is not equal to 0. + * @param numAdditionalBlocks Optional out parameter for the number of + * additional blocks. Value is only valid if + * hasAdditionalBlocks is not equal to 0. + * @return 0 on success and non-zero on failure. + */ +int get_mar_file_info_fp(FILE *fp, + int *hasSignatureBlock, + uint32_t *numSignatures, + int *hasAdditionalBlocks, + uint32_t *offsetAdditionalBlocks, + uint32_t *numAdditionalBlocks) +{ + uint32_t offsetToIndex, offsetToContent, signatureCount, signatureLen, i; + + /* One of hasSignatureBlock or hasAdditionalBlocks must be non NULL */ + if (!hasSignatureBlock && !hasAdditionalBlocks) { + return -1; + } + + + /* Skip to the start of the offset index */ + if (fseek(fp, MAR_ID_SIZE, SEEK_SET)) { + return -1; + } + + /* Read the offset to the index. */ + if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fp) != 1) { + return -1; + } + offsetToIndex = ntohl(offsetToIndex); + + if (numSignatures) { + /* Skip past the MAR file size field */ + if (fseek(fp, sizeof(uint64_t), SEEK_CUR)) { + return -1; + } + + /* Read the number of signatures field */ + if (fread(numSignatures, sizeof(*numSignatures), 1, fp) != 1) { + return -1; + } + *numSignatures = ntohl(*numSignatures); + } + + /* Skip to the first index entry past the index size field + We do it in 2 calls because offsetToIndex + sizeof(uint32_t) + could oerflow in theory. */ + if (fseek(fp, offsetToIndex, SEEK_SET)) { + return -1; + } + + if (fseek(fp, sizeof(uint32_t), SEEK_CUR)) { + return -1; + } + + /* Read the first offset to content field. */ + if (fread(&offsetToContent, sizeof(offsetToContent), 1, fp) != 1) { + return -1; + } + offsetToContent = ntohl(offsetToContent); + + /* Check if we have a new or old MAR file */ + if (hasSignatureBlock) { + if (offsetToContent == MAR_ID_SIZE + sizeof(uint32_t)) { + *hasSignatureBlock = 0; + } else { + *hasSignatureBlock = 1; + } + } + + /* If the caller doesn't care about the product info block + value, then just return */ + if (!hasAdditionalBlocks) { + return 0; + } + + /* Skip to the start of the signature block */ + if (fseeko(fp, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) { + return -1; + } + + /* Get the number of signatures */ + if (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) { + return -1; + } + signatureCount = ntohl(signatureCount); + + /* Check that we have less than the max amount of signatures so we don't + waste too much of either updater's or signmar's time. */ + if (signatureCount > MAX_SIGNATURES) { + return -1; + } + + /* Skip past the whole signature block */ + for (i = 0; i < signatureCount; i++) { + /* Skip past the signature algorithm ID */ + if (fseek(fp, sizeof(uint32_t), SEEK_CUR)) { + return -1; + } + + /* Read the signature length and skip past the signature */ + if (fread(&signatureLen, sizeof(uint32_t), 1, fp) != 1) { + return -1; + } + signatureLen = ntohl(signatureLen); + if (fseek(fp, signatureLen, SEEK_CUR)) { + return -1; + } + } + + if ((int64_t)ftell(fp) == (int64_t)offsetToContent) { + *hasAdditionalBlocks = 0; + } else { + if (numAdditionalBlocks) { + /* We have an additional block, so read in the number of additional blocks + and set the offset. */ + *hasAdditionalBlocks = 1; + if (fread(numAdditionalBlocks, sizeof(uint32_t), 1, fp) != 1) { + return -1; + } + *numAdditionalBlocks = ntohl(*numAdditionalBlocks); + if (offsetAdditionalBlocks) { + *offsetAdditionalBlocks = ftell(fp); + } + } else if (offsetAdditionalBlocks) { + /* numAdditionalBlocks is not specified but offsetAdditionalBlocks + is, so fill it! */ + *offsetAdditionalBlocks = ftell(fp) + sizeof(uint32_t); + } + } + + return 0; +} + +/** + * Reads the product info block from the MAR file's additional block section. + * The caller is responsible for freeing the fields in infoBlock + * if the return is successful. + * + * @param infoBlock Out parameter for where to store the result to + * @return 0 on success, -1 on failure +*/ +int +read_product_info_block(char *path, + struct ProductInformationBlock *infoBlock) +{ + int rv; + MarFile mar; + mar.fp = fopen(path, "rb"); + if (!mar.fp) { + fprintf(stderr, "ERROR: could not open file in read_product_info_block()\n"); + perror(path); + return -1; + } + rv = mar_read_product_info_block(&mar, infoBlock); + fclose(mar.fp); + return rv; +} + +/** + * Reads the product info block from the MAR file's additional block section. + * The caller is responsible for freeing the fields in infoBlock + * if the return is successful. + * + * @param infoBlock Out parameter for where to store the result to + * @return 0 on success, -1 on failure +*/ +int +mar_read_product_info_block(MarFile *mar, + struct ProductInformationBlock *infoBlock) +{ + uint32_t i, offsetAdditionalBlocks, numAdditionalBlocks, + additionalBlockSize, additionalBlockID; + int hasAdditionalBlocks; + + /* The buffer size is 97 bytes because the MAR channel name < 64 bytes, and + product version < 32 bytes + 3 NULL terminator bytes. */ + char buf[97] = { '\0' }; + int ret = get_mar_file_info_fp(mar->fp, NULL, NULL, + &hasAdditionalBlocks, + &offsetAdditionalBlocks, + &numAdditionalBlocks); + for (i = 0; i < numAdditionalBlocks; ++i) { + /* Read the additional block size */ + if (fread(&additionalBlockSize, + sizeof(additionalBlockSize), + 1, mar->fp) != 1) { + return -1; + } + additionalBlockSize = ntohl(additionalBlockSize) - + sizeof(additionalBlockSize) - + sizeof(additionalBlockID); + + /* Read the additional block ID */ + if (fread(&additionalBlockID, + sizeof(additionalBlockID), + 1, mar->fp) != 1) { + return -1; + } + additionalBlockID = ntohl(additionalBlockID); + + if (PRODUCT_INFO_BLOCK_ID == additionalBlockID) { + const char *location; + int len; + + /* This block must be at most 104 bytes. + MAR channel name < 64 bytes, and product version < 32 bytes + 3 NULL + terminator bytes. We only check for 96 though because we remove 8 + bytes above from the additionalBlockSize: We subtract + sizeof(additionalBlockSize) and sizeof(additionalBlockID) */ + if (additionalBlockSize > 96) { + return -1; + } + + if (fread(buf, additionalBlockSize, 1, mar->fp) != 1) { + return -1; + } + + /* Extract the MAR channel name from the buffer. For now we + point to the stack allocated buffer but we strdup this + if we are within bounds of each field's max length. */ + location = buf; + len = strlen(location); + infoBlock->MARChannelID = location; + location += len + 1; + if (len >= 64) { + infoBlock->MARChannelID = NULL; + return -1; + } + + /* Extract the version from the buffer */ + len = strlen(location); + infoBlock->productVersion = location; + location += len + 1; + if (len >= 32) { + infoBlock->MARChannelID = NULL; + infoBlock->productVersion = NULL; + return -1; + } + infoBlock->MARChannelID = + strdup(infoBlock->MARChannelID); + infoBlock->productVersion = + strdup(infoBlock->productVersion); + return 0; + } else { + /* This is not the additional block you're looking for. Move along. */ + if (fseek(mar->fp, additionalBlockSize, SEEK_CUR)) { + return -1; + } + } + } + + /* If we had a product info block we would have already returned */ + return -1; +} + +const MarItem *mar_find_item(MarFile *mar, const char *name) { + uint32_t hash; + const MarItem *item; + + hash = mar_hash_name(name); + + item = mar->item_table[hash]; + while (item && strcmp(item->name, name) != 0) + item = item->next; + + return item; +} + +int mar_enum_items(MarFile *mar, MarItemCallback callback, void *closure) { + MarItem *item; + int i; + + for (i = 0; i < TABLESIZE; ++i) { + item = mar->item_table[i]; + while (item) { + int rv = callback(mar, item, closure); + if (rv) + return rv; + item = item->next; + } + } + + return 0; +} + +int mar_read(MarFile *mar, const MarItem *item, int offset, char *buf, + int bufsize) { + int nr; + + if (offset == (int) item->length) + return 0; + if (offset > (int) item->length) + return -1; + + nr = item->length - offset; + if (nr > bufsize) + nr = bufsize; + + if (fseek(mar->fp, item->offset + offset, SEEK_SET)) + return -1; + + return fread(buf, 1, nr, mar->fp); +} + +/** + * Determines the MAR file information. + * + * @param path The path of the MAR file to check. + * @param hasSignatureBlock Optional out parameter specifying if the MAR + * file has a signature block or not. + * @param numSignatures Optional out parameter for storing the number + * of signatures in the MAR file. + * @param hasAdditionalBlocks Optional out parameter specifying if the MAR + * file has additional blocks or not. + * @param offsetAdditionalBlocks Optional out parameter for the offset to the + * first additional block. Value is only valid if + * hasAdditionalBlocks is not equal to 0. + * @param numAdditionalBlocks Optional out parameter for the number of + * additional blocks. Value is only valid if + * has_additional_blocks is not equal to 0. + * @return 0 on success and non-zero on failure. + */ +int get_mar_file_info(const char *path, + int *hasSignatureBlock, + uint32_t *numSignatures, + int *hasAdditionalBlocks, + uint32_t *offsetAdditionalBlocks, + uint32_t *numAdditionalBlocks) +{ + int rv; + FILE *fp = fopen(path, "rb"); + if (!fp) { + fprintf(stderr, "ERROR: could not open file in get_mar_file_info()\n"); + perror(path); + return -1; + } + + rv = get_mar_file_info_fp(fp, hasSignatureBlock, + numSignatures, hasAdditionalBlocks, + offsetAdditionalBlocks, numAdditionalBlocks); + + fclose(fp); + return rv; +} diff --git a/src/include/randtable.c b/src/include/randtable.c new file mode 100644 index 0000000..d186335 --- /dev/null +++ b/src/include/randtable.c @@ -0,0 +1,84 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for randomising repetitive blocks ---*/ +/*--- randtable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------*/ +Int32 BZ2_rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +/*-------------------------------------------------------------*/ +/*--- end randtable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/main.cpp b/src/main.cpp index c40402192ab06e841fbadabdcf5e8e0b6d860c95..0544b2cd28df1ae39e0525cbec381df98bb66d95 100644 GIT binary patch literal 36178 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 diff --git a/src/main.h b/src/main.h index fa5227d2b854cfd3d0e8338dd078b9d0e139c5da..92ca11009e605bbcb7ce36a8ea48e26d248cefcc 100644 GIT binary patch delta 84 zcmZ3$b%lL{5aYxrBEpFb1wa_jkj#+JkjIe5kjaofnVs<|qv_;CX8FlHOfo>0CX?#q l9wt4;_{lq&0w+&liJ82NMTfhbp_su4sMDCiX!3m)M*zz@7JUE! delta 379 zcmcb@zJP0k5aVPQ##@XgljWJLfn+q3>f{|vLcAUfsSJ4xMGTb;+6>x2Ir+&AOnQ?y zFa=CjW0J5BXK-b3VhCpNWC#JW6c~IMlo&D?N`SC{!HPj22+P4x4=4&VrvNCY$B+*+ zGaY1Jy*pU92SX^(BvccMp=P8rWCBghU?^os0_sc#>dgh3jB27111|#?7%Kx+r!k}e z?Mnli7tat5G~bWGjKKsd%L$ds1o|tLL1FTGMoxWS21f>G1`n`Gm_I-|Af_q<)#Wf0 s14)n_$_$*77cz?5V$);HV1%S64`>s}Eeha}Kyl0D?@XzamoOUu06Ek_(f|Me diff --git a/src/res/101.ico b/src/res/101.ico new file mode 100644 index 0000000000000000000000000000000000000000..85ffedfe613c48146e9912fe2a072427166c5626 GIT binary patch literal 85989 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 literal 0 HcmV?d00001 diff --git a/src/resource.h b/src/resource.h index 012ba0b..370191a 100644 --- a/src/resource.h +++ b/src/resource.h @@ -13,12 +13,11 @@ // Main Dlg #define IDC_PROGRESS 1001 -#define IDC_VERSION 1002 -#define IDC_REVISION 1003 -#define IDC_BUILD 1004 -#define IDC_COMMIT 1005 -#define IDC_DATE 1006 -#define IDC_STATUSBAR 1007 +#define IDC_BROWSER 1002 +#define IDC_CURRENTVERSION 1003 +#define IDC_VERSION 1004 +#define IDC_DATE 1005 +#define IDC_STATUSBAR 1006 // Main Menu #define IDM_EXIT 1000 @@ -31,15 +30,15 @@ // Strings #define IDS_ABOUT 1000 -#define IDS_VERSION 1001 -#define IDS_REVISION 1002 -#define IDS_BUILD 1003 -#define IDS_COMMIT 1004 -#define IDS_DATE 1005 +#define IDS_BROWSER 1001 +#define IDS_CURRENTVERSION 1002 +#define IDS_VERSION 1003 +#define IDS_DATE 1004 #define IDS_STATUS_DOWNLOAD 1006 #define IDS_STATUS_INSTALL 1007 +#define IDS_STATUS_NOTFOUND 1008 -#define IDS_QUESTION_BUSY 1008 +#define IDS_QUESTION_BUSY 1009 #endif // __RESOURCE_H__ diff --git a/src/resource.rc b/src/resource.rc index db8730a38c24c69608d167a02820175f038b4bef..39bff3cf9b3f06440e42f87c636663ac926c99a5 100644 GIT binary patch delta 608 zcmaJ;JuHJ!6g_RF?N{Gd^0kT>`V*2?{FOuy5uqwXDybG*(^Ar;K0^I$HVK1>yV#8) zk<@B2vzjcz%xrT!Qzhi(-TU6X=bm%#d#7E`oi|-|j(!YPd+P@5+8i>N!ZI@Q;%qi1 zkj6Zgu)tVauAH&jeA^_lM5LKbv2O7jMeGb~QWA9iLd%iUlyg^mEr-myb+Nl6a^_As zhS67jb%*V?Vd-|YRzvkIwnGgDJkZFRAa@QmJt2e$we#3O5hJ{HV23tJzlv@YP(lSU zVrn`5>02>QVi((7MOYpZgs{iswp{9AN$OF#)f?r;(D^*O6ev?FgjKmS9_7hsSx<5N z43e~2ww6$YSy*hcKx~os3N~riSZk?Ti_v{XlnMtZF>fivCY$(UD2eM$a^W2hmWkd` zym@SKm07<+waO2Ve0YzwIQkIhBWg0;5VpmurG_boEhpDzvn!|ma83@*puCv@Mn8Ev vF})J?jVZt98&&?^mry?7Pby#bC+Z{Uq4WWFgbc0n?jKaScfVIAnjXFYu(p6r delta 599 zcmZ8eO-oxr6g?Wv%Zo`&C#f-_7==KsABkU~hzOdeRM2OPsoNq=&|sQWqtcz=&W$bJ zZ9#D1x-@^F-MA>-6pAZX-S&NT z{Pc!o-cq9c3Hjpff5f`;SjIM1u|?Z}D?xwq(rVH665fzlgQE%AZZTnd1M6I?C>Z9( z>XVAES6^c}SVRHK8uz@yj9htR^4)SfCy~ZfE*BvHo* zh7p7xHrqQ?_7+c6BEgJ2N;pAT{&fw-S~3l@gkzLZK~cs7@qsMg)s$-3ENXbqRmKtK zLw?JQN~*NFxP^K=85bu ze)^K;aEua%8ArTfj;EyT2Y$%6pc~sk)!bVldW;V!K4i&Y=)Cbal<{;fB8Qx8dgAg& zDaomRaU(uCQ9W{}dgWSW=+|grNk<&x&mt>w8!3#KN{(}#Ka|C5j@RY)>tRk%#z$IH TuKZTdWg)6Nh3P}`Ir{5A