// This may look like C code, but it is really -*- C++ -*- // ------------------------------------------------------------------ // The Goldware Library // Copyright (C) 2000 Alex. S. Aganichev // ------------------------------------------------------------------ // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this program; if not, write to the Free // Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, // MA 02111-1307, USA // ------------------------------------------------------------------ // $Id$ // ------------------------------------------------------------------ // Digital Dynamics 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 // ------------------------------------------------------------------ #include #include #include #include // ------------------------------------------------------------------ // 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 static char lzh_text_buf[LZH_N + LZH_F - 1]; static short int lzh_match_position, lzh_match_length, lzh_lson[LZH_N + 1], lzh_rson[LZH_N + 257], lzh_dad[LZH_N + 1]; // ------------------------------------------------------------------ // Initializing tree static void glzh_init_tree(void) { short int 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 static void glzh_insert_node(short int r) { short int i, p, cmp; char *key; unsigned 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) < 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 } // ------------------------------------------------------------------ // Deleting node from the tree static void glzh_delete_node(short int p) { short int 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 // character code (= 0..LZH_N_CHAR-1) #define LZH_N_CHAR (256 - LZH_THRESHOLD + LZH_F) // Size of table #define LZH_T (LZH_N_CHAR * 2 - 1) // root position #define LZH_R (LZH_T - 1) // update when cumulative frequency reaches to this value #define MAX_FREQ 0x8000 // ------------------------------------------------------------------ // Tables for encoding/decoding upper 6 bits of sliding dictionary pointer // ------------------------------------------------------------------ // encoder table static char 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 }; static char 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 static char 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, }; static char 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, }; // ------------------------------------------------------------------ static unsigned short lzh_freq[LZH_T + 1]; // cumulative freq table static short int lzh_prnt[LZH_T + LZH_N_CHAR]; static short int lzh_son[LZH_T + 1]; static unsigned short lzh_getbuf = 0; static char lzh_getlen = 0; // ------------------------------------------------------------------ // get one bit static int glzh_getbit(char *inbuf, long *incnt, long inlen) { short int 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); } // ------------------------------------------------------------------ // get a byte static short int glzh_getbyte(char *inbuf, long *incnt, long inlen) { unsigned short 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; } // ------------------------------------------------------------------ static unsigned lzh_putbuf = 0; static char lzh_putlen = 0; // ------------------------------------------------------------------ // output c bits static void glzh_putcode(short int l, unsigned short c, char *outbuf, long *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 static void glzh_start_huff() { short int i, j; lzh_getbuf = 0; 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 static void glzh_reconst() { short int i, j, k; unsigned short 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; memmove(lzh_freq+k+1, lzh_freq+k, l); lzh_freq[k] = f; 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 static void glzh_update(short int c) { short int i, j, k, l; if (lzh_freq[LZH_R] == MAX_FREQ) glzh_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 } // ------------------------------------------------------------------ static unsigned short lzh_code, lzh_len; // ------------------------------------------------------------------ static void glzh_encode_char(unsigned short c, char *outbuf, long *outlen) { unsigned short i; short int 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); glzh_putcode(j, i, outbuf, outlen); lzh_code = i; lzh_len = j; glzh_update(c); } // ------------------------------------------------------------------ static void glzh_encode_position(unsigned short c, char *outbuf, long *outlen) { unsigned short i; // output upper 6 bits with encoding i = c >> 6; glzh_putcode(lzh_p_len[i], (unsigned)lzh_p_code[i] << 8, outbuf, outlen); // output lower 6 bits directly glzh_putcode(6, (c & 0x3f) << 10, outbuf, outlen); } // ------------------------------------------------------------------ static void glzh_encode_end(char *outbuf, long *outlen) { if(lzh_putlen) outbuf[(*outlen)++]=(lzh_putbuf >> 8); } // ------------------------------------------------------------------ static short int glzh_decode_char(char *inbuf, long *incnt, long inlen) { unsigned short 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 += glzh_getbit(inbuf,incnt,inlen); c = lzh_son[c]; } c -= LZH_T; glzh_update(c); return c; } // ------------------------------------------------------------------ static short int glzh_decode_position(char *inbuf, long *incnt, long inlen) { unsigned short i, j, c; // decode upper 6 bits from given table i = glzh_getbyte(inbuf,incnt,inlen); c = (unsigned)lzh_d_code[i] << 6; j = lzh_d_len[i]; // input lower 6 bits directly j -= 2; while(j--) i = (i << 1) + glzh_getbit(inbuf,incnt,inlen); return c | i & 0x3f; } // ------------------------------------------------------------------ // Encoding/Compressing: returns length of outbuf long glzh_encode(char *inbuf, long inlen, char *outbuf) { short int i, c, len, r, s, last_match_length; long incnt,outlen; // textsize=0; incnt=0; memcpy(outbuf,&inlen,sizeof(inlen)); outlen=sizeof(inlen); if(not inlen) { return(outlen); } glzh_start_huff(); glzh_init_tree(); s = 0; r = LZH_N - LZH_F; for(i = s; i < r; i++) lzh_text_buf[i] = ' '; for(len = 0; len len) lzh_match_length = len; if(lzh_match_length <= LZH_THRESHOLD) { lzh_match_length = 1; glzh_encode_char(lzh_text_buf[r],outbuf,&outlen); } else { glzh_encode_char(255 - LZH_THRESHOLD + lzh_match_length, outbuf, &outlen); glzh_encode_position(lzh_match_position, outbuf, &outlen); } last_match_length = lzh_match_length; for(i = 0; i 0); glzh_encode_end(outbuf, &outlen); return(outlen); } // ------------------------------------------------------------------ // Decoding/Uncompressing: returns length of outbuf long glzh_decode(char *inbuf, long inlen, char *outbuf) { short int i, j, k, r, c; unsigned long int count; long incnt,textsize; incnt=0; memcpy(&textsize, inbuf, sizeof(textsize)); incnt+=sizeof(textsize); if(textsize == 0) { return(textsize); } glzh_start_huff(); for(i = 0; i < LZH_N - LZH_F; i++) *(lzh_text_buf+i) = ' '; r = LZH_N - LZH_F; for(count = 0; count < textsize; ) { c = glzh_decode_char(inbuf,&incnt,inlen); if(c < 256) { outbuf[count]=c; *(lzh_text_buf+r) = c; r++; r &= (LZH_N - 1); count++; } else { i = (r - glzh_decode_position(inbuf,&incnt,inlen) - 1) & (LZH_N - 1); j = c - 255 + LZH_THRESHOLD; for (k = 0; k < j && count