/* lzh.c */ /* Synchronet LZH compression library */ /* $Id$ */ /**************************************************************************** * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * * Rob Swindell's conversion of 1988 LZH (LHarc) encoding functions * * Based on Japanese version 29-NOV-1988 * * LZSS coded by Haruhiko Okumura * * Adaptive Huffman Coding coded by Haruyasu Yoshizaki * * * * Anonymous FTP access to the most recent released source is available at * * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * * * * Anonymous CVS access to the development source and modification history * * is available at cvs.synchro.net:/cvsroot/sbbs, example: * * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login * * (just hit return, no password is necessary) * * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src * * * * For Synchronet coding style and modification guidelines, see * * http://www.synchro.net/source.html * * * * You are encouraged to submit any modifications (preferably in Unix diff * * format) via e-mail to mods@synchro.net * * * * Note: If this box doesn't appear square, then you need to fix your tabs. * ****************************************************************************/ #include #include #include #include /* FreeBSD's malloc.h is deprecated, it drops a warning and */ /* #includes , which is already here. */ #ifndef __FreeBSD__ #include #endif #include "lzh.h" /****************************************************************************/ /* Memory allocation macros for various compilers and environments */ /* MALLOC is used for allocations of 64k or less */ /* FREE is used to free buffers allocated with MALLOC */ /* LMALLOC is used for allocations of possibly larger than 64k */ /* LFREE is used to free buffers allocated with LMALLOC */ /* REALLOC is used to re-size a previously MALLOCed or LMALLOCed buffer */ /****************************************************************************/ #if defined(__COMPACT__) || defined(__LARGE__) || defined(__HUGE__) #if defined(__TURBOC__) #define REALLOC(x,y) farrealloc(x,y) #define LMALLOC(x) farmalloc(x) #define MALLOC(x) farmalloc(x) #define LFREE(x) farfree(x) #define FREE(x) farfree(x) #elif defined(__WATCOMC__) #define REALLOC realloc #define LMALLOC(x) halloc(x,1) /* far heap, but slow */ #define MALLOC malloc /* far heap, but 64k max */ #define LFREE hfree #define FREE free #else /* Other 16-bit Compiler */ #define REALLOC realloc #define LMALLOC malloc #define MALLOC malloc #define LFREE free #define FREE free #endif #else /* 32-bit Compiler or Small Memory Model */ #define REALLOC realloc #define LMALLOC malloc #define MALLOC malloc #define LFREE free #define FREE free #endif /* LZSS Parameters */ #define LZH_N 4096 /* Size of string buffer */ #define LZH_F 60 /* Size of look-ahead buffer */ #define LZH_THRESHOLD 2 #define LZH_NIL LZH_N /* End of tree's node */ #ifdef LZH_DYNAMIC_BUF uint8_t *lzh_text_buf; int16_t lzh_match_position, lzh_match_length, *lzh_lson, *lzh_rson, *lzh_dad; #else uint8_t lzh_text_buf[LZH_N + LZH_F - 1]; int16_t lzh_match_position, lzh_match_length, lzh_lson[LZH_N + 1], lzh_rson[LZH_N + 257], lzh_dad[LZH_N + 1]; #endif void lzh_init_tree(void) /* Initializing tree */ { int16_t i; for (i = LZH_N + 1; i <= LZH_N + 256; i++) lzh_rson[i] = LZH_NIL; /* root */ for (i = 0; i < LZH_N; i++) lzh_dad[i] = LZH_NIL; /* node */ } /******************************/ /* Inserting node to the tree */ /* Only used during encoding */ /******************************/ void lzh_insert_node(int16_t r) { int16_t i, p, cmp; uint8_t *key; uint32_t c; cmp = 1; key = lzh_text_buf+r; p = LZH_N + 1 + key[0]; lzh_rson[r] = lzh_lson[r] = LZH_NIL; lzh_match_length = 0; for ( ; ; ) { if (cmp >= 0) { if (lzh_rson[p] != LZH_NIL) p = lzh_rson[p]; else { lzh_rson[p] = r; lzh_dad[r] = p; return; } } else { if (lzh_lson[p] != LZH_NIL) p = lzh_lson[p]; else { lzh_lson[p] = r; lzh_dad[r] = p; return; } } for (i = 1; i < LZH_F; i++) if ((cmp = key[i] - lzh_text_buf[p + i]) != 0) break; if (i > LZH_THRESHOLD) { if (i > lzh_match_length) { lzh_match_position = ((r - p) & (LZH_N - 1)) - 1; if ((lzh_match_length = i) >= LZH_F) break; } if (i == lzh_match_length) { if ((c = ((r - p) & (LZH_N - 1)) - 1) < (uint32_t)lzh_match_position) { lzh_match_position = c; } } } } lzh_dad[r] = lzh_dad[p]; lzh_lson[r] = lzh_lson[p]; lzh_rson[r] = lzh_rson[p]; lzh_dad[lzh_lson[p]] = r; lzh_dad[lzh_rson[p]] = r; if (lzh_rson[lzh_dad[p]] == p) lzh_rson[lzh_dad[p]] = r; else lzh_lson[lzh_dad[p]] = r; lzh_dad[p] = LZH_NIL; /* remove p */ } void lzh_delete_node(int16_t p) /* Deleting node from the tree */ { int16_t q; if (lzh_dad[p] == LZH_NIL) return; /* unregistered */ if (lzh_rson[p] == LZH_NIL) q = lzh_lson[p]; else if (lzh_lson[p] == LZH_NIL) q = lzh_rson[p]; else { q = lzh_lson[p]; if (lzh_rson[q] != LZH_NIL) { do { q = lzh_rson[q]; } while (lzh_rson[q] != LZH_NIL); lzh_rson[lzh_dad[q]] = lzh_lson[q]; lzh_dad[lzh_lson[q]] = lzh_dad[q]; lzh_lson[q] = lzh_lson[p]; lzh_dad[lzh_lson[p]] = q; } lzh_rson[q] = lzh_rson[p]; lzh_dad[lzh_rson[p]] = q; } lzh_dad[q] = lzh_dad[p]; if (lzh_rson[lzh_dad[p]] == p) lzh_rson[lzh_dad[p]] = q; else lzh_lson[lzh_dad[p]] = q; lzh_dad[p] = LZH_NIL; } /* Huffman coding parameters */ #define LZH_N_CHAR (256 - LZH_THRESHOLD + LZH_F) /* character code (= 0..LZH_N_CHAR-1) */ #define LZH_T (LZH_N_CHAR * 2 - 1) /* Size of table */ #define LZH_R (LZH_T - 1) /* root position */ #define MAX_FREQ 0x8000 /* update when cumulative frequency */ /* reaches to this value */ /* * Tables for encoding/decoding upper 6 bits of * sliding dictionary pointer */ /* encoder table */ uint8_t lzh_p_len[64] = { 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }; uint8_t lzh_p_code[64] = { 0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C, 0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC, 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE, 0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; /* decoder table */ uint8_t lzh_d_code[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, }; uint8_t lzh_d_len[256] = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }; #ifdef LZH_DYNAMIC_BUF uint16_t *lzh_freq = NULL; /* cumulative freq table */ /* * pointing parent nodes. * area [LZH_T..(LZH_T + LZH_N_CHAR - 1)] are pointers for leaves */ int16_t *lzh_prnt = NULL; /* pointing children nodes (son[], son[] + 1)*/ int16_t *lzh_son = NULL; #else /* STATIC */ uint16_t lzh_freq[LZH_T + 1]; /* cumulative freq table */ int16_t lzh_prnt[LZH_T + LZH_N_CHAR]; int16_t lzh_son[LZH_T + 1]; /* bug fixed by Digital Dynamics */ #endif uint16_t lzh_getbuf = 0; /* Was just "unsigned" fixed 04/12/95 */ uint8_t lzh_getlen = 0; int lzh_getbit(uint8_t *inbuf, int32_t *incnt, int32_t inlen) /* get one bit */ { int16_t i; while (lzh_getlen <= 8) { if((*incnt)>=inlen) i=0; else i=inbuf[(*incnt)++]; lzh_getbuf |= i << (8 - lzh_getlen); lzh_getlen += 8; } i = lzh_getbuf; lzh_getbuf <<= 1; lzh_getlen--; return (i < 0); } int16_t lzh_getbyte(uint8_t *inbuf, int32_t *incnt, int32_t inlen) /* get a byte */ { uint16_t i; while (lzh_getlen <= 8) { if((*incnt)>=inlen) i=0; else i=inbuf[(*incnt)++]; lzh_getbuf |= i << (8 - lzh_getlen); lzh_getlen += 8; } i = lzh_getbuf; lzh_getbuf <<= 8; lzh_getlen -= 8; return i >> 8; } uint32_t lzh_putbuf = 0; uint8_t lzh_putlen = 0; /* output c bits */ void lzh_putcode(int16_t l, uint16_t c, uint8_t *outbuf, int32_t *outlen) { lzh_putbuf |= c >> lzh_putlen; if ((lzh_putlen += l) >= 8) { outbuf[(*outlen)++]=(lzh_putbuf >> 8); if ((lzh_putlen -= 8) >= 8) { outbuf[(*outlen)++]=lzh_putbuf; lzh_putlen -= 8; lzh_putbuf = c << (l - lzh_putlen); } else { lzh_putbuf <<= 8; } } } /* initialize freq tree */ void lzh_start_huff(void) { int16_t i, j; lzh_getbuf = 0; /* Added by Digital Dynamics for repeating operations */ lzh_getlen = 0; lzh_putbuf = 0; lzh_putlen = 0; for (i = 0; i < LZH_N_CHAR; i++) { lzh_freq[i] = 1; lzh_son[i] = i + LZH_T; lzh_prnt[i + LZH_T] = i; } i = 0; j = LZH_N_CHAR; while (j <= LZH_R) { lzh_freq[j] = lzh_freq[i] + lzh_freq[i + 1]; lzh_son[j] = i; lzh_prnt[i] = lzh_prnt[i + 1] = j; i += 2; j++; } lzh_freq[LZH_T] = 0xffff; lzh_prnt[LZH_R] = 0; } /* reconstruct freq tree */ void lzh_reconst(void) { int16_t i, j, k; uint16_t f, l; /* halven cumulative freq for leaf nodes */ j = 0; for (i = 0; i < LZH_T; i++) { if (lzh_son[i] >= LZH_T) { lzh_freq[j] = (lzh_freq[i] + 1) / 2; lzh_son[j] = lzh_son[i]; j++; } } /* make a tree : first, connect children nodes */ for (i = 0, j = LZH_N_CHAR; j < LZH_T; i += 2, j++) { k = i + 1; f = lzh_freq[j] = lzh_freq[i] + lzh_freq[k]; for (k = j - 1; f < lzh_freq[k]; k--); k++; l = (j - k) * 2; /* movmem() is Turbo-C dependent rewritten to memmove() by Kenji */ /* movmem(&lzh_freq[k], &lzh_freq[k + 1], l); */ (void)memmove(lzh_freq+k+1,lzh_freq+k, l); lzh_freq[k] = f; /* movmem(&lzh_son[k], &lzh_son[k + 1], l); */ (void)memmove(lzh_son+k+1,lzh_son+k, l); lzh_son[k] = i; } /* connect parent nodes */ for (i = 0; i < LZH_T; i++) { if ((k = lzh_son[i]) >= LZH_T) { lzh_prnt[k] = i; } else { lzh_prnt[k] = lzh_prnt[k + 1] = i; } } } /* update freq tree */ void lzh_update(int16_t c) { int16_t i, j, k, l; if (lzh_freq[LZH_R] == MAX_FREQ) { lzh_reconst(); } c = lzh_prnt[c + LZH_T]; do { k = ++lzh_freq[c]; /* swap nodes to keep the tree freq-ordered */ if (k > lzh_freq[l = c + 1]) { while (k > lzh_freq[++l]); l--; lzh_freq[c] = lzh_freq[l]; lzh_freq[l] = k; i = lzh_son[c]; lzh_prnt[i] = l; if (i < LZH_T) lzh_prnt[i + 1] = l; j = lzh_son[l]; lzh_son[l] = i; lzh_prnt[j] = c; if (j < LZH_T) lzh_prnt[j + 1] = c; lzh_son[c] = j; c = l; } } while ((c = lzh_prnt[c]) != 0); /* do it until reaching the root */ } uint16_t lzh_code, lzh_len; void lzh_encode_char(uint16_t c, uint8_t *outbuf, int32_t *outlen) { uint16_t i; int16_t j, k; i = 0; j = 0; k = lzh_prnt[c + LZH_T]; /* search connections from leaf node to the root */ do { i >>= 1; /* if node's address is odd, output 1 else output 0 */ if (k & 1) i += 0x8000; j++; } while ((k = lzh_prnt[k]) != LZH_R); lzh_putcode(j, i, outbuf, outlen); lzh_code = i; lzh_len = j; lzh_update(c); } void lzh_encode_position(uint16_t c, uint8_t *outbuf, int32_t *outlen) { uint16_t i; /* output upper 6 bits with encoding */ i = c >> 6; lzh_putcode(lzh_p_len[i], (uint16_t)(lzh_p_code[i] << 8), outbuf, outlen); /* output lower 6 bits directly */ lzh_putcode(6, (uint16_t)((c & 0x3f) << 10), outbuf, outlen); } void lzh_encode_end(uint8_t *outbuf, int32_t *outlen) { if (lzh_putlen) { outbuf[(*outlen)++]=(lzh_putbuf >> 8); } } int16_t lzh_decode_char(uint8_t *inbuf, int32_t *incnt, int32_t inlen) { uint16_t c; c = lzh_son[LZH_R]; /* * start searching tree from the root to leaves. * choose node #(lzh_son[]) if input bit == 0 * else choose #(lzh_son[]+1) (input bit == 1) */ while (c < LZH_T) { c += lzh_getbit(inbuf,incnt,inlen); c = lzh_son[c]; } c -= LZH_T; lzh_update(c); return c; } int16_t lzh_decode_position(uint8_t *inbuf, int32_t *incnt, int32_t inlen) { uint16_t i, j, c; /* decode upper 6 bits from given table */ i = lzh_getbyte(inbuf,incnt,inlen); c = (uint32_t)lzh_d_code[i] << 6; j = lzh_d_len[i]; /* input lower 6 bits directly */ j -= 2; while (j--) { i = (i << 1) + lzh_getbit(inbuf,incnt,inlen); } return c | (i & 0x3f); } /* Compression */ /* Encoding/Compressing */ /* Returns length of outbuf */ int32_t LZHCALL lzh_encode(uint8_t *inbuf, int32_t inlen, uint8_t *outbuf) { int16_t i, c, len, r, s, last_match_length; int32_t incnt, outlen; /* textsize=0; */ #ifdef LZH_DYNAMIC_BUF if((lzh_text_buf=(uint8_t *)MALLOC(LZH_N + LZH_F - 1))==NULL) return(-1); if((lzh_freq=(uint16_t *)MALLOC((LZH_T + 1)*sizeof(uint16_t)))==NULL) { FREE(lzh_text_buf); return(-1); } if((lzh_prnt=(int16_t *)MALLOC((LZH_T + LZH_N_CHAR)*sizeof(int16_t)))==NULL) { FREE(lzh_text_buf); FREE(lzh_freq); return(-1); } if((lzh_son=(int16_t *)MALLOC((LZH_T + 1) * sizeof(int16_t)))==NULL) { FREE(lzh_text_buf); FREE(lzh_prnt); FREE(lzh_freq); return(-1); } if((lzh_lson=(int16_t *)MALLOC((LZH_N + 1)*sizeof(int16_t)))==NULL) { FREE(lzh_text_buf); FREE(lzh_prnt); FREE(lzh_freq); FREE(lzh_son); return(-1); } if((lzh_rson=(int16_t *)MALLOC((LZH_N + 257)*sizeof(int16_t)))==NULL) { FREE(lzh_text_buf); FREE(lzh_prnt); FREE(lzh_freq); FREE(lzh_son); FREE(lzh_lson); return(-1); } if((lzh_dad=(int16_t *)MALLOC((LZH_N + 1)*sizeof(int16_t)))==NULL) { FREE(lzh_text_buf); FREE(lzh_prnt); FREE(lzh_freq); FREE(lzh_son); FREE(lzh_lson); FREE(lzh_rson); return(-1); } #endif incnt=0; memcpy(outbuf,&inlen,sizeof(inlen)); outlen=sizeof(inlen); if(!inlen) { #ifdef LZH_DYNAMIC_BUF FREE(lzh_text_buf); FREE(lzh_prnt); FREE(lzh_freq); FREE(lzh_son); FREE(lzh_lson); FREE(lzh_rson); FREE(lzh_dad); #endif return(outlen); } lzh_start_huff(); lzh_init_tree(); s = 0; r = LZH_N - LZH_F; for (i = s; i < r; i++) lzh_text_buf[i] = ' '; for (len = 0; len < LZH_F && incnt len) lzh_match_length = len; if (lzh_match_length <= LZH_THRESHOLD) { lzh_match_length = 1; lzh_encode_char(lzh_text_buf[r],outbuf,&outlen); } else { lzh_encode_char((uint16_t)(255 - LZH_THRESHOLD + lzh_match_length) ,outbuf,&outlen); lzh_encode_position(lzh_match_position ,outbuf,&outlen); } last_match_length = lzh_match_length; for (i = 0; i < last_match_length && incnt printcount) { printf("%12ld\r", textsize); printcount += 1024; } ***/ while (i++ < last_match_length) { lzh_delete_node(s); s = (s + 1) & (LZH_N - 1); r = (r + 1) & (LZH_N - 1); if (--len) lzh_insert_node(r); } } while (len > 0); lzh_encode_end(outbuf,&outlen); /* printf("input: %ld (%ld) bytes\n", inlen,textsize); printf("output: %ld bytes\n", outlen); printf("output/input: %.3f\n", (double)outlen / inlen); */ #ifdef LZH_DYNAMIC_BUF FREE(lzh_text_buf); FREE(lzh_prnt); FREE(lzh_freq); FREE(lzh_son); FREE(lzh_lson); FREE(lzh_rson); FREE(lzh_dad); #endif return(outlen); } /* Decoding/Uncompressing */ /* Returns length of outbuf */ int32_t LZHCALL lzh_decode(uint8_t *inbuf, int32_t inlen, uint8_t *outbuf) { int16_t i, j, k, r, c; uint32_t count; int32_t incnt, textsize; #ifdef LZH_DYNAMIC_BUF if((lzh_text_buf=(uint8_t *)MALLOC((LZH_N + LZH_F - 1)*2))==NULL) return(-1); if((lzh_freq=(uint16_t *)MALLOC((LZH_T + 1)*sizeof(uint16_t))) ==NULL) { FREE(lzh_text_buf); return(-1); } if((lzh_prnt=(int16_t *)MALLOC((LZH_T + LZH_N_CHAR)*sizeof(int16_t)))==NULL) { FREE(lzh_text_buf); FREE(lzh_freq); return(-1); } if((lzh_son=(int16_t *)MALLOC((LZH_T + 1) * sizeof(int16_t)))==NULL) { FREE(lzh_text_buf); FREE(lzh_prnt); FREE(lzh_freq); return(-1); } #endif incnt=0; memcpy(&textsize,inbuf,sizeof(textsize)); incnt+=sizeof(textsize); if (textsize == 0) { #ifdef LZH_DYNAMIC_BUF FREE(lzh_text_buf); FREE(lzh_prnt); FREE(lzh_freq); FREE(lzh_son); #endif return(textsize); } lzh_start_huff(); for (i = 0; i < LZH_N - LZH_F; i++) *(lzh_text_buf+i) = ' '; r = LZH_N - LZH_F; for (count = 0; count < (uint32_t)textsize; ) { c = lzh_decode_char(inbuf,&incnt,inlen); if (c < 256) { outbuf[count]=(uint8_t)c; #if 0 if(r>(LZH_N + LZH_F - 1) || r<0) { printf("Overflow! (%d)\n",r); getch(); exit(-1); } #endif *(lzh_text_buf+r) = (uint8_t)c; r++; r &= (LZH_N - 1); count++; } else { i = (r - lzh_decode_position(inbuf,&incnt,inlen) - 1) & (LZH_N - 1); j = c - 255 + LZH_THRESHOLD; for (k = 0; k < j && count<(uint32_t)textsize; k++) { c = lzh_text_buf[(i + k) & (LZH_N - 1)]; outbuf[count]=(uint8_t)c; #if 0 if(r>(LZH_N + LZH_F - 1) || r<0) { printf("Overflow! (%d)\n",r); exit(-1); } #endif *(lzh_text_buf+r) = (uint8_t)c; r++; r &= (LZH_N - 1); count++; } } } /*** printf("%12ld\n", count); ***/ #ifdef LZH_DYNAMIC_BUF FREE(lzh_text_buf); FREE(lzh_prnt); FREE(lzh_freq); FREE(lzh_son); #endif return(count); }