123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- /******************************************************************************
- *
- * project name: TI-68k Developer Utilities (formerly TIGCC Tools Suite)
- * file name: unpack.c
- * initial date: 14/08/2000
- * authors: albert@cs.tut.fi
- * thomas.nussbaumer@gmx.net
- * description: unpacking routine
- *
- * NOTE: the behavior ("fast/long code/unsecure" or "slow/short code/safe") can
- * be set by defining DO_FAST_UNPACKING
- *
- * -----------------------------------------------------------------------------
- *
- * Unpacking program using the PuCrunch algorithm.
- * Based on code from Pasi 'Albert' Ojala, albert@cs.tut.fi
- * Heavily reduced to fit to the needs by thomas.nussbaumer@gmx.net
- * Pucrunch 1997-2005 by Pasi 'Albert' Ojala, a1bert@iki.fi
- * See http://www.cs.tut.fi/~albert/Dev/pucrunch/ for details on the used algorithm
- * Pucrunch is under GNU LGPL:
- * See http://creativecommons.org/licenses/LGPL/2.1/ or
- * http://www.gnu.org/copyleft/lesser.html
- *
- *
- * The decompression code is distributed under the
- * WXWindows Library Licence:
- * See http://www.wxwidgets.org/licence3.txt
- *
- * In short: binary version of the decompression code can
- * accompany the compressed data or be used in decompression
- * programs.
- *
- ******************************************************************************
- *
- * NOTE: This is a slow, but generic implementation which can be used
- * on the PC as well as for the calculator software.
- *
- ******************************************************************************/
- #include "ttunpack.h" // errorcodes definition
- #include "packhead.h" // compressed header definition
- #ifdef DO_FAST_UNPACKING
- #define _ttcallmode_ inline
- #else
- //#define ALL_CHECKS // additionally runtime checks (enable this for tests)
- #define _ttcallmode_
- #endif
- //-----------------------------------------------------------------------------
- // All globals and functions are prefixed with _tt_ by the intention to
- // prevent possible name conflicts in the global namespace
- //-----------------------------------------------------------------------------
- unsigned char* _tt_InBuffer = 0; // input buffer
- unsigned int _tt_InMask = 0; // input buffer byte mask
- //---------------------------------------------------------------------------
- // _tt_InMask is initialized with 0x80 and gets shifted right each time about
- // 1 bit. CORRECT_IN_MASK will handle the shift right and if the mask becomes
- // zero it will set it again to 0x80 + increments the inputbuffer
- //
- // THIS SHOULD BE OPTIMIZABLE WITH A ROTATE WITH CARRY
- //---------------------------------------------------------------------------
- #define CORRECT_IN_MASK if (!(_tt_InMask >>= 1)) _tt_InMask = 0x80,_tt_InBuffer++;
- //---------------------------------------------------------------------------
- // returns >0 if next bit is set, otherwise 0
- //---------------------------------------------------------------------------
- #define NEXT_BIT_SET (*_tt_InBuffer & _tt_InMask)
- //=============================================================================
- // gets a number of bits from the input buffer
- //=============================================================================
- _ttcallmode_ unsigned int _tt_GetBits(unsigned int bits) {
- unsigned int val = 0;
- while (bits--) {
- val <<= 1;
- if (NEXT_BIT_SET) val |= 1;
- CORRECT_IN_MASK;
- }
- return val;
- }
- //=============================================================================
- // get next 8 bits
- //=============================================================================
- _ttcallmode_ unsigned int _tt_Get8Bit() {
- unsigned int v;
- // very fast if we are already on a byte boundary
- if (_tt_InMask == 0x80) return *_tt_InBuffer++;
- v = *(_tt_InBuffer++) << 8;
- v |= *_tt_InBuffer;
- switch(_tt_InMask) {
- case 0x40: v &= 0x7fff; return v >>= 7;
- case 0x20: v &= 0x3fff; return v >>= 6;
- case 0x10: v &= 0x1fff; return v >>= 5;
- case 0x08: v &= 0x0fff; return v >>= 4;
- case 0x04: v &= 0x07ff; return v >>= 3;
- case 0x02: v &= 0x03ff; return v >>= 2;
- case 0x01: v &= 0x01ff; return v >>= 1;
- }
- return 0;
- }
- //=============================================================================
- // get next value from the input buffer
- //=============================================================================
- unsigned int _tt_GetValue(unsigned int maxgamma) {
- unsigned int i = 0;
- while (i<maxgamma) {
- if (!(NEXT_BIT_SET)) {
- CORRECT_IN_MASK;
- break;
- }
- CORRECT_IN_MASK;
- i++;
- }
- return (1<<i) | _tt_GetBits(i);
- }
- //=============================================================================
- // the decompression routine
- //
- // using it is very simple: feed in a filled source array and a buffer which is
- // large enough to hold the decompression result
- //
- // returns 0 if okay
- //
- //=============================================================================
- int _tt_Decompress(unsigned char *src, unsigned char *dest) {
- long startEsc;
- unsigned char* byteCodeVec;
- PackedHeader* cth = (PackedHeader*)src;
- unsigned int maxgamma1;
- unsigned int maxgamma2;
- unsigned int maxgamma8;
- unsigned int escbits8;
- unsigned int escbits;
- unsigned int extralzposbits;
- unsigned int maxgamma;
- unsigned char* outbuffer;
- #ifdef ALL_CHECKS
- unsigned char* pend_in;
- unsigned char* pend_out;
- #endif
- //---------------------------------------------------------------------
- // check if the magic markers exists. if they are not present we cannot
- // decompress this type of file
- //---------------------------------------------------------------------
- if (cth->magic1 != MAGIC_CHAR1 || cth->magic2 != MAGIC_CHAR2) return ERRPCK_NOMAGIC;
- startEsc = cth->esc1;
- escbits = cth->esc2;
- maxgamma = cth->gamma1 - 1;
- extralzposbits = cth->extralz;
- maxgamma1 = 1 << maxgamma;
- maxgamma2 = 2 << maxgamma;
- maxgamma8 = 8 - maxgamma;
- escbits8 = 8 - escbits;
- if (escbits > 8) return ERRPCK_ESCBITS;
- if (cth->gamma2 != maxgamma1 || maxgamma < 5 || maxgamma > 7) return ERRPCK_MAXGAMMA;
- if (extralzposbits > 4) return ERRPCK_EXTRALZP;
- byteCodeVec = &src[15]; // ??? shouldn't it start at 16 -- strange ???
- //--------------------------
- // initialize buffer globals
- //--------------------------
- outbuffer = dest;
- _tt_InBuffer = src + sizeof(PackedHeader) + cth->rleentries; // points at start of data
- _tt_InMask = 0x80;
- #ifdef ALL_CHECKS
- pend_in = _tt_InBuffer + (((unsigned int)cth->compsize_lo) | ((unsigned int)(cth->compsize_hi << 8)));
- pend_out = dest + (((unsigned int)cth->origsize_lo) | ((unsigned int)(cth->origsize_hi << 8)));
- #endif
- while (1) {
- int sel = startEsc;
- #ifdef ALL_CHECKS
- if (outbuffer > pend_out) return ERRPCK_OUTBUFOVERRUN;
- if (_tt_InBuffer > pend_in) return ERRPCK_NOESCFOUND;
- #endif
- if (escbits) sel = _tt_GetBits(escbits);
- if (sel == startEsc) {
- unsigned int lzPos, lzLen = _tt_GetValue(maxgamma), i;
- unsigned int add = 0;
- if (lzLen != 1) {
- unsigned int lzPosHi = _tt_GetValue(maxgamma)-1, lzPosLo;
- if (lzPosHi == maxgamma2-2) {
- if (lzLen > 3) {
- add = _tt_Get8Bit();
- lzPos = _tt_Get8Bit() ^ 0xff;
- }
- else {
- break; // finish !!!
- }
- }
- else {
- if (extralzposbits) lzPosHi = (lzPosHi<<extralzposbits) | _tt_GetBits(extralzposbits);
- lzPosLo = _tt_Get8Bit() ^ 0xff;
- lzPos = (lzPosHi<<8) | lzPosLo;
- }
- }
- else {
- if (NEXT_BIT_SET) {
- unsigned int rleLen, byteCode, byte;
- CORRECT_IN_MASK;
- if (!NEXT_BIT_SET) {
- unsigned int newEsc;
- CORRECT_IN_MASK;
- newEsc = _tt_GetBits(escbits);
- *outbuffer++ = (startEsc<<escbits8) | _tt_GetBits(escbits8);
- startEsc = newEsc;
- #ifdef ALL_CHECKS
- if (outbuffer > pend_out) return ERRPCK_OUTBUFOVERRUN;
- #endif
- continue;
- }
- //else {
- CORRECT_IN_MASK;
- //}
- rleLen = _tt_GetValue(maxgamma);
- if (rleLen >= maxgamma1) {
- rleLen = ((rleLen-maxgamma1)<<maxgamma8) | _tt_GetBits(maxgamma8);
- rleLen |= ((_tt_GetValue(maxgamma)-1)<<8);
- }
- byteCode = _tt_GetValue(maxgamma);
- if (byteCode < 32) byte = (unsigned int)(byteCodeVec[byteCode]);
- else byte = ((byteCode-32)<<3) | _tt_GetBits(3);
- for (i=0; i<=rleLen; i++) *outbuffer++ = byte;
- continue;
- }
- //else {
- CORRECT_IN_MASK;
- //}
- lzPos = _tt_Get8Bit() ^ 0xff;
- }
- #ifdef ALL_CHECKS
- if (outbuffer + lzLen + 1 > pend_out) return ERRPCK_OUTBUFOVERRUN;
- #endif
- for (i=0; i<=lzLen; i++) {
- *outbuffer = *(outbuffer - lzPos - 1) + add;
- outbuffer++;
- }
- }
- else {
- *outbuffer++ = (sel<<escbits8) | _tt_GetBits(escbits8);
- #ifdef ALL_CHECKS
- if (outbuffer > pend_out) return ERRPCK_OUTBUFOVERRUN;
- #endif
- }
- }
- return ERRPCK_OKAY;
- }
- //#############################################################################
- //###################### NO MORE FAKES BEYOND THIS LINE #######################
- //#############################################################################
- //
- //=============================================================================
- // Revision History
- //=============================================================================
- //
- // Revision 1.2 2002/02/07 09:49:38 tnussb
- // all local includes changed, because header files are now located in pctools folder
- //
- // Revision 1.1 2001/02/05 20:45:05 Thomas Nussbaumer
- // moved to pctools folder
- //
- //
- //
|