1 /*
2 LIBDSK: General floppy and diskimage access library
3 Copyright (C) 2002, 2014 John Elliott <seasip.webmaster@gmail.com>
4
5 LZH decompression code based on tdlzhuf.c / tdcrc.c
6 (both from wteledsk by Will Kranz, GPLv2. Permission to
7 relicense these source files under LGPLv2 was granted by
8 email).
9 All functions made static. All static global variables moved
10 into the TLZH_COMPRESS_DATA structure.
11
12 tdlzhuf.c module to perform lzss-huffman decompression
13 as is used in teledisk.exe
14 Conditionally compiled main to convert *.td0 advanced
15 compression file back normal compression file.
16 derived from lzhuf.c 1.0 per below
17
18 This library is free software; you can redistribute it and/or
19 modify it under the terms of the GNU Library General Public
20 License as published by the Free Software Foundation; either
21 version 2 of the License, or (at your option) any later version.
22
23 This library is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 Library General Public License for more details.
27
28 You should have received a copy of the GNU Library General Public
29 License along with this library; if not, write to the Free
30 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
31 MA 02111-1307, USA
32
33 11/10/02 this was working with struct tdlzhuf * passed to
34 both Decode() and init_Decode() as first arg. Save this as
35 tdlzhuf1.c and then make this structure locally static and try
36 to switch to unsigned shorts where it matters so works in linux.
37
38 Started with program below:
39 * LZHUF.C English version 1.0
40 * Based on Japanese version 29-NOV-1988
41 * LZSS coded by Haruhiko OKUMURA
42 * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
43 * Edited and translated to English by Kenji RIKITAKE
44
45 In summary changes by WTK:
46 wrote a new conditionally compiled main()
47 remove Encode() modules and arrays
48 make remaing arrays and variables static to hide from external modules
49 add struct tdlzhuf to provide state retension between calls to Decode()
50 change from fgetc(FILE *) to read(int fp) so read
51 a block at a time into an input buffer. Now the
52 Decode() routine can be called instead of read()
53 by a user, ie from wteledisk.c
54 change size of data elements for Linux,
55 int -> short
56 unsigned int -> unsigned short
57
58 */
59 #include "compi.h"
60 #include "comptlzh.h"
61
62 unsigned short teledisk_crc(unsigned char *b, unsigned short len);
63
64 #if 0 /* These functions are not called; presumably they would be used for
65 LZHUF compression were LibDsk to implement that */
66
67 /* Initializing tree */
68 static void InitTree(TLZH_COMPRESS_DATA *self)
69 {
70 int i;
71
72 for (i = N + 1; i <= N + 256; i++)
73 self->rson[i] = NIL; /* root */
74 for (i = 0; i < N; i++)
75 self->dad[i] = NIL; /* node */
76 }
77
78 /* Inserting node to the tree */
79 static void InsertNode(TLZH_COMPRESS_DATA *self, int r)
80 {
81 int i, p, cmp;
82 unsigned char *key;
83 unsigned c;
84
85 cmp = 1;
86 key = &self->text_buf[r];
87 p = N + 1 + key[0];
88 self->rson[r] = self->lson[r] = NIL;
89 self->match_length = 0;
90 for ( ; ; ) {
91 if (cmp >= 0) {
92 if (self->rson[p] != NIL)
93 p = self->rson[p];
94 else {
95 self->rson[p] = r;
96 self->dad[r] = p;
97 return;
98 }
99 } else {
100 if (self->lson[p] != NIL)
101 p = self->lson[p];
102 else {
103 self->lson[p] = r;
104 self->dad[r] = p;
105 return;
106 }
107 }
108 for (i = 1; i < F; i++)
109 if ((cmp = key[i] - self->text_buf[p + i]) != 0)
110 break;
111 if (i > THRESHOLD) {
112 if (i > self->match_length) {
113 self->match_position = ((r - p) & (N - 1)) - 1;
114 if ((self->match_length = i) >= F)
115 break;
116 }
117 if (i == self->match_length) {
118 if ((c = ((r - p) & (N - 1)) - 1) < self->match_position) {
119 self->match_position = c;
120 }
121 }
122 }
123 }
124 self->dad[r] = self->dad[p];
125 self->lson[r] = self->lson[p];
126 self->rson[r] = self->rson[p];
127 self->dad[self->lson[p]] = r;
128 self->dad[self->rson[p]] = r;
129 if (self->rson[self->dad[p]] == p)
130 self->rson[self->dad[p]] = r;
131 else
132 self->lson[self->dad[p]] = r;
133 self->dad[p] = NIL; /* remove p */
134 }
135
136 static void DeleteNode(TLZH_COMPRESS_DATA *self, int p) /* Deleting node from the tree */
137 {
138 int q;
139
140 if (self->dad[p] == NIL)
141 return; /* unregistered */
142 if (self->rson[p] == NIL)
143 q = self->lson[p];
144 else
145 if (self->lson[p] == NIL)
146 q = self->rson[p];
147 else {
148 q = self->lson[p];
149 if (self->rson[q] != NIL) {
150 do {
151 q = self->rson[q];
152 } while (self->rson[q] != NIL);
153 self->rson[self->dad[q]] = self->lson[q];
154 self->dad[self->lson[q]] = self->dad[q];
155 self->lson[q] = self->lson[p];
156 self->dad[self->lson[p]] = q;
157 }
158 self->rson[q] = self->rson[p];
159 self->dad[self->rson[p]] = q;
160 }
161 self->dad[q] = self->dad[p];
162 if (self->rson[self->dad[p]] == p)
163 self->rson[self->dad[p]] = q;
164 else
165 self->lson[self->dad[p]] = q;
166 self->dad[p] = NIL;
167 }
168 #endif
169
170 /*
171 * Tables for encoding/decoding upper 6 bits of
172 * sliding dictionary pointer
173 */
174
175 /* decoder table */
176 static const unsigned char d_code[256] = {
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
182 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
183 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
184 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
185 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
186 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
187 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
188 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
189 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
190 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
191 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
192 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
193 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
194 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
195 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
196 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
197 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
198 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
199 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
200 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
201 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
202 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
203 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
204 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
205 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
206 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
207 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
208 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
209 };
210
211 static const unsigned char d_len[256] = {
212 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
213 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
214 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
215 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
216 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
217 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
218 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
219 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
220 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
221 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
222 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
223 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
224 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
225 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
226 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
227 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
228 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
229 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
230 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
231 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
232 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
233 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
234 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
235 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
236 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
237 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
238 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
239 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
240 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
241 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
242 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
243 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
244 };
245
246
247 /* this is old code duplicated in GetBit() and GetByte()
248 while (getlen <= 8) {
249 if ((i = getc(infile)) < 0) i = 0;
250 getbuf |= i << (8 - getlen);
251 getlen += 8;
252 }
253
254 replace this with next_word() routine that handles block read
255 */
next_word(TLZH_COMPRESS_DATA * self)256 static int next_word(TLZH_COMPRESS_DATA *self)
257 {
258 if(self->ibufndx >= self->ibufcnt)
259 {
260 self->ibufndx = 0;
261 self->ibufcnt = fread(self->inbuf,1, TLZH_BUFSZ, self->fp_in);
262 if(self->ibufcnt <= 0)
263 return(-1);
264 }
265 while (self->getlen <= 8) { // typically reads a word at a time
266 self->getbuf |= self->inbuf[self->ibufndx++] << (8 - self->getlen);
267 self->getlen += 8;
268 }
269 return(0);
270 }
271
272
GetBit(TLZH_COMPRESS_DATA * self)273 static int GetBit(TLZH_COMPRESS_DATA *self) /* get one bit */
274 {
275 short i;
276 if(next_word(self) < 0)
277 return(-1);
278 i = self->getbuf;
279 self->getbuf <<= 1;
280 self->getlen--;
281 if(i < 0)
282 return(1);
283 else
284 return(0);
285 }
286
GetByte(TLZH_COMPRESS_DATA * self)287 static int GetByte(TLZH_COMPRESS_DATA *self) /* get a byte */
288 {
289 unsigned short i;
290 if(next_word(self) != 0)
291 return(-1);
292 i = self->getbuf;
293 self->getbuf <<= 8;
294 self->getlen -= 8;
295 i = i >> 8;
296 return((int) i);
297 }
298
299
300
301 /* initialize freq tree */
302
StartHuff(TLZH_COMPRESS_DATA * self)303 static void StartHuff(TLZH_COMPRESS_DATA *self)
304 {
305 int i, j;
306
307 for (i = 0; i < TLZH_NCHAR; i++) {
308 self->freq[i] = 1;
309 self->son[i] = i + TLZH_T;
310 self->prnt[i + TLZH_T] = i;
311 }
312 i = 0; j = TLZH_NCHAR;
313 while (j <= TLZH_R) {
314 self->freq[j] = self->freq[i] + self->freq[i + 1];
315 self->son[j] = i;
316 self->prnt[i] = self->prnt[i + 1] = j;
317 i += 2; j++;
318 }
319 self->freq[TLZH_T] = 0xffff;
320 self->prnt[TLZH_R] = 0;
321 }
322
323
324 /* reconstruct freq tree */
325
reconst(TLZH_COMPRESS_DATA * self)326 static void reconst(TLZH_COMPRESS_DATA *self)
327 {
328 short i, j, k;
329 unsigned short f, l;
330
331 /* halven cumulative freq for leaf nodes */
332 j = 0;
333 for (i = 0; i < TLZH_T; i++) {
334 if (self->son[i] >= TLZH_T) {
335 self->freq[j] = (self->freq[i] + 1) / 2;
336 self->son[j] = self->son[i];
337 j++;
338 }
339 }
340 /* make a tree : first, connect children nodes */
341 for (i = 0, j = TLZH_NCHAR; j < TLZH_T; i += 2, j++) {
342 k = i + 1;
343 f = self->freq[j] = self->freq[i] + self->freq[k];
344 for (k = j - 1; f < self->freq[k]; k--);
345 k++;
346 l = (j - k) * 2;
347
348 /* movmem() is Turbo-C dependent
349 rewritten to memmove() by Kenji */
350
351 /* movmem(&freq[k], &freq[k + 1], l); */
352 (void)memmove(&self->freq[k + 1], &self->freq[k], l);
353 self->freq[k] = f;
354 /* movmem(&son[k], &son[k + 1], l); */
355 (void)memmove(&self->son[k + 1], &self->son[k], l);
356 self->son[k] = i;
357 }
358 /* connect parent nodes */
359 for (i = 0; i < TLZH_T; i++) {
360 if ((k = self->son[i]) >= TLZH_T) {
361 self->prnt[k] = i;
362 } else {
363 self->prnt[k] = self->prnt[k + 1] = i;
364 }
365 }
366 }
367
368
369 /* update freq tree */
370
update(TLZH_COMPRESS_DATA * self,int c)371 static void update(TLZH_COMPRESS_DATA *self, int c)
372 {
373 int i, j, k, l;
374
375 if (self->freq[TLZH_R] == TLZH_MAX_FREQ) {
376 reconst(self);
377 }
378 c = self->prnt[c + TLZH_T];
379 do {
380 k = ++self->freq[c];
381
382 /* swap nodes to keep the tree freq-ordered */
383 if (k > self->freq[l = c + 1]) {
384 while (k > self->freq[++l]);
385 l--;
386 self->freq[c] = self->freq[l];
387 self->freq[l] = k;
388
389 i = self->son[c];
390 self->prnt[i] = l;
391 if (i < TLZH_T) self->prnt[i + 1] = l;
392
393 j = self->son[l];
394 self->son[l] = i;
395
396 self->prnt[j] = c;
397 if (j < TLZH_T) self->prnt[j + 1] = c;
398 self->son[c] = j;
399
400 c = l;
401 }
402 } while ((c = self->prnt[c]) != 0); /* do it until reaching the root */
403 }
404
405
DecodeChar(TLZH_COMPRESS_DATA * self)406 static short DecodeChar(TLZH_COMPRESS_DATA *self)
407 {
408 int ret;
409 unsigned short c;
410
411 c = self->son[TLZH_R];
412
413 /*
414 * start searching tree from the root to leaves.
415 * choose node #(son[]) if input bit == 0
416 * else choose #(son[]+1) (input bit == 1)
417 */
418 while (c < TLZH_T) {
419 if((ret = GetBit(self)) < 0)
420 return(-1);
421 c += (unsigned) ret;
422 c = self->son[c];
423 }
424 c -= TLZH_T;
425 update(self, c);
426 return c;
427 }
428
DecodePosition(TLZH_COMPRESS_DATA * self)429 static short DecodePosition(TLZH_COMPRESS_DATA *self)
430 {
431 short bit;
432 unsigned short i, j, c;
433
434 /* decode upper 6 bits from given table */
435 if((bit=GetByte(self)) < 0)
436 return(-1);
437 i = (unsigned short) bit;
438 c = (unsigned short)d_code[i] << 6;
439 j = d_len[i];
440
441 /* input lower 6 bits directly */
442 j -= 2;
443 while (j--) {
444 if((bit = GetBit(self)) < 0)
445 return(-1);
446 i = (i << 1) + bit;
447 }
448 return(c | (i & 0x3f));
449 }
450
451 /* DeCompression
452
453 split out initialization code to init_Decode()
454
455 */
456
init_Decode(TLZH_COMPRESS_DATA * self)457 static void init_Decode(TLZH_COMPRESS_DATA *self)
458 {
459 int i;
460
461 self->ibufcnt= self->ibufndx = 0; // input buffer is empty
462 self->bufcnt = 0;
463 StartHuff(self);
464 for (i = 0; i < TLZH_N - TLZH_F; i++)
465 {
466 self->text_buf[i] = ' ';
467 }
468 self->r = TLZH_N - TLZH_F;
469 }
470
471
Decode(TLZH_COMPRESS_DATA * self,unsigned char * buf,int len)472 static int Decode(TLZH_COMPRESS_DATA *self, unsigned char *buf, int len)
473 /* Decoding/Uncompressing */
474 {
475 short c,pos;
476 int count; // was an unsigned long, seems unnecessary
477 for (count = 0; count < len; ) {
478 if(self->bufcnt == 0) {
479 if((c = DecodeChar(self)) < 0)
480 return(count); // fatal error
481 if (c < 256) {
482 *(buf++) = (unsigned char)c;
483 self->text_buf[self->r++] = (unsigned char)c;
484 self->r &= (TLZH_N - 1);
485 count++;
486 }
487 else {
488 if((pos = DecodePosition(self)) < 0)
489 return(count); // fatal error
490 self->bufpos = (self->r - pos - 1) & (TLZH_N - 1);
491 self->bufcnt = c - 255 + TLZH_THRESHOLD;
492 self->bufndx = 0;
493 }
494 }
495 else { // still chars from last string
496 while( self->bufndx < self->bufcnt && count < len ) {
497 c = self->text_buf[(self->bufpos + self->bufndx) & (TLZH_N - 1)];
498 *(buf++) = (unsigned char)c;
499 self->bufndx++;
500 self->text_buf[self->r++] = (unsigned char)c;
501 self->r &= (TLZH_N - 1);
502 count++;
503 }
504 // reset bufcnt after copy string from text_buf[]
505 if(self->bufndx >= self->bufcnt)
506 self->bufndx = self->bufcnt = 0;
507 }
508 }
509 return(count); // count == len, success
510 }
511
512
513 /* This struct contains function pointers to the driver's functions, and the
514 * size of its DSK_DRIVER subclass */
515
516 COMPRESS_CLASS cc_tlzh =
517 {
518 sizeof(TLZH_COMPRESS_DATA),
519 "tdlzh",
520 "TeleDisk advanced compression",
521 tlzh_open, /* open */
522 tlzh_creat, /* create new */
523 tlzh_commit, /* commit */
524 tlzh_abort /* abort */
525 };
526
527
528
uncompress(TLZH_COMPRESS_DATA * self)529 static dsk_err_t uncompress(TLZH_COMPRESS_DATA *self)
530 {
531 unsigned char head[12];
532 int rd;
533 long off=0;
534 unsigned short crc=0;
535
536 /* Load the header */
537 if (fread(head, 1, sizeof(head), self->fp_in) != sizeof(head))
538 {
539 return DSK_ERR_SYSERR;
540 }
541 off = sizeof(head);
542 init_Decode(self);
543
544 /* Change the 'compressed' signature to 'uncompressed' */
545 head[0] = 'T';
546 head[1] = 'D';
547
548 /* And update the CRC */
549 crc = teledisk_crc(head,10);
550 head[10] = crc & 0xff;
551 head[11] = (crc >> 8) & 0xff;
552
553 /* Write out the new header */
554 if(fwrite(head, 1, sizeof(head), self->fp_out) != sizeof(head))
555 {
556 return DSK_ERR_SYSERR;
557 }
558 /* Expand the compressed contents */
559 do
560 {
561 if((rd = Decode(self, self->obuf,TLZH_BUFSZ)) > 0)
562 {
563 if (fwrite(self->obuf, 1, rd, self->fp_out) < (unsigned)rd)
564 return DSK_ERR_SYSERR;
565 }
566 off += rd;
567 } while(rd == TLZH_BUFSZ);
568
569 /* This is a decompress-only driver, so set the read-only flag in the
570 * compression structure */
571 self->tlzh_super.cd_readonly = 1;
572 return DSK_ERR_OK;
573 }
574
575
576 /* Expand a compressed ('td') file to uncompressed ('TD') */
tlzh_open(COMPRESS_DATA * self)577 dsk_err_t tlzh_open(COMPRESS_DATA *self)
578 {
579 TLZH_COMPRESS_DATA *tlzh_self;
580 dsk_err_t err;
581 unsigned char magic[12];
582
583 /* Sanity check: Is this meant for our driver? */
584 if (self->cd_class != &cc_tlzh) return DSK_ERR_BADPTR;
585 tlzh_self = (TLZH_COMPRESS_DATA *)self;
586 tlzh_self->fp_in = NULL;
587 tlzh_self->fp_out = NULL;
588
589 /* Open the file to decompress */
590 err = comp_fopen(self, &tlzh_self->fp_in);
591 if (err) return DSK_ERR_NOTME;
592
593 /* Check for magic number: "td\0" */
594 /* Check header CRC */
595 if (fread(magic, 1, 12, tlzh_self->fp_in) < 12 ||
596 memcmp(magic, "td", 3) ||
597 magic[10] + 256 * magic[11] != teledisk_crc(magic, 10))
598 {
599 fclose(tlzh_self->fp_in);
600 return DSK_ERR_NOTME;
601 }
602
603 /* OK. This looks like an advanced Teledisk file. Decompress it to a
604 * normal Teledisk file. */
605 rewind(tlzh_self->fp_in);
606 err = comp_mktemp(self, &tlzh_self->fp_out);
607 if (!err) err = uncompress(tlzh_self);
608
609 if (tlzh_self->fp_out) fclose(tlzh_self->fp_out);
610 fclose(tlzh_self->fp_in);
611
612 return err;
613 }
614
tlzh_creat(COMPRESS_DATA * self)615 dsk_err_t tlzh_creat(COMPRESS_DATA *self)
616 {
617 return DSK_ERR_RDONLY;
618 }
619
tlzh_commit(COMPRESS_DATA * self)620 dsk_err_t tlzh_commit(COMPRESS_DATA *self)
621 {
622 return DSK_ERR_RDONLY;
623 }
624
tlzh_abort(COMPRESS_DATA * self)625 dsk_err_t tlzh_abort(COMPRESS_DATA *self)
626 {
627 return DSK_ERR_OK;
628 }
629
630 /* Wholesale inclusion of tdcrc.c */
631
632 /* tdcrc.c - a crc routine to mimic tdcheck.exe
633
634 This program is free software; you can redistribute it and/or modify
635 it under the terms of the GNU General Public License as published by
636 the Free Software Foundation; either version 2 of the License, or
637 (at your option) any later version.
638
639 This program is distributed in the hope that it will be useful,
640 but WITHOUT ANY WARRANTY; without even the implied warranty of
641 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
642 GNU General Public License for more details.
643
644 You should have received a copy of the GNU General Public License
645 along with this program; if not, write to the Free Software
646 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
647 http://www.gnu.org/licenses/gpl.txt
648
649
650 10/19/02 got it working!
651 Contains conditionals to build a test program
652 or just use as a module.
653 Define DOMAIN if *.exe is desired
654 if not defined get a linkable crc module
655 */
656
657 static unsigned char table[] = {
658 0x00,0xa0,0xe1,0x41,0x63,0xc3,0x82,0x22,0xc7,0x67,0x26,0x86,0xa4,0x04,0x45,0xe5,
659 0x2f,0x8f,0xce,0x6e,0x4c,0xec,0xad,0x0d,0xe8,0x48,0x09,0xa9,0x8b,0x2b,0x6a,0xca,
660 0x5e,0xfe,0xbf,0x1f,0x3d,0x9d,0xdc,0x7c,0x99,0x39,0x78,0xd8,0xfa,0x5a,0x1b,0xbb,
661 0x71,0xd1,0x90,0x30,0x12,0xb2,0xf3,0x53,0xb6,0x16,0x57,0xf7,0xd5,0x75,0x34,0x94,
662 0xbc,0x1c,0x5d,0xfd,0xdf,0x7f,0x3e,0x9e,0x7b,0xdb,0x9a,0x3a,0x18,0xb8,0xf9,0x59,
663 0x93,0x33,0x72,0xd2,0xf0,0x50,0x11,0xb1,0x54,0xf4,0xb5,0x15,0x37,0x97,0xd6,0x76,
664 0xe2,0x42,0x03,0xa3,0x81,0x21,0x60,0xc0,0x25,0x85,0xc4,0x64,0x46,0xe6,0xa7,0x07,
665 0xcd,0x6d,0x2c,0x8c,0xae,0x0e,0x4f,0xef,0x0a,0xaa,0xeb,0x4b,0x69,0xc9,0x88,0x28,
666
667 0xd8,0x78,0x39,0x99,0xbb,0x1b,0x5a,0xfa,0x1f,0xbf,0xfe,0x5e,0x7c,0xdc,0x9d,0x3d,
668 0xf7,0x57,0x16,0xb6,0x94,0x34,0x75,0xd5,0x30,0x90,0xd1,0x71,0x53,0xf3,0xb2,0x12,
669 0x86,0x26,0x67,0xc7,0xe5,0x45,0x04,0xa4,0x41,0xe1,0xa0,0x00,0x22,0x82,0xc3,0x63,
670 0xa9,0x09,0x48,0xe8,0xca,0x6a,0x2b,0x8b,0x6e,0xce,0x8f,0x2f,0x0d,0xad,0xec,0x4c,
671 0x64,0xc4,0x85,0x25,0x07,0xa7,0xe6,0x46,0xa3,0x03,0x42,0xe2,0xc0,0x60,0x21,0x81,
672 0x4b,0xeb,0xaa,0x0a,0x28,0x88,0xc9,0x69,0x8c,0x2c,0x6d,0xcd,0xef,0x4f,0x0e,0xae,
673 0x3a,0x9a,0xdb,0x7b,0x59,0xf9,0xb8,0x18,0xfd,0x5d,0x1c,0xbc,0x9e,0x3e,0x7f,0xdf,
674 0x15,0xb5,0xf4,0x54,0x76,0xd6,0x97,0x37,0xd2,0x72,0x33,0x93,0xb1,0x11,0x50,0xf0,
675
676 0x00,0x97,0xb9,0x2e,0xe5,0x72,0x5c,0xcb,0xca,0x5d,0x73,0xe4,0x2f,0xb8,0x96,0x01,
677 0x03,0x94,0xba,0x2d,0xe6,0x71,0x5f,0xc8,0xc9,0x5e,0x70,0xe7,0x2c,0xbb,0x95,0x02,
678 0x06,0x91,0xbf,0x28,0xe3,0x74,0x5a,0xcd,0xcc,0x5b,0x75,0xe2,0x29,0xbe,0x90,0x07,
679 0x05,0x92,0xbc,0x2b,0xe0,0x77,0x59,0xce,0xcf,0x58,0x76,0xe1,0x2a,0xbd,0x93,0x04,
680 0x0c,0x9b,0xb5,0x22,0xe9,0x7e,0x50,0xc7,0xc6,0x51,0x7f,0xe8,0x23,0xb4,0x9a,0x0d,
681 0x0f,0x98,0xb6,0x21,0xea,0x7d,0x53,0xc4,0xc5,0x52,0x7c,0xeb,0x20,0xb7,0x99,0x0e,
682 0x0a,0x9d,0xb3,0x24,0xef,0x78,0x56,0xc1,0xc0,0x57,0x79,0xee,0x25,0xb2,0x9c,0x0b,
683 0x09,0x9e,0xb0,0x27,0xec,0x7b,0x55,0xc2,0xc3,0x54,0x7a,0xed,0x26,0xb1,0x9f,0x08,
684
685 0x8f,0x18,0x36,0xa1,0x6a,0xfd,0xd3,0x44,0x45,0xd2,0xfc,0x6b,0xa0,0x37,0x19,0x8e,
686 0x8c,0x1b,0x35,0xa2,0x69,0xfe,0xd0,0x47,0x46,0xd1,0xff,0x68,0xa3,0x34,0x1a,0x8d,
687 0x89,0x1e,0x30,0xa7,0x6c,0xfb,0xd5,0x42,0x43,0xd4,0xfa,0x6d,0xa6,0x31,0x1f,0x88,
688 0x8a,0x1d,0x33,0xa4,0x6f,0xf8,0xd6,0x41,0x40,0xd7,0xf9,0x6e,0xa5,0x32,0x1c,0x8b,
689 0x83,0x14,0x3a,0xad,0x66,0xf1,0xdf,0x48,0x49,0xde,0xf0,0x67,0xac,0x3b,0x15,0x82,
690 0x80,0x17,0x39,0xae,0x65,0xf2,0xdc,0x4b,0x4a,0xdd,0xf3,0x64,0xaf,0x38,0x16,0x81,
691 0x85,0x12,0x3c,0xab,0x60,0xf7,0xd9,0x4e,0x4f,0xd8,0xf6,0x61,0xaa,0x3d,0x13,0x84,
692 0x86,0x11,0x3f,0xa8,0x63,0xf4,0xda,0x4d,0x4c,0xdb,0xf5,0x62,0xa9,0x3e,0x10,0x87
693 };
694
695
696 // basically same logic as below, but doesn't initialize crc so can append
updt_crc(unsigned short * crc,unsigned char * b,unsigned short len)697 void updt_crc(unsigned short *crc,unsigned char *b, unsigned short len)
698 {
699 unsigned char tmp;
700 while(len-- != 0)
701 {
702 tmp = *b ^ (*crc >> 8);
703 *crc = ((table[tmp] ^ (*crc & 0xff)) << 8) + table[tmp+0x100];
704 b++;
705 }
706
707 }
708
709 // let unsigned char *b point to start of buffer
710 // this initializes crc, then does updt_crc logic
teledisk_crc(unsigned char * b,unsigned short len)711 unsigned short teledisk_crc(unsigned char *b, unsigned short len)
712 {
713 unsigned char tmp;
714 unsigned short i,crc = 0;
715 for(i=0;i<len;i++,b++)
716 {
717 tmp = *b ^ (crc >> 8);
718 crc = ((table[tmp] ^ (crc & 0xff)) << 8) + table[tmp+0x100];
719 }
720 return(crc);
721 }
722
723 #if 0
724 #ifndef MSDOS
725 #define O_BINARY 0 // not defined for Linux gcc
726 #define strnicmp strncasecmp
727 #endif
728
729 #define BLKSZ 256
730
731 main(int argc,char *argv[])
732 { int rd,fp=EOF;
733 unsigned char buf[BLKSZ];
734 unsigned short crc=0;
735 long start = -1,end = -1,off = 0,bytes = 0;
736 if(argc < 2)
737 printf("\nusage: tdcrc <filename> [-s#] [-e#]");
738 else if((fp = open(argv[1],O_RDONLY|O_BINARY)) == EOF)
739 printf("\nfailed to open %s",argv[1]);
740 else
741 {
742 for(rd=2;rd < argc;rd++)
743 {
744 if(strnicmp(argv[rd],"-s",2) == 0 &&
745 sscanf(argv[rd]+2,"%lx",&start) == 1)
746 {
747 printf("\nstart offset 0x%lx",start);
748 if(lseek(fp,start,SEEK_SET) != start)
749 {
750 printf(" -- seek failed!");
751 start = -1;
752 }
753 else
754 off = start;
755 }
756 if(strnicmp(argv[rd],"-e",2) == 0 &&
757 sscanf(argv[rd]+2,"%lx",&end) == 1)
758 printf("\nend offset 0x%lx",end);
759 }
760 while(1)
761 {
762 rd = read(fp,buf,BLKSZ);
763 if(end > 0 && off + rd > end)
764 rd = end - off;
765 if(rd <= 0)
766 break;
767 updt_crc(&crc,buf,rd);
768 bytes += rd;
769 off += rd;
770 }
771 }
772 if(fp != EOF)
773 {
774 printf("\nfile crc = 0x%x = %u",crc,crc);
775 printf("\nread %d bytes",bytes);
776 close(fp);
777 }
778 putchar('\n');
779
780 }
781
782 #endif
783
784
785