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