Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
716 | lvd | 1 | #include "std.h" |
2 | |||
3 | #include "emul.h" |
||
4 | #include "vars.h" |
||
5 | #include "wd93crc.h" |
||
6 | |||
7 | #include "util.h" |
||
8 | |||
9 | int FDD::write_td0(FILE *ff) |
||
10 | { |
||
11 | unsigned char zerosec[256] = { 0 }; |
||
12 | unsigned char td0hdr[12] = { 0 }; |
||
13 | |||
14 | *(unsigned short*)td0hdr = WORD2('T','D'); |
||
15 | td0hdr[4] = 21; td0hdr[6] = 2; td0hdr[9] = (unsigned char)sides; |
||
16 | if (*dsc) td0hdr[7] = 0x80; |
||
17 | *(unsigned short*)(td0hdr + 10) = crc16(td0hdr, 10); |
||
18 | fwrite(td0hdr, 1, 12, ff); |
||
19 | if (*dsc) { |
||
20 | unsigned char inf[0x200] = { 0 }; |
||
21 | strcpy((char*)inf+10, dsc); |
||
784 | DimkaM | 22 | unsigned len = unsigned(strlen(dsc)+1); |
716 | lvd | 23 | *(unsigned*)(inf+2) = len; |
24 | *(unsigned short*)inf = crc16(inf+2, len+8); |
||
25 | fwrite(inf, 1, len+10, ff); |
||
26 | } |
||
27 | |||
28 | unsigned c; //Alone Coder 0.36.7 |
||
29 | for (/*unsigned*/ c = 0; c < cyls; c++) |
||
30 | for (unsigned s = 0; s < sides; s++) { |
||
31 | t.seek(this,c,s,LOAD_SECTORS); |
||
32 | unsigned char bf[16]; |
||
784 | DimkaM | 33 | *bf = u8(t.s); |
34 | bf[1] = u8(c); bf[2] = u8(s); |
||
716 | lvd | 35 | bf[3] = (unsigned char)crc16(bf, 3); |
36 | fwrite(bf, 1, 4, ff); |
||
37 | for (unsigned sec = 0; sec < t.s; sec++) { |
||
784 | DimkaM | 38 | if(!t.hdr[sec].data) |
39 | { |
||
40 | t.hdr[sec].data = zerosec; |
||
41 | t.hdr[sec].datlen = 256; |
||
42 | t.hdr[sec].l = 1; |
||
43 | } |
||
716 | lvd | 44 | *(unsigned*)bf = *(unsigned*)&t.hdr[sec]; |
45 | bf[4] = 0; // flags |
||
46 | bf[5] = (unsigned char)crc16(t.hdr[sec].data, t.hdr[sec].datlen); |
||
784 | DimkaM | 47 | *(unsigned short*)(bf+6) = u16(t.hdr[sec].datlen + 1); |
716 | lvd | 48 | bf[8] = 0; // compression type = none |
49 | fwrite(bf, 1, 9, ff); |
||
50 | if (fwrite(t.hdr[sec].data, 1, t.hdr[sec].datlen, ff) != t.hdr[sec].datlen) return 0; |
||
51 | } |
||
52 | } |
||
53 | c = WORD4(0xFF,0,0,0); |
||
54 | if (fwrite(&c, 1, 4, ff) != 4) return 0; |
||
55 | return 1; |
||
56 | } |
||
57 | |||
58 | |||
59 | unsigned unpack_lzh(unsigned char *src, unsigned size, unsigned char *buf); |
||
60 | |||
61 | // No ID address field was present for this sector, |
||
62 | // but there is a data field. The sector information in |
||
63 | // the header represents fabricated information. |
||
64 | const ULONG TD0_SEC_NO_ID = 0x40; |
||
65 | |||
66 | // This sector's data field is missing; no sector data follows this header. |
||
67 | const ULONG TD0_SEC_NO_DATA = 0x20; |
||
68 | |||
69 | // A DOS sector copy was requested; this sector was not allocated. |
||
70 | // In this case, no sector data follows this header. |
||
71 | const ULONG TD0_SEC_NO_DATA2 = 0x10; |
||
72 | |||
73 | #pragma pack(push, 1) |
||
74 | struct TTd0Sec |
||
75 | { |
||
76 | u8 c; |
||
77 | u8 h; |
||
78 | u8 s; |
||
79 | u8 n; |
||
80 | u8 flags; |
||
81 | u8 crc; |
||
82 | }; |
||
83 | #pragma pack(pop) |
||
84 | |||
85 | int FDD::read_td0() |
||
86 | { |
||
87 | if (*(short*)snbuf == WORD2('t','d')) |
||
88 | { // packed disk |
||
89 | unsigned char *tmp = (unsigned char*)malloc(snapsize); |
||
90 | memcpy(tmp, snbuf+12, snapsize-12); |
||
91 | snapsize = 12+unpack_lzh(tmp, snapsize-12, snbuf+12); |
||
92 | ::free(tmp); |
||
93 | //*(short*)snbuf = WORD2('T','D'); |
||
94 | } |
||
95 | |||
96 | char dscbuffer[sizeof(dsc)]; |
||
97 | *dscbuffer = 0; |
||
98 | |||
99 | unsigned char *start = snbuf+12; |
||
100 | if (snbuf[7] & 0x80) // coment record |
||
101 | { |
||
102 | start += 10; |
||
103 | unsigned len = *(unsigned short*)(snbuf+14); |
||
104 | start += len; |
||
105 | if (len >= sizeof dsc) |
||
106 | len = sizeof(dsc)-1; |
||
107 | memcpy(dscbuffer, snbuf+12+10, len); |
||
108 | dscbuffer[len] = 0; |
||
109 | } |
||
110 | unsigned char *td0_src = start; |
||
111 | |||
112 | unsigned sides = (snbuf[9] == 1 ? 1 : 2); |
||
113 | unsigned max_cyl = 0; |
||
114 | |||
115 | for (;;) |
||
116 | { |
||
117 | unsigned char s = *td0_src; // Sectors |
||
118 | if (s == 0xFF) |
||
119 | break; |
||
120 | max_cyl = max(max_cyl, unsigned(td0_src[1])); // PhysTrack |
||
121 | td0_src += 4; // sizeof(track_rec) |
||
122 | for (; s; s--) |
||
123 | { |
||
124 | unsigned char flags = td0_src[4]; |
||
125 | td0_src += 6; // sizeof(sec_rec) |
||
126 | |||
127 | assert(td0_src <= snbuf + snapsize); |
||
128 | |||
129 | if (td0_src > snbuf + snapsize) |
||
130 | return 0; |
||
131 | td0_src += *(unsigned short*)td0_src + 2; // data_len |
||
132 | } |
||
133 | } |
||
134 | |||
135 | if(max_cyl+1 > MAX_CYLS) |
||
136 | { |
||
137 | err_printf("cylinders (%d) > MAX_CYLS(%d)", max_cyl, MAX_CYLS); |
||
138 | return 0; |
||
139 | } |
||
140 | |||
141 | newdisk(max_cyl+1, sides); |
||
142 | memcpy(dsc, dscbuffer, sizeof dsc); |
||
143 | |||
144 | td0_src = start; |
||
145 | for (;;) |
||
146 | { |
||
147 | unsigned char t0[16384]; |
||
148 | unsigned char *dst = t0; |
||
149 | unsigned char *trkh = td0_src; |
||
150 | td0_src += 4; // sizeof(track_rec) |
||
151 | |||
152 | if(*trkh == 0xFF) |
||
153 | break; |
||
154 | |||
155 | t.seek(this, trkh[1], trkh[2], JUST_SEEK); |
||
156 | |||
157 | unsigned s = 0; |
||
158 | for (unsigned se = 0; se < trkh[0]; se++) |
||
159 | { |
||
160 | TTd0Sec *SecHdr = (TTd0Sec *)td0_src; |
||
161 | unsigned sec_size = 128U << (SecHdr->n & 3); // [vv] |
||
162 | unsigned char flags = SecHdr->flags; |
||
163 | // printf("fl=%x\n", flags); |
||
164 | // printf("c=%d, h=%d, s=%d, n=%d\n", SecHdr->c, SecHdr->h, SecHdr->s, SecHdr->n); |
||
165 | if(flags & (TD0_SEC_NO_ID | TD0_SEC_NO_DATA | TD0_SEC_NO_DATA2)) // skip sectors with no data & sectors without headers |
||
166 | { |
||
167 | td0_src += sizeof(TTd0Sec); // sizeof(sec_rec) |
||
168 | |||
169 | unsigned src_size = *(unsigned short*)td0_src; |
||
170 | // printf("sz=%d\n", src_size); |
||
171 | td0_src += 2; // data_len |
||
172 | unsigned char *end_packed_data = td0_src + src_size; |
||
173 | /* |
||
174 | u8 method = *td0_src++; |
||
175 | printf("m=%d\n", method); |
||
176 | switch(method) |
||
177 | { |
||
178 | case 0: |
||
179 | { |
||
180 | char name[MAX_PATH]; |
||
181 | sprintf(name, "%02d-%d-%03d-%d.trk", SecHdr->c, SecHdr->h, SecHdr->s, SecHdr->n); |
||
182 | FILE *f = fopen(name, "wb"); |
||
183 | fwrite(td0_src, 1, src_size - 1, f); |
||
184 | fclose(f); |
||
185 | break; |
||
186 | } |
||
187 | case 1: |
||
188 | { |
||
189 | unsigned n = *(unsigned short*)td0_src; |
||
190 | td0_src += 2; |
||
191 | unsigned short data = *(unsigned short*)td0_src; |
||
192 | printf("len=%d, data=%04X\n", n, data); |
||
193 | break; |
||
194 | } |
||
195 | } |
||
196 | */ |
||
197 | td0_src = end_packed_data; |
||
198 | continue; |
||
199 | } |
||
200 | |||
201 | // c, h, s, n |
||
202 | t.hdr[s].c = SecHdr->c; |
||
203 | t.hdr[s].s = SecHdr->h; |
||
204 | t.hdr[s].n = SecHdr->s; |
||
205 | t.hdr[s].l = SecHdr->n; |
||
206 | t.hdr[s].c1 = t.hdr[s].c2 = 0; |
||
207 | t.hdr[s].data = dst; |
||
800 | DimkaM | 208 | t.hdr[s].datlen = 0; |
716 | lvd | 209 | |
210 | td0_src += sizeof(TTd0Sec); // sizeof(sec_rec) |
||
211 | |||
212 | unsigned src_size = *(unsigned short*)td0_src; |
||
213 | td0_src += 2; // data_len |
||
214 | unsigned char *end_packed_data = td0_src + src_size; |
||
215 | |||
784 | DimkaM | 216 | if(src_size == 0) |
217 | { |
||
218 | printf("sector data size is zero\n"); |
||
219 | goto shit; |
||
220 | } |
||
221 | |||
222 | if(src_size > sec_size + 1) |
||
223 | { |
||
224 | printf("sector overflow: src_size=%u > (sec_size+1)=%u\n", src_size, sec_size + 1); |
||
225 | goto shit; |
||
226 | } |
||
227 | |||
716 | lvd | 228 | memset(dst, 0, sec_size); |
229 | |||
230 | switch (*td0_src++) // Method |
||
231 | { |
||
232 | case 0: // raw sector |
||
233 | memcpy(dst, td0_src, src_size-1); |
||
234 | break; |
||
235 | case 1: // repeated 2-byte pattern |
||
236 | { |
||
237 | unsigned n = *(unsigned short*)td0_src; |
||
238 | td0_src += 2; |
||
239 | unsigned short data = *(unsigned short*)td0_src; |
||
240 | for (unsigned i = 0; i < n; i++) |
||
241 | *(unsigned short*)(dst+2*i) = data; |
||
242 | break; |
||
243 | } |
||
244 | case 2: // RLE block |
||
245 | { |
||
784 | DimkaM | 246 | u8 n; |
716 | lvd | 247 | unsigned char *d0 = dst; |
248 | do |
||
249 | { |
||
784 | DimkaM | 250 | u8 RleData[510]; |
251 | u8 l = 2 * (*td0_src++); |
||
252 | if(l == 0) // Zero count means a literal data block |
||
716 | lvd | 253 | { |
784 | DimkaM | 254 | n = *td0_src++; |
255 | if(dst + n > d0 + sec_size) |
||
256 | { |
||
257 | printf("sector overflow: pos=0x%x, l=%u, n=%u, sec_size=%u, src_size=%u\n", |
||
258 | unsigned(td0_src - 2 - snbuf), unsigned(l), unsigned(n), sec_size, src_size); |
||
259 | goto shit; |
||
260 | } |
||
261 | memcpy(dst, td0_src, n); |
||
262 | td0_src += n; |
||
263 | dst += n; |
||
716 | lvd | 264 | } |
784 | DimkaM | 265 | else // repeated fragment |
266 | { |
||
267 | n = *td0_src++; |
||
268 | memcpy(RleData, td0_src, l); |
||
269 | td0_src += l; |
||
270 | for ( ; n; n--) |
||
271 | { |
||
272 | if(dst + l > d0 + sec_size) |
||
273 | { |
||
274 | printf("sector overflow: pos=0x%x, dpos=0x%x, l=%u, sec_size=%u, src_size=%u\n", |
||
275 | unsigned(td0_src - 2 - snbuf), unsigned((dst + l) - d0), unsigned(l), sec_size, src_size); |
||
276 | goto shit; |
||
277 | } |
||
278 | memcpy(dst, RleData, l); |
||
279 | dst += l; |
||
280 | } |
||
281 | } |
||
716 | lvd | 282 | } while (td0_src < end_packed_data); |
283 | dst = d0; |
||
284 | break; |
||
285 | } |
||
286 | default: // error! |
||
287 | errmsg("unknown block type"); |
||
288 | |||
289 | shit: |
||
290 | errmsg("bad TD0 file"); |
||
291 | return 0; |
||
292 | } |
||
293 | dst += sec_size; |
||
294 | td0_src = end_packed_data; |
||
295 | s++; |
||
296 | } |
||
297 | t.s = s; |
||
298 | t.format(); |
||
299 | } |
||
300 | return 1; |
||
301 | } |
||
302 | |||
303 | // ------------------------------------------------------ LZH unpacker |
||
304 | |||
305 | |||
784 | DimkaM | 306 | static unsigned char *packed_ptr, *packed_end; |
716 | lvd | 307 | |
784 | DimkaM | 308 | static unsigned readChar() |
716 | lvd | 309 | { |
784 | DimkaM | 310 | if(packed_ptr < packed_end) |
311 | { |
||
312 | return *packed_ptr++; |
||
313 | } |
||
314 | else |
||
315 | { |
||
316 | return -1U; |
||
317 | } |
||
716 | lvd | 318 | } |
319 | |||
784 | DimkaM | 320 | static unsigned char d_code[256] = |
716 | lvd | 321 | { |
322 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
323 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
324 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
325 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
326 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
||
327 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
||
328 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, |
||
329 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, |
||
330 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
||
331 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
||
332 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, |
||
333 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, |
||
334 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, |
||
335 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, |
||
336 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
||
337 | 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, |
||
338 | 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, |
||
339 | 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, |
||
340 | 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, |
||
341 | 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, |
||
342 | 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, |
||
343 | 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, |
||
344 | 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, |
||
345 | 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, |
||
346 | 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, |
||
347 | 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, |
||
348 | 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, |
||
349 | 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, |
||
350 | 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, |
||
351 | 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, |
||
352 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, |
||
353 | 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, |
||
354 | }; |
||
355 | |||
784 | DimkaM | 356 | static unsigned char d_len[256] = |
716 | lvd | 357 | { |
358 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
||
359 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
||
360 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
||
361 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
||
362 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, |
||
363 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, |
||
364 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, |
||
365 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, |
||
366 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, |
||
367 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, |
||
368 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, |
||
369 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, |
||
370 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, |
||
371 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, |
||
372 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, |
||
373 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, |
||
374 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, |
||
375 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, |
||
376 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, |
||
377 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, |
||
378 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, |
||
379 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, |
||
380 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, |
||
381 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, |
||
382 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, |
||
383 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, |
||
384 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, |
||
385 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, |
||
386 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, |
||
387 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, |
||
388 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
||
389 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
||
390 | }; |
||
391 | |||
392 | |||
393 | const int N = 4096; // buffer size |
||
394 | const int F = 60; // lookahead buffer size |
||
395 | const int THRESHOLD = 2; |
||
396 | const int NIL = N; // leaf of tree |
||
397 | |||
784 | DimkaM | 398 | static unsigned char text_buf[N + F - 1]; |
716 | lvd | 399 | |
400 | const int N_CHAR = (256 - THRESHOLD + F); // kinds of characters (character code = 0..N_CHAR-1) |
||
401 | const int T = (N_CHAR * 2 - 1); // size of table |
||
402 | const int R = (T - 1); // position of root |
||
403 | const int MAX_FREQ = 0x8000; // updates tree when the |
||
404 | // root frequency comes to this value. |
||
405 | |||
784 | DimkaM | 406 | static unsigned short freq[T + 1]; // frequency table |
716 | lvd | 407 | |
784 | DimkaM | 408 | static short prnt[T + N_CHAR]; // pointers to parent nodes, except for the |
716 | lvd | 409 | // elements [T..T + N_CHAR - 1] which are used to get |
410 | // the positions of leaves corresponding to the codes. |
||
784 | DimkaM | 411 | static short son[T]; // pointers to child nodes (son[], son[] + 1) |
716 | lvd | 412 | |
413 | |||
784 | DimkaM | 414 | static int r; |
716 | lvd | 415 | |
784 | DimkaM | 416 | static unsigned getbuf; |
417 | static unsigned char getlen; |
||
716 | lvd | 418 | |
784 | DimkaM | 419 | static int GetBit() /* get one bit */ |
716 | lvd | 420 | { |
784 | DimkaM | 421 | unsigned i; |
716 | lvd | 422 | |
423 | while (getlen <= 8) |
||
424 | { |
||
784 | DimkaM | 425 | if((i = readChar()) == -1U) |
426 | { |
||
427 | i = 0; |
||
428 | } |
||
429 | getbuf |= unsigned(i << (8 - getlen)); |
||
430 | getlen += 8; |
||
716 | lvd | 431 | } |
432 | i = getbuf; |
||
433 | getbuf <<= 1; |
||
434 | getlen--; |
||
435 | return ((i>>15) & 1); |
||
436 | } |
||
437 | |||
784 | DimkaM | 438 | static int GetByte() /* get one byte */ |
716 | lvd | 439 | { |
440 | unsigned i; |
||
441 | |||
442 | while (getlen <= 8) |
||
443 | { |
||
784 | DimkaM | 444 | if((i = readChar()) == -1U) |
445 | { |
||
446 | i = 0; |
||
447 | } |
||
448 | getbuf |= unsigned(i << (8 - getlen)); |
||
449 | getlen += 8; |
||
716 | lvd | 450 | } |
451 | i = getbuf; |
||
452 | getbuf <<= 8; |
||
453 | getlen -= 8; |
||
454 | return (i >> 8) & 0xFF; |
||
455 | } |
||
456 | |||
784 | DimkaM | 457 | static void StartHuff() |
716 | lvd | 458 | { |
459 | int i, j; |
||
460 | |||
784 | DimkaM | 461 | getbuf = 0; getlen = 0; |
716 | lvd | 462 | for (i = 0; i < N_CHAR; i++) { |
463 | freq[i] = 1; |
||
784 | DimkaM | 464 | son[i] = i16(i + T); |
465 | prnt[i + T] = i16(i); |
||
716 | lvd | 466 | } |
467 | i = 0; j = N_CHAR; |
||
468 | while (j <= R) { |
||
469 | freq[j] = freq[i] + freq[i + 1]; |
||
784 | DimkaM | 470 | son[j] = i16(i); |
471 | prnt[i] = prnt[i + 1] = i16(j); |
||
716 | lvd | 472 | i += 2; j++; |
473 | } |
||
474 | freq[T] = 0xffff; |
||
475 | prnt[R] = 0; |
||
476 | |||
477 | for (i = 0; i < N - F; i++) text_buf[i] = ' '; |
||
478 | r = N - F; |
||
479 | } |
||
480 | |||
481 | /* reconstruction of tree */ |
||
784 | DimkaM | 482 | static void reconst() |
716 | lvd | 483 | { |
484 | int i, j, k; |
||
784 | DimkaM | 485 | int f; |
716 | lvd | 486 | |
487 | /* collect leaf nodes in the first half of the table */ |
||
488 | /* and replace the freq by (freq + 1) / 2. */ |
||
489 | j = 0; |
||
490 | for(i = 0; i < T; i++) |
||
491 | { |
||
492 | if(son[i] >= T) |
||
493 | { |
||
494 | freq[j] = (freq[i] + 1) / 2; |
||
495 | son[j] = son[i]; |
||
496 | j++; |
||
497 | } |
||
498 | } |
||
499 | /* begin constructing tree by connecting sons */ |
||
500 | for(i = 0, j = N_CHAR; j < T; i += 2, j++) |
||
501 | { |
||
502 | k = i + 1; |
||
503 | f = freq[j] = freq[i] + freq[k]; |
||
504 | for(k = j - 1; f < freq[k]; k--); |
||
505 | k++; |
||
784 | DimkaM | 506 | size_t l = unsigned(j - k) * sizeof(*freq); |
716 | lvd | 507 | MoveMemory(&freq[k + 1], &freq[k], l); |
784 | DimkaM | 508 | freq[k] = u16(f); |
716 | lvd | 509 | MoveMemory(&son[k + 1], &son[k], l); |
784 | DimkaM | 510 | son[k] = i16(i); |
716 | lvd | 511 | } |
512 | /* connect prnt */ |
||
513 | for (i = 0; i < T; i++) |
||
784 | DimkaM | 514 | if ((k = son[i]) >= T) prnt[k] = i16(i); |
515 | else prnt[k] = prnt[k + 1] = i16(i); |
||
716 | lvd | 516 | } |
517 | |||
518 | |||
519 | /* increment frequency of given code by one, and update tree */ |
||
520 | |||
784 | DimkaM | 521 | static void update(int c) |
716 | lvd | 522 | { |
523 | int i, j, k, l; |
||
524 | |||
525 | if(freq[R] == MAX_FREQ) reconst(); |
||
526 | |||
527 | c = prnt[c + T]; |
||
528 | do { |
||
529 | k = ++freq[c]; |
||
530 | |||
531 | /* if the order is disturbed, exchange nodes */ |
||
532 | if (k > freq[l = c + 1]) |
||
533 | { |
||
534 | while (k > freq[++l]); |
||
535 | l--; |
||
536 | freq[c] = freq[l]; |
||
784 | DimkaM | 537 | freq[l] = u16(k); |
716 | lvd | 538 | |
539 | i = son[c]; |
||
784 | DimkaM | 540 | prnt[i] = i16(l); |
541 | if (i < T) prnt[i + 1] = i16(l); |
||
716 | lvd | 542 | |
543 | j = son[l]; |
||
784 | DimkaM | 544 | son[l] = i16(i); |
716 | lvd | 545 | |
784 | DimkaM | 546 | prnt[j] = i16(c); |
547 | if (j < T) prnt[j + 1] = i16(c); |
||
548 | son[c] = i16(j); |
||
716 | lvd | 549 | |
550 | c = l; |
||
551 | } |
||
552 | } while ((c = prnt[c]) != 0); /* repeat up to root */ |
||
553 | } |
||
554 | |||
784 | DimkaM | 555 | static int DecodeChar() |
716 | lvd | 556 | { |
557 | int c; |
||
558 | |||
559 | c = son[R]; |
||
560 | |||
561 | /* travel from root to leaf, */ |
||
562 | /* choosing the smaller child node (son[]) if the read bit is 0, */ |
||
563 | /* the bigger (son[]+1} if 1 */ |
||
564 | while(c < T) c = son[c + GetBit()]; |
||
565 | c -= T; |
||
566 | update(c); |
||
567 | return c; |
||
568 | } |
||
569 | |||
784 | DimkaM | 570 | static int DecodePosition() |
716 | lvd | 571 | { |
572 | int i, j, c; |
||
573 | |||
574 | /* recover upper 6 bits from table */ |
||
575 | i = GetByte(); |
||
576 | c = (int)d_code[i] << 6; |
||
577 | j = d_len[i]; |
||
578 | /* read lower 6 bits verbatim */ |
||
579 | j -= 2; |
||
580 | while (j--) i = (i << 1) + GetBit(); |
||
581 | return c | (i & 0x3f); |
||
582 | } |
||
583 | |||
584 | unsigned unpack_lzh(unsigned char *src, unsigned size, unsigned char *buf) |
||
585 | { |
||
586 | packed_ptr = src; packed_end = src+size; |
||
587 | int i, j, k, c; |
||
588 | unsigned count = 0; |
||
589 | StartHuff(); |
||
590 | |||
591 | // while (count < textsize) // textsize - sizeof unpacked data |
||
592 | while (packed_ptr < packed_end) |
||
593 | { |
||
594 | c = DecodeChar(); |
||
595 | if(c < 256) |
||
596 | { |
||
784 | DimkaM | 597 | *buf++ = u8(c); |
598 | text_buf[r++] = u8(c); |
||
716 | lvd | 599 | r &= (N - 1); |
600 | count++; |
||
601 | } else { |
||
602 | i = (r - DecodePosition() - 1) & (N - 1); |
||
603 | j = c - 255 + THRESHOLD; |
||
604 | for (k = 0; k < j; k++) |
||
605 | { |
||
606 | c = text_buf[(i + k) & (N - 1)]; |
||
784 | DimkaM | 607 | *buf++ = u8(c); |
608 | text_buf[r++] = u8(c); |
||
716 | lvd | 609 | r &= (N - 1); |
610 | count++; |
||
611 | } |
||
612 | } |
||
613 | } |
||
614 | return count; |
||
615 | } |