1 
2 /*
3  *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
4  *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
5  *
6  *     Lempel-Ziv-Huffman decompression functions used in Heavy 1 & 2
7  *     compression modes. Based on LZH decompression functions from
8  *     UNIX LHA made by Masaru Oki
9  *
10  */
11 
12 
13 #include "cdata.h"
14 #include "u_heavy.h"
15 #include "getbits.h"
16 #include "maketbl.h"
17 
18 
19 #define NC 510
20 #define NPT 20
21 #define N1 510
22 #define OFFSET 253
23 
24 USHORT dms_left[2 * NC - 1], dms_right[2 * NC - 1 + 9];
25 static UCHAR c_len[NC], pt_len[NPT];
26 static USHORT c_table[4096], pt_table[256];
27 USHORT dms_lastlen, dms_np;
28 USHORT dms_heavy_text_loc;
29 
30 
31 static USHORT read_tree_c(void);
32 static USHORT read_tree_p(void);
33 USHORT decode_c(void);
34 USHORT decode_p(void);
35 
36 
37 
Unpack_HEAVY(UCHAR * in,UCHAR * out,UCHAR flags,USHORT origsize)38 USHORT Unpack_HEAVY(UCHAR *in, UCHAR *out, UCHAR flags, USHORT origsize){
39 	USHORT j, i, c, bitmask;
40 	UCHAR *outend;
41 
42 	/*  Heavy 1 uses a 4Kb dictionary,  Heavy 2 uses 8Kb  */
43 
44 	if (flags & 8) {
45 		dms_np = 15;
46 		bitmask = 0x1fff;
47 	} else {
48 		dms_np = 14;
49 		bitmask = 0x0fff;
50 	}
51 
52 	initbitbuf(in);
53 
54 	if (flags & 2) {
55 		if (read_tree_c()) return 1;
56 		if (read_tree_p()) return 2;
57 	}
58 
59 	outend = out+origsize;
60 
61 	while (out<outend) {
62 		c = decode_c();
63 		if (c < 256) {
64 			*out++ = dms_text[dms_heavy_text_loc++ & bitmask] = (UCHAR)c;
65 		} else {
66 			j = (USHORT) (c - OFFSET);
67 			i = (USHORT) (dms_heavy_text_loc - decode_p() - 1);
68 			while(j--) *out++ = dms_text[dms_heavy_text_loc++ & bitmask] = dms_text[i++ & bitmask];
69 		}
70 	}
71 
72 	return 0;
73 }
74 
75 
76 
decode_c(void)77 INLINE USHORT decode_c(void){
78 	USHORT i, j, m;
79 
80 	j = c_table[GETBITS(12)];
81 	if (j < N1) {
82 		DROPBITS(c_len[j]);
83 	} else {
84 		DROPBITS(12);
85 		i = GETBITS(16);
86 		m = 0x8000;
87 		do {
88 			if (i & m) j = dms_right[j];
89 			else              j = dms_left [j];
90 			m >>= 1;
91 		} while (j >= N1);
92 		DROPBITS(c_len[j] - 12);
93 	}
94 	return j;
95 }
96 
97 
98 
decode_p(void)99 INLINE USHORT decode_p(void){
100 	USHORT i, j, m;
101 
102 	j = pt_table[GETBITS(8)];
103 	if (j < dms_np) {
104 		DROPBITS(pt_len[j]);
105 	} else {
106 		DROPBITS(8);
107 		i = GETBITS(16);
108 		m = 0x8000;
109 		do {
110 			if (i & m) j = dms_right[j];
111 			else             j = dms_left [j];
112 			m >>= 1;
113 		} while (j >= dms_np);
114 		DROPBITS(pt_len[j] - 8);
115 	}
116 
117 	if (j != dms_np-1) {
118 		if (j > 0) {
119 			j = (USHORT)(GETBITS(i=(USHORT)(j-1)) | (1U << (j-1)));
120 			DROPBITS(i);
121 		}
122 		dms_lastlen=j;
123 	}
124 
125 	return dms_lastlen;
126 
127 }
128 
129 
130 
read_tree_c(void)131 static USHORT read_tree_c(void){
132 	USHORT i,n;
133 
134 	n = GETBITS(9);
135 	DROPBITS(9);
136 	if (n>0){
137 		for (i=0; i<n; i++) {
138 			c_len[i] = (UCHAR)GETBITS(5);
139 			DROPBITS(5);
140 		}
141 		for (i=n; i<510; i++) c_len[i] = 0;
142 		if (dms_make_table(510,c_len,12,c_table)) return 1;
143 	} else {
144 		n = GETBITS(9);
145 		DROPBITS(9);
146 		for (i=0; i<510; i++) c_len[i] = 0;
147 		for (i=0; i<4096; i++) c_table[i] = n;
148 	}
149 	return 0;
150 }
151 
152 
153 
read_tree_p(void)154 static USHORT read_tree_p(void){
155 	USHORT i,n;
156 
157 	n = GETBITS(5);
158 	DROPBITS(5);
159 	if (n>0){
160 		for (i=0; i<n; i++) {
161 			pt_len[i] = (UCHAR)GETBITS(4);
162 			DROPBITS(4);
163 		}
164 		for (i=n; i<dms_np; i++) pt_len[i] = 0;
165 		if (dms_make_table(dms_np,pt_len,8,pt_table)) return 1;
166 	} else {
167 		n = GETBITS(5);
168 		DROPBITS(5);
169 		for (i=0; i<dms_np; i++) pt_len[i] = 0;
170 		for (i=0; i<256; i++) pt_table[i] = n;
171 	}
172 	return 0;
173 }
174 
175 
176