uzlib_deflate.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. /*
  2. * This implementation draws heavily on the work down by Paul Sokolovsky
  3. * (https://github.com/pfalcon) and his uzlib library which in turn uses
  4. * work done by Joergen Ibsen, Simon Tatham and others. All of this work
  5. * is under an unrestricted right to use subject to copyright attribution.
  6. * Two copyright wordings (variants A and B) are following.
  7. *
  8. * (c) statement A initTables, copy, literal
  9. *
  10. * The remainder of this code has been written by me, Terry Ellison 2018,
  11. * under the standard NodeMCU MIT licence, but is available to the other
  12. * contributors to this source under any permissive licence.
  13. *
  14. * My primary algorithmic reference is RFC 1951: "DEFLATE Compressed Data
  15. * Format Specification version 1.3", dated May 1996.
  16. *
  17. * Also because the code in this module is drawn from different sources,
  18. * the different coding practices can be confusing, I have standardised
  19. * the source by:
  20. *
  21. * - Adopting the 2 indent rule as in the rest of the firmware
  22. *
  23. * - I have replaced the various mix of char, unsigned char and uchar
  24. * by the single uchar type; ditto for ushort and uint.
  25. *
  26. * - All internal (non-exported) functions and data are static
  27. *
  28. * - Only exported functions and data have the module prefix. All
  29. * internal (static) variables and fields are lowerCamalCase.
  30. *
  31. ***********************************************************************
  32. * Copyright statement A for Zlib (RFC1950 / RFC1951) compression for PuTTY.
  33. PuTTY is copyright 1997-2014 Simon Tatham.
  34. Portions copyright Robert de Bath, Joris van Rantwijk, Delian
  35. Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
  36. Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
  37. Kuhn, Colin Watson, and CORE SDI S.A.
  38. Permission is hereby granted, free of charge, to any person
  39. obtaining a copy of this software and associated documentation files
  40. (the "Software"), to deal in the Software without restriction,
  41. including without limitation the rights to use, copy, modify, merge,
  42. publish, distribute, sublicense, and/or sell copies of the Software,
  43. and to permit persons to whom the Software is furnished to do so,
  44. subject to the following conditions:
  45. The above copyright notice and this permission notice shall be
  46. included in all copies or substantial portions of the Software.
  47. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  48. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  49. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  50. NONINFRINGEMENT. IN NO EVENT SHALL THE COP--YRIGHT HOLDERS BE LIABLE
  51. FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  52. CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  53. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  54. ************************************************************************
  55. Copyright statement B for genlz77 functions:
  56. *
  57. * genlz77 - Generic LZ77 compressor
  58. *
  59. * Copyright (c) 2014 by Paul Sokolovsky
  60. *
  61. * This software is provided 'as-is', without any express
  62. * or implied warranty. In no event will the authors be
  63. * held liable for any damages arising from the use of
  64. * this software.
  65. *
  66. * Permission is granted to anyone to use this software
  67. * for any purpose, including commercial applications,
  68. * and to alter it and redistribute it freely, subject to
  69. * the following restrictions:
  70. *
  71. * 1. The origin of this software must not be
  72. * misrepresented; you must not claim that you
  73. * wrote the original software. If you use this
  74. * software in a product, an acknowledgment in
  75. * the product documentation would be appreciated
  76. * but is not required.
  77. *
  78. * 2. Altered source versions must be plainly marked
  79. * as such, and must not be misrepresented as
  80. * being the original software.
  81. *
  82. * 3. This notice may not be removed or altered from
  83. * any source distribution.
  84. */
  85. #include <stdlib.h>
  86. #include <string.h>
  87. #include <stdio.h>
  88. #include <assert.h>
  89. #include "uzlib.h"
  90. jmp_buf unwindAddr;
  91. /* Minimum and maximum length of matches to look for, inclusive */
  92. #define MIN_MATCH 3
  93. #define MAX_MATCH 258
  94. /* Max offset of the match to look for, inclusive */
  95. #define MAX_OFFSET 16384 // 32768 //
  96. #define OFFSET16_MASK 0x7FFF
  97. #define NULL_OFFSET 0xFFFF
  98. #if MIN_MATCH < 3
  99. #error "Encoding requires a minium match of 3 bytes"
  100. #endif
  101. #define SIZE(a) (sizeof(a)/sizeof(*a)) /* no of elements in array */
  102. #ifdef __XTENSA__
  103. #define RAM_COPY_BYTE_ARRAY(c,s,sl) uchar *c = alloca(sl); memcpy(c,s,(sl))
  104. #else
  105. #define RAM_COPY_BYTE_ARRAY(c,s,sl) uchar *c = s;
  106. #endif
  107. #define FREE(v) if (v) uz_free(v)
  108. typedef uint8_t uchar;
  109. typedef uint16_t ushort;
  110. typedef uint32_t uint;
  111. #ifdef DEBUG_COUNTS
  112. #define DBG_PRINT(...) printf(__VA_ARGS__)
  113. #define DBG_COUNT(n) (debugCounts[n]++)
  114. #define DBG_ADD_COUNT(n,m) (debugCounts[n]+=m)
  115. int debugCounts[20];
  116. #else
  117. #define DBG_PRINT(...)
  118. #define DBG_COUNT(n)
  119. #define DBG_ADD_COUNT(n,m)
  120. #endif
  121. int dbg_break(void) {return 1;}
  122. typedef struct {
  123. ushort code, extraBits, min, max;
  124. } codeRecord;
  125. struct dynTables {
  126. ushort *hashChain;
  127. ushort *hashTable;
  128. ushort hashMask;
  129. ushort hashSlots;
  130. ushort hashBits;
  131. ushort dictLen;
  132. const uchar bitrevNibble[16];
  133. const codeRecord lenCodes[285-257+1];
  134. const codeRecord distCodes[29-0+1];
  135. } *dynamicTables;
  136. struct outputBuf {
  137. uchar *buffer;
  138. uint len, size;
  139. uint inLen, inNdx;
  140. uint bits, nBits;
  141. uint compDisabled;
  142. } *oBuf;
  143. /*
  144. * Set up the constant tables used to drive the compression
  145. *
  146. * Constants are stored in flash memory on the ESP8266 NodeMCU firmware
  147. * builds, but only word aligned data access are supported in hardware so
  148. * short and byte accesses are handled by a S/W exception handler and are
  149. * SLOW. RAM is also at premium, so these short routines are driven by
  150. * byte vectors copied into RAM and then used to generate temporary RAM
  151. * tables, which are the same as the above statically declared versions.
  152. *
  153. * This might seem a bit convolved but this runs faster and takes up less
  154. * memory than the original version. This code also works fine on the
  155. * x86-64s so we just use one code variant.
  156. *
  157. * Note that fixed Huffman trees as defined in RFC 1951 Sec 3.2.5 are
  158. * always used. Whilst dynamic trees can give better compression for
  159. * larger blocks, this comes at a performance hit of having to compute
  160. * these trees. Fixed trees give better compression performance on short
  161. * blocks and significantly reduce compression times.
  162. *
  163. * The following defines are used to initialise these tables.
  164. */
  165. #define lenCodes_GEN \
  166. "\x03\x01\x01\x01\x01\x01\x01\x01\xff\x02\x02\x02\x02\xff\x04\x04\x04\x04" \
  167. "\xff\x08\x08\x08\x08\xff\x10\x10\x10\x10\xff\x20\x20\x20\x1f\xff\x01\x00"
  168. #define lenCodes_LEN 29
  169. #define distCodes_GEN \
  170. "\x01\x01\x01\x01\xff\x02\x02\xff\x04\x04\xff\x08\x08\xff\x10\x10\xff" \
  171. "\x20\x20\xff\x40\x40\xff\x86\x86\xff\x87\x87\xff\x88\x88\xff" \
  172. "\x89\x89\xff\x8a\x8a\xff\x8b\x8b\xff\x8c\x8c"
  173. #define distCodes_LEN 30
  174. #define BITREV16 "\x0\x8\x4\xc\x2\xa\x6\xe\x1\x9\x5\xd\x3\xb\x7\xf"
  175. static void genCodeRecs (const codeRecord *rec, ushort len,
  176. char *init, int initLen,
  177. ushort start, ushort m0) {
  178. DBG_COUNT(0);
  179. int i, b=0, m=0, last=m0;
  180. RAM_COPY_BYTE_ARRAY(c, (uchar *)init,initLen);
  181. codeRecord *p = (codeRecord *) rec;
  182. for (i = start; i < start+len; i++, c++) {
  183. if (*c == 0xFF)
  184. b++, c++;
  185. m += (*c & 0x80) ? 2 << (*c & 0x1F) : *c;
  186. *p++ = (codeRecord) {i, b, last + 1, (last = m)};
  187. }
  188. }
  189. static void initTables (uint chainLen, uint hashSlots) {
  190. DBG_COUNT(1);
  191. uint dynamicSize = sizeof(struct dynTables) +
  192. sizeof(struct outputBuf) +
  193. chainLen * sizeof(ushort) +
  194. hashSlots * sizeof(ushort);
  195. struct dynTables *dt = uz_malloc(dynamicSize);
  196. memset(dt, 0, dynamicSize);
  197. dynamicTables = dt;
  198. /* Do a single malloc for dymanic tables and assign addresses */
  199. if(!dt )
  200. UZLIB_THROW(UZLIB_MEMORY_ERROR);
  201. memcpy((uchar*)dt->bitrevNibble, BITREV16, 16);
  202. oBuf = (struct outputBuf *)(dt+1);
  203. dt->hashTable = (ushort *)(oBuf+1);
  204. dt->hashChain = dt->hashTable + hashSlots;
  205. dt->hashSlots = hashSlots;
  206. dt->hashMask = hashSlots - 1;
  207. /* As these are offset rather than pointer, 0 is a valid offset */
  208. /* (unlike NULL), so 0xFFFF is used to denote an unset value */
  209. memset(dt->hashTable, -1, sizeof(ushort)*hashSlots);
  210. memset(dt->hashChain, -1, sizeof(ushort)*chainLen);
  211. /* Generate the code recors for the lenth and distance code tables */
  212. genCodeRecs(dt->lenCodes, SIZE(dt->lenCodes),
  213. lenCodes_GEN, sizeof(lenCodes_GEN),
  214. 257,2);
  215. ((codeRecord *)(dynamicTables->lenCodes+285-257))->extraBits=0; /* odd ball entry */
  216. genCodeRecs(dt->distCodes, SIZE(dt->distCodes),
  217. distCodes_GEN, sizeof(distCodes_GEN),
  218. 0,0);
  219. }
  220. /*
  221. * Routines to output bit streams and byte streams to the output buffer
  222. */
  223. void resizeBuffer(void) {
  224. uchar *nb;
  225. DBG_COUNT(2);
  226. /* The outbuf is given an initial size estimate but if we are running */
  227. /* out of space then extropolate size using current compression */
  228. double newEstimate = (((double) oBuf->len)*oBuf->inLen) / oBuf->inNdx;
  229. oBuf->size = 128 + (uint) newEstimate;
  230. if (!(nb = realloc(oBuf->buffer, oBuf->size)))
  231. UZLIB_THROW(UZLIB_MEMORY_ERROR);
  232. oBuf->buffer = nb;
  233. }
  234. void outBits(ushort bits, int nBits) {
  235. DBG_COUNT(3);
  236. oBuf->bits |= bits << oBuf->nBits;
  237. oBuf->nBits += nBits;
  238. if (oBuf->len >= oBuf->size - sizeof(bits))
  239. resizeBuffer();
  240. while (oBuf->nBits >= 8) {
  241. DBG_PRINT("%02x-", oBuf->bits & 0xFF);
  242. oBuf->buffer[oBuf->len++] = oBuf->bits & 0xFF;
  243. oBuf->bits >>= 8;
  244. oBuf->nBits -= 8;
  245. }
  246. }
  247. void outBitsRev(uchar bits, int nBits) {
  248. DBG_COUNT(4);
  249. /* Note that bit reversal only operates on an 8-bit bits field */
  250. uchar bitsRev = (dynamicTables->bitrevNibble[bits & 0x0f]<<4) |
  251. dynamicTables->bitrevNibble[bits>>4];
  252. outBits(bitsRev, nBits);
  253. }
  254. void outBytes(void *bytes, int nBytes) {
  255. DBG_COUNT(5);
  256. int i;
  257. if (oBuf->len >= oBuf->size - nBytes)
  258. resizeBuffer();
  259. /* Note that byte output dumps any bits data so the caller must */
  260. /* flush this first, if necessary */
  261. oBuf->nBits = oBuf->bits = 0;
  262. for (i = 0; i < nBytes; i++) {
  263. DBG_PRINT("%02x-", *((uchar*)bytes+i));
  264. oBuf->buffer[oBuf->len++] = *((uchar*)bytes+i);
  265. }
  266. }
  267. /*
  268. * Output an literal byte as an 8 or 9 bit code
  269. */
  270. void literal (uchar c) {
  271. DBG_COUNT(6);
  272. DBG_PRINT("sym: %02x %c\n", c, c);
  273. if (oBuf->compDisabled) {
  274. /* We're in an uncompressed block, so just output the byte. */
  275. outBits(c, 8);
  276. } else if (c <= 143) {
  277. /* 0 through 143 are 8 bits long starting at 00110000. */
  278. outBitsRev(0x30 + c, 8);
  279. } else {
  280. /* 144 through 255 are 9 bits long starting at 110010000. */
  281. outBits(1, 1);
  282. outBitsRev(0x90 - 144 + c, 8);
  283. }
  284. }
  285. /*
  286. * Output a dictionary (distance, length) pars as bitstream codes
  287. */
  288. void copy (int distance, int len) {
  289. DBG_COUNT(7);
  290. const codeRecord *lenCodes = dynamicTables->lenCodes, *l;
  291. const codeRecord *distCodes = dynamicTables->distCodes, *d;
  292. int i, j, k;
  293. assert(!oBuf->compDisabled);
  294. while (len > 0) {
  295. /*
  296. * We can transmit matches of lengths 3 through 258
  297. * inclusive. So if len exceeds 258, we must transmit in
  298. * several steps, with 258 or less in each step.
  299. *
  300. * Specifically: if len >= 261, we can transmit 258 and be
  301. * sure of having at least 3 left for the next step. And if
  302. * len <= 258, we can just transmit len. But if len == 259
  303. * or 260, we must transmit len-3.
  304. */
  305. int thislen = (len > 260 ? 258 : len <= 258 ? len : len - 3);
  306. len -= thislen;
  307. /*
  308. * Binary-search to find which length code we're
  309. * transmitting.
  310. */
  311. i = -1;
  312. j = lenCodes_LEN;
  313. while (1) {
  314. assert(j - i >= 2);
  315. k = (j + i) / 2;
  316. if (thislen < lenCodes[k].min)
  317. j = k;
  318. else if (thislen > lenCodes[k].max)
  319. i = k;
  320. else {
  321. l = &lenCodes[k];
  322. break; /* found it! */
  323. }
  324. }
  325. /*
  326. * Transmit the length code. 256-279 are seven bits
  327. * starting at 0000000; 280-287 are eight bits starting at
  328. * 11000000.
  329. */
  330. if (l->code <= 279) {
  331. outBitsRev((l->code - 256) * 2, 7);
  332. } else {
  333. outBitsRev(0xc0 - 280 + l->code, 8);
  334. }
  335. /*
  336. * Transmit the extra bits.
  337. */
  338. if (l->extraBits)
  339. outBits(thislen - l->min, l->extraBits);
  340. /*
  341. * Binary-search to find which distance code we're
  342. * transmitting.
  343. */
  344. i = -1;
  345. j = distCodes_LEN;
  346. while (1) {
  347. assert(j - i >= 2);
  348. k = (j + i) / 2;
  349. if (distance < distCodes[k].min)
  350. j = k;
  351. else if (distance > distCodes[k].max)
  352. i = k;
  353. else {
  354. d = &distCodes[k];
  355. break; /* found it! */
  356. }
  357. }
  358. /*
  359. * Transmit the distance code. Five bits starting at 00000.
  360. */
  361. outBitsRev(d->code * 8, 5);
  362. /*
  363. * Transmit the extra bits.
  364. */
  365. if (d->extraBits)
  366. outBits(distance - d->min, d->extraBits);
  367. }
  368. }
  369. /*
  370. * Block compression uses a hashTable to index into a set of search
  371. * chainList, where each chain links together the triples of chars within
  372. * the dictionary (the last MAX_OFFSET bytes of the input buffer) with
  373. * the same hash index. So for compressing a file of 200Kb, say, with a
  374. * 16K dictionary (the largest that we can inflate within the memory
  375. * constraints of the ESP8266), the chainList is 16K slots long, and the
  376. * hashTable is 4K slots long, so a typical chain will have 4 links.
  377. *
  378. * These two tables use 16-bit ushort offsets rather than pointers to
  379. * save memory (essential on the ESP8266).
  380. *
  381. * As per RFC 1951 sec 4, we also implement a "lazy match" procedure
  382. */
  383. void uzlibCompressBlock(const uchar *src, uint srcLen) {
  384. int i, j, k, l;
  385. uint hashMask = dynamicTables->hashMask;
  386. ushort *hashChain = dynamicTables->hashChain;
  387. ushort *hashTable = dynamicTables->hashTable;
  388. uint hashShift = 24 - dynamicTables->hashBits;
  389. uint lastOffset = 0, lastLen = 0;
  390. oBuf->inLen = srcLen; /* used for output buffer resizing */
  391. DBG_COUNT(9);
  392. for (i = 0; i <= ((int)srcLen) - MIN_MATCH; i++) {
  393. /*
  394. * Calculate a hash on the next three chars using the liblzf hash
  395. * function, then use this via the hashTable to index into the chain
  396. * of triples within the dictionary window which have the same hash.
  397. *
  398. * Note that using 16-bit offsets requires a little manipulation to
  399. * handle wrap-around and recover the correct offset, but all other
  400. * working uses uint offsets simply because the compiler generates
  401. * faster (and smaller in the case of the ESP8266) code.
  402. *
  403. * Also note that this code also works for any tail 2 literals; the
  404. * hash will access beyond the array and will be incorrect, but
  405. * these can't match and will flush the last cache.
  406. */
  407. const uchar *this = src + i, *comp;
  408. uint base = i & ~OFFSET16_MASK;
  409. uint iOffset = i - base;
  410. uint maxLen = srcLen - i;
  411. uint matchLen = MIN_MATCH - 1;
  412. uint matchOffset = 0;
  413. uint v = (this[0] << 16) | (this[1] << 8) | this[2];
  414. uint hash = ((v >> hashShift) - v) & hashMask;
  415. uint nextOffset = hashTable[hash];
  416. oBuf->inNdx = i; /* used for output buffer resizing */
  417. DBG_COUNT(10);
  418. if (maxLen>MAX_MATCH)
  419. maxLen = MAX_MATCH;
  420. hashTable[hash] = iOffset;
  421. hashChain[iOffset & (MAX_OFFSET-1)] = nextOffset;
  422. for (l = 0; nextOffset != NULL_OFFSET && l<60; l++) {
  423. DBG_COUNT(11);
  424. /* handle the case where base has bumped */
  425. j = base + nextOffset - ((nextOffset < iOffset) ? 0 : (OFFSET16_MASK + 1));
  426. if (i - j > MAX_OFFSET)
  427. break;
  428. for (k = 0, comp = src + j; this[k] == comp[k] && k < maxLen; k++)
  429. {}
  430. DBG_ADD_COUNT(12, k);
  431. if (k > matchLen) {
  432. matchOffset = i - j;
  433. matchLen = k;
  434. }
  435. nextOffset = hashChain[nextOffset & (MAX_OFFSET-1)];
  436. }
  437. if (lastOffset) {
  438. if (matchOffset == 0 || lastLen >= matchLen ) {
  439. /* ignore this match (or not) and process last */
  440. DBG_COUNT(14);
  441. copy(lastOffset, lastLen);
  442. DBG_PRINT("dic: %6x %6x %6x\n", i-1, lastLen, lastOffset);
  443. i += lastLen - 1 - 1;
  444. lastOffset = lastLen = 0;
  445. } else {
  446. /* ignore last match and emit a symbol instead; cache this one */
  447. DBG_COUNT(15);
  448. literal(this[-1]);
  449. lastOffset = matchOffset;
  450. lastLen = matchLen;
  451. }
  452. } else { /* no last match */
  453. if (matchOffset) {
  454. DBG_COUNT(16);
  455. /* cache this one */
  456. lastOffset = matchOffset;
  457. lastLen = matchLen;
  458. } else {
  459. DBG_COUNT(17);
  460. /* emit a symbol; last already clear */
  461. literal(this[0]);
  462. }
  463. }
  464. }
  465. if (lastOffset) { /* flush cached match if any */
  466. copy(lastOffset, lastLen);
  467. DBG_PRINT("dic: %6x %6x %6x\n", i, lastLen, lastOffset);
  468. i += lastLen - 1;
  469. }
  470. while (i < srcLen)
  471. literal(src[i++]); /* flush the last few bytes if needed */
  472. }
  473. /*
  474. * This compress wrapper treats the input stream as a single block for
  475. * compression using the default Static huffman block encoding
  476. */
  477. int uzlib_compress (uchar **dest, uint *destLen, const uchar *src, uint srcLen) {
  478. uint crc = ~uzlib_crc32(src, srcLen, ~0);
  479. uint chainLen = srcLen < MAX_OFFSET ? srcLen : MAX_OFFSET;
  480. uint hashSlots, i, j;
  481. int status;
  482. uint FLG_MTIME[] = {0x00088b1f, 0};
  483. ushort XFL_OS = 0x0304;
  484. /* The hash table has 4K slots for a 16K chain and scaling down */
  485. /* accordingly, for an average chain length of 4 links or thereabouts */
  486. for (i = 256, j = 8 - 2; i < chainLen; i <<= 1)
  487. j++;
  488. hashSlots = i >> 2;
  489. if ((status = UZLIB_SETJMP(unwindAddr)) == 0) {
  490. initTables(chainLen, hashSlots);
  491. oBuf->size = srcLen/5; /* initial guess of a 5x compression ratio */
  492. oBuf->buffer = uz_malloc(oBuf->size);
  493. dynamicTables->hashSlots = hashSlots;
  494. dynamicTables->hashBits = j;
  495. if(!oBuf->buffer ) {
  496. status = UZLIB_MEMORY_ERROR;
  497. } else {
  498. /* Output gzip and block headers */
  499. outBytes(FLG_MTIME, sizeof(FLG_MTIME));
  500. outBytes(&XFL_OS, sizeof(XFL_OS));
  501. outBits(1, 1); /* Final block */
  502. outBits(1, 2); /* Static huffman block */
  503. uzlibCompressBlock(src, srcLen); /* Do the compress */
  504. /* Output block finish */
  505. outBits(0, 7); /* close block */
  506. outBits(0, 7); /* Make sure all bits are flushed */
  507. outBytes(&crc, sizeof(crc));
  508. outBytes(&srcLen, sizeof(srcLen));
  509. status = UZLIB_OK;
  510. }
  511. } else {
  512. status = UZLIB_OK;
  513. }
  514. for (i=0; i<20;i++) DBG_PRINT("count %u = %u\n",i,debugCounts[i]);
  515. if (status == UZLIB_OK) {
  516. uchar *trimBuf = realloc(oBuf->buffer, oBuf->len);
  517. *dest = trimBuf ? trimBuf : oBuf->buffer;
  518. *destLen = oBuf->len;
  519. } else {
  520. *dest = NULL;
  521. *destLen = 0;
  522. FREE(oBuf->buffer);
  523. }
  524. FREE(dynamicTables);
  525. return status;
  526. }