/* * xDMS v1.3 - Portable DMS archive unpacker - Public Domain * Written by Andre Rodrigues de la Rocha * * Lempel-Ziv-DynamicHuffman decompression functions used in Deep * mode. * Most routines ripped from LZHUF written by Haruyasu Yoshizaki * */ #include #include "cdata.h" #include "tables.h" #include "u_deep.h" #include "getbits.h" INLINE USHORT DecodeChar(void); INLINE USHORT DecodePosition(void); INLINE void update(USHORT c); static void reconst(void); USHORT deep_text_loc; int init_deep_tabs=1; #define DBITMASK 0x3fff /* uses 16Kb dictionary */ #define F 60 /* lookahead buffer size */ #define THRESHOLD 2 #define N_CHAR (256 - THRESHOLD + F) /* kinds of characters (character code = 0..N_CHAR-1) */ #define T (N_CHAR * 2 - 1) /* size of table */ #define R (T - 1) /* position of root */ #define MAX_FREQ 0x8000 /* updates tree when the */ USHORT freq[T + 1]; /* frequency table */ USHORT prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */ /* elements [T..T + N_CHAR - 1] which are used to get */ /* the positions of leaves corresponding to the codes. */ USHORT son[T]; /* pointers to child nodes (son[], son[] + 1) */ void Init_DEEP_Tabs(void){ USHORT i, j; for (i = 0; i < N_CHAR; i++) { freq[i] = 1; son[i] = (USHORT)(i + T); prnt[i + T] = i; } i = 0; j = N_CHAR; while (j <= R) { freq[j] = (USHORT) (freq[i] + freq[i + 1]); son[j] = i; prnt[i] = prnt[i + 1] = j; i += 2; j++; } freq[T] = 0xffff; prnt[R] = 0; init_deep_tabs = 0; } USHORT Unpack_DEEP(UCHAR *in, UCHAR *out, USHORT origsize){ USHORT i, j, c; UCHAR *outend; initbitbuf(in); if (init_deep_tabs) Init_DEEP_Tabs(); outend = out+origsize; while (out < outend) { c = DecodeChar(); if (c < 256) { *out++ = text[deep_text_loc++ & DBITMASK] = (UCHAR)c; } else { j = (USHORT) (c - 255 + THRESHOLD); i = (USHORT) (deep_text_loc - DecodePosition() - 1); while (j--) *out++ = text[deep_text_loc++ & DBITMASK] = text[i++ & DBITMASK]; } } deep_text_loc = (USHORT)((deep_text_loc+60) & DBITMASK); return 0; } INLINE USHORT DecodeChar(void){ USHORT c; c = son[R]; /* travel from root to leaf, */ /* choosing the smaller child node (son[]) if the read bit is 0, */ /* the bigger (son[]+1} if 1 */ while (c < T) { c = son[c + GETBITS(1)]; DROPBITS(1); } c -= T; update(c); return c; } INLINE USHORT DecodePosition(void){ USHORT i, j, c; i = GETBITS(8); DROPBITS(8); c = (USHORT) (d_code[i] << 8); j = d_len[i]; i = (USHORT) (((i << j) | GETBITS(j)) & 0xff); DROPBITS(j); return (USHORT) (c | i) ; } /* reconstruction of tree */ static void reconst(void){ USHORT i, j, k, f, l; /* collect leaf nodes in the first half of the table */ /* and replace the freq by (freq + 1) / 2. */ j = 0; for (i = 0; i < T; i++) { if (son[i] >= T) { freq[j] = (USHORT) ((freq[i] + 1) / 2); son[j] = son[i]; j++; } } /* begin constructing tree by connecting sons */ for (i = 0, j = N_CHAR; j < T; i += 2, j++) { k = (USHORT) (i + 1); f = freq[j] = (USHORT) (freq[i] + freq[k]); for (k = (USHORT)(j - 1); f < freq[k]; k--); k++; l = (USHORT)((j - k) * 2); memmove(&freq[k + 1], &freq[k], (size_t)l); freq[k] = f; memmove(&son[k + 1], &son[k], (size_t)l); son[k] = i; } /* connect prnt */ for (i = 0; i < T; i++) { if ((k = son[i]) >= T) { prnt[k] = i; } else { prnt[k] = prnt[k + 1] = i; } } } /* increment frequency of given code by one, and update tree */ INLINE void update(USHORT c){ USHORT i, j, k, l; if (freq[R] == MAX_FREQ) { reconst(); } c = prnt[c + T]; do { k = ++freq[c]; /* if the order is disturbed, exchange nodes */ if (k > freq[l = (USHORT)(c + 1)]) { while (k > freq[++l]); l--; freq[c] = freq[l]; freq[l] = k; i = son[c]; prnt[i] = l; if (i < T) prnt[i + 1] = l; j = son[l]; son[l] = i; prnt[j] = c; if (j < T) prnt[j + 1] = c; son[c] = j; c = l; } } while ((c = prnt[c]) != 0); /* repeat up to root */ }