unpack.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /******************************************************************************
  2. *
  3. * project name: TI-68k Developer Utilities
  4. * file name: unpack.c
  5. * initial date: 14/08/2000
  6. * authors: albert@cs.tut.fi
  7. * thomas.nussbaumer@gmx.net
  8. * description: unpacking routine
  9. *
  10. * NOTE: the behavior ("fast/long code/unsecure" or "slow/short code/safe") can
  11. * be set by defining DO_FAST_UNPACKING
  12. *
  13. * -----------------------------------------------------------------------------
  14. *
  15. * Unpacking program using the PuCrunch algorithm.
  16. * Based on code from Pasi 'Albert' Ojala, albert@cs.tut.fi
  17. * Heavily reduced to fit to the needs by thomas.nussbaumer@gmx.net
  18. * Pucrunch 1997-2005 by Pasi 'Albert' Ojala, a1bert@iki.fi
  19. * See http://www.cs.tut.fi/~albert/Dev/pucrunch/ for details on the used algorithm
  20. * Pucrunch is under GNU LGPL:
  21. * See http://creativecommons.org/licenses/LGPL/2.1/ or
  22. * http://www.gnu.org/copyleft/lesser.html
  23. *
  24. *
  25. * The decompression code is distributed under the
  26. * WXWindows Library Licence:
  27. * See http://www.wxwidgets.org/licence3.txt
  28. *
  29. * In short: binary version of the decompression code can
  30. * accompany the compressed data or be used in decompression
  31. * programs.
  32. *
  33. ******************************************************************************
  34. *
  35. * NOTE: This is a slow, but generic implementation which can be used
  36. * on the PC as well as for the calculator software.
  37. *
  38. ******************************************************************************/
  39. #include "ttunpack.h" // errorcodes definition
  40. #include "packhead.h" // compressed header definition
  41. #ifdef DO_FAST_UNPACKING
  42. #define _ttcallmode_ inline
  43. #else
  44. //#define ALL_CHECKS // additionally runtime checks (enable this for tests)
  45. #define _ttcallmode_
  46. #endif
  47. //-----------------------------------------------------------------------------
  48. // All globals and functions are prefixed with _tt_ by the intention to
  49. // prevent possible name conflicts in the global namespace
  50. //-----------------------------------------------------------------------------
  51. unsigned char* _tt_InBuffer = 0; // input buffer
  52. unsigned int _tt_InMask = 0; // input buffer byte mask
  53. //---------------------------------------------------------------------------
  54. // _tt_InMask is initialized with 0x80 and gets shifted right each time about
  55. // 1 bit. CORRECT_IN_MASK will handle the shift right and if the mask becomes
  56. // zero it will set it again to 0x80 + increments the inputbuffer
  57. //
  58. // THIS SHOULD BE OPTIMIZABLE WITH A ROTATE WITH CARRY
  59. //---------------------------------------------------------------------------
  60. #define CORRECT_IN_MASK if (!(_tt_InMask >>= 1)) _tt_InMask = 0x80,_tt_InBuffer++;
  61. //---------------------------------------------------------------------------
  62. // returns >0 if next bit is set, otherwise 0
  63. //---------------------------------------------------------------------------
  64. #define NEXT_BIT_SET (*_tt_InBuffer & _tt_InMask)
  65. //=============================================================================
  66. // gets a number of bits from the input buffer
  67. //=============================================================================
  68. _ttcallmode_ unsigned int _tt_GetBits(unsigned int bits) {
  69. unsigned int val = 0;
  70. while (bits--) {
  71. val <<= 1;
  72. if (NEXT_BIT_SET) val |= 1;
  73. CORRECT_IN_MASK;
  74. }
  75. return val;
  76. }
  77. //=============================================================================
  78. // get next 8 bits
  79. //=============================================================================
  80. _ttcallmode_ unsigned int _tt_Get8Bit() {
  81. unsigned int v;
  82. // very fast if we are already on a byte boundary
  83. if (_tt_InMask == 0x80) return *_tt_InBuffer++;
  84. v = *(_tt_InBuffer++) << 8;
  85. v |= *_tt_InBuffer;
  86. switch(_tt_InMask) {
  87. case 0x40: v &= 0x7fff; return v >>= 7;
  88. case 0x20: v &= 0x3fff; return v >>= 6;
  89. case 0x10: v &= 0x1fff; return v >>= 5;
  90. case 0x08: v &= 0x0fff; return v >>= 4;
  91. case 0x04: v &= 0x07ff; return v >>= 3;
  92. case 0x02: v &= 0x03ff; return v >>= 2;
  93. case 0x01: v &= 0x01ff; return v >>= 1;
  94. }
  95. return 0;
  96. }
  97. //=============================================================================
  98. // get next value from the input buffer
  99. //=============================================================================
  100. unsigned int _tt_GetValue(unsigned int maxgamma) {
  101. unsigned int i = 0;
  102. while (i<maxgamma) {
  103. if (!(NEXT_BIT_SET)) {
  104. CORRECT_IN_MASK;
  105. break;
  106. }
  107. CORRECT_IN_MASK;
  108. i++;
  109. }
  110. return (1<<i) | _tt_GetBits(i);
  111. }
  112. //=============================================================================
  113. // the decompression routine
  114. //
  115. // using it is very simple: feed in a filled source array and a buffer which is
  116. // large enough to hold the decompression result
  117. //
  118. // returns 0 if okay
  119. //
  120. //=============================================================================
  121. int _tt_Decompress(unsigned char *src, unsigned char *dest) {
  122. long startEsc;
  123. unsigned char* byteCodeVec;
  124. PackedHeader* cth = (PackedHeader*)src;
  125. unsigned int maxgamma1;
  126. unsigned int maxgamma2;
  127. unsigned int maxgamma8;
  128. unsigned int escbits8;
  129. unsigned int escbits;
  130. unsigned int extralzposbits;
  131. unsigned int maxgamma;
  132. unsigned char* outbuffer;
  133. #ifdef ALL_CHECKS
  134. unsigned char* pend_in;
  135. unsigned char* pend_out;
  136. #endif
  137. //---------------------------------------------------------------------
  138. // check if the magic markers exists. if they are not present we cannot
  139. // decompress this type of file
  140. //---------------------------------------------------------------------
  141. if (cth->magic1 != MAGIC_CHAR1 || cth->magic2 != MAGIC_CHAR2) return ERRPCK_NOMAGIC;
  142. startEsc = cth->esc1;
  143. escbits = cth->esc2;
  144. maxgamma = cth->gamma1 - 1;
  145. extralzposbits = cth->extralz;
  146. maxgamma1 = 1 << maxgamma;
  147. maxgamma2 = 2 << maxgamma;
  148. maxgamma8 = 8 - maxgamma;
  149. escbits8 = 8 - escbits;
  150. if (escbits > 8) return ERRPCK_ESCBITS;
  151. if (cth->gamma2 != maxgamma1 || maxgamma < 5 || maxgamma > 7) return ERRPCK_MAXGAMMA;
  152. if (extralzposbits > 4) return ERRPCK_EXTRALZP;
  153. byteCodeVec = &src[15]; // ??? shouldn't it start at 16 -- strange ???
  154. //--------------------------
  155. // initialize buffer globals
  156. //--------------------------
  157. outbuffer = dest;
  158. _tt_InBuffer = src + sizeof(PackedHeader) + cth->rleentries; // points at start of data
  159. _tt_InMask = 0x80;
  160. #ifdef ALL_CHECKS
  161. pend_in = _tt_InBuffer + (((unsigned int)cth->compsize_lo) | ((unsigned int)(cth->compsize_hi << 8)));
  162. pend_out = dest + (((unsigned int)cth->origsize_lo) | ((unsigned int)(cth->origsize_hi << 8)));
  163. #endif
  164. while (1) {
  165. int sel = startEsc;
  166. #ifdef ALL_CHECKS
  167. if (outbuffer > pend_out) return ERRPCK_OUTBUFOVERRUN;
  168. if (_tt_InBuffer > pend_in) return ERRPCK_NOESCFOUND;
  169. #endif
  170. if (escbits) sel = _tt_GetBits(escbits);
  171. if (sel == startEsc) {
  172. unsigned int lzPos, lzLen = _tt_GetValue(maxgamma), i;
  173. unsigned int add = 0;
  174. if (lzLen != 1) {
  175. unsigned int lzPosHi = _tt_GetValue(maxgamma)-1, lzPosLo;
  176. if (lzPosHi == maxgamma2-2) {
  177. if (lzLen > 3) {
  178. add = _tt_Get8Bit();
  179. lzPos = _tt_Get8Bit() ^ 0xff;
  180. }
  181. else {
  182. break; // finish !!!
  183. }
  184. }
  185. else {
  186. if (extralzposbits) lzPosHi = (lzPosHi<<extralzposbits) | _tt_GetBits(extralzposbits);
  187. lzPosLo = _tt_Get8Bit() ^ 0xff;
  188. lzPos = (lzPosHi<<8) | lzPosLo;
  189. }
  190. }
  191. else {
  192. if (NEXT_BIT_SET) {
  193. unsigned int rleLen, byteCode, byte;
  194. CORRECT_IN_MASK;
  195. if (!NEXT_BIT_SET) {
  196. unsigned int newEsc;
  197. CORRECT_IN_MASK;
  198. newEsc = _tt_GetBits(escbits);
  199. *outbuffer++ = (startEsc<<escbits8) | _tt_GetBits(escbits8);
  200. startEsc = newEsc;
  201. #ifdef ALL_CHECKS
  202. if (outbuffer > pend_out) return ERRPCK_OUTBUFOVERRUN;
  203. #endif
  204. continue;
  205. }
  206. //else {
  207. CORRECT_IN_MASK;
  208. //}
  209. rleLen = _tt_GetValue(maxgamma);
  210. if (rleLen >= maxgamma1) {
  211. rleLen = ((rleLen-maxgamma1)<<maxgamma8) | _tt_GetBits(maxgamma8);
  212. rleLen |= ((_tt_GetValue(maxgamma)-1)<<8);
  213. }
  214. byteCode = _tt_GetValue(maxgamma);
  215. if (byteCode < 32) byte = (unsigned int)(byteCodeVec[byteCode]);
  216. else byte = ((byteCode-32)<<3) | _tt_GetBits(3);
  217. for (i=0; i<=rleLen; i++) *outbuffer++ = byte;
  218. continue;
  219. }
  220. //else {
  221. CORRECT_IN_MASK;
  222. //}
  223. lzPos = _tt_Get8Bit() ^ 0xff;
  224. }
  225. #ifdef ALL_CHECKS
  226. if (outbuffer + lzLen + 1 > pend_out) return ERRPCK_OUTBUFOVERRUN;
  227. #endif
  228. for (i=0; i<=lzLen; i++) {
  229. *outbuffer = *(outbuffer - lzPos - 1) + add;
  230. outbuffer++;
  231. }
  232. }
  233. else {
  234. *outbuffer++ = (sel<<escbits8) | _tt_GetBits(escbits8);
  235. #ifdef ALL_CHECKS
  236. if (outbuffer > pend_out) return ERRPCK_OUTBUFOVERRUN;
  237. #endif
  238. }
  239. }
  240. return ERRPCK_OKAY;
  241. }
  242. //#############################################################################
  243. //###################### NO MORE FAKES BEYOND THIS LINE #######################
  244. //#############################################################################
  245. //
  246. //=============================================================================
  247. // Revision History
  248. //=============================================================================
  249. //
  250. // Revision 1.2 2002/02/07 09:49:38 tnussb
  251. // all local includes changed, because header files are now located in pctools folder
  252. //
  253. // Revision 1.1 2001/02/05 20:45:05 Thomas Nussbaumer
  254. // moved to pctools folder
  255. //
  256. //
  257. //