Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtHelp / decompress.c
1 /* $XConsortium: decompress.c /main/4 1995/10/26 12:36:44 rswiston $ */
2 /* 
3  * decompress - cat a compressed file
4  *
5  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
6  *  (c) Copyright 1993, 1994 International Business Machines Corp.
7  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
8  *  (c) Copyright 1993, 1994 Novell, Inc.
9  */
10
11 /* #include "fontmisc.h" */
12 #include <fcntl.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <sys/stat.h>
16 #include "bufioI.h"
17
18 #define BITS    16
19
20 /*
21  * a code_int must be able to hold 2**BITS values of type int, and also -1
22  */
23 #if BITS > 15
24 typedef long int        code_int;
25 #else
26 typedef int             code_int;
27 #endif
28
29 typedef long int          count_int;
30
31 #ifdef NO_UCHAR
32  typedef char   char_type;
33 #else
34  typedef        unsigned char   char_type;
35 #endif /* UCHAR */
36
37 static  char_type magic_header[] = { "\037\235" };      /* 1F 9D */
38
39 /* Defines for third byte of header */
40 #define BIT_MASK        0x1f
41 #define BLOCK_MASK      0x80
42 /* Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
43    a fourth header byte (for expansion).
44 */
45
46 #define INIT_BITS 9                     /* initial number of bits/code */
47
48 #ifdef COMPATIBLE               /* But wrong! */
49 # define MAXCODE(n_bits)        (1 << (n_bits) - 1)
50 #else
51 # define MAXCODE(n_bits)        ((1 << (n_bits)) - 1)
52 #endif /* COMPATIBLE */
53
54 static code_int getcode();
55
56 /*
57  * the next two codes should not be changed lightly, as they must not
58  * lie within the contiguous general code space.
59  */ 
60 #define FIRST   257     /* first free entry */
61 #define CLEAR   256     /* table clear output code */
62
63 #define STACK_SIZE  8192
64
65 typedef struct _compressedFILE {
66     BufFilePtr      file;
67
68     char_type       *stackp;
69     code_int        oldcode;
70     char_type       finchar;
71
72     int         block_compress;
73     int         maxbits;
74     code_int    maxcode, maxmaxcode;
75
76     code_int    free_ent;
77     int         clear_flg;
78     int         n_bits;
79
80     /* bit buffer */
81     int         offset, size;
82     char_type   buf[BITS];
83
84     char_type       de_stack[STACK_SIZE];
85     char_type       *tab_suffix;
86     unsigned short  *tab_prefix;
87 } CompressedFile;
88
89
90 static  int hsize_table[] = {
91     5003,       /* 12 bits - 80% occupancy */
92     9001,       /* 13 bits - 91% occupancy */
93     18013,      /* 14 bits - 91% occupancy */
94     35023,      /* 15 bits - 94% occupancy */
95     69001       /* 16 bits - 95% occupancy */
96 };
97
98 static int  BufCompressedFill(), BufCompressedSkip(), BufCompressedClose();
99
100 BufFilePtr
101 _DtHelpCeBufFilePushZ (BufFilePtr f)
102 {
103     int             code;
104     int             maxbits;
105     int             hsize;
106     CompressedFile  *file;
107     int             extra;
108
109     if ((BufFileGet(f) != (magic_header[0] & 0xFF)) ||
110         (BufFileGet(f) != (magic_header[1] & 0xFF)))
111     {
112         return 0;
113     }
114     code = BufFileGet (f);
115     maxbits = code & BIT_MASK;
116     if (maxbits > BITS || maxbits < 12)
117         return 0;
118     hsize = hsize_table[maxbits - 12];
119     extra = (1 << maxbits) * sizeof (char_type) +
120             hsize * sizeof (unsigned short);
121     file = (CompressedFile *) malloc (sizeof (CompressedFile) + extra);
122     if (!file)
123         return 0;
124     file->file = f;
125     file->maxbits = maxbits;
126     file->block_compress = code & BLOCK_MASK;
127     file->maxmaxcode = 1 << file->maxbits;
128     file->tab_suffix = (char_type *) &file[1];
129     file->tab_prefix = (unsigned short *) (file->tab_suffix + file->maxmaxcode);
130     /*
131      * As above, initialize the first 256 entries in the table.
132      */
133     file->maxcode = MAXCODE(file->n_bits = INIT_BITS);
134     for ( code = 255; code >= 0; code-- ) {
135         file->tab_prefix[code] = 0;
136         file->tab_suffix[code] = (char_type) code;
137     }
138     file->free_ent = ((file->block_compress) ? FIRST : 256 );
139     file->clear_flg = 0;
140     file->offset = 0;
141     file->size = 0;
142     file->stackp = file->de_stack;
143     file->finchar = file->oldcode = getcode (file);
144     if (file->oldcode != -1)
145         *file->stackp++ = file->finchar;
146     return _DtHelpCeBufFileCreate ((char *) file,
147                           BufCompressedFill,
148                           BufCompressedSkip,
149                           BufCompressedClose);
150 }
151
152 static int
153 BufCompressedClose (
154     BufFilePtr  f,
155     int         doClose )
156 {
157     CompressedFile  *file;
158     BufFilePtr      raw;
159
160     file = (CompressedFile *) f->hidden;
161     raw = file->file;
162     free (file);
163     _DtHelpCeBufFileClose (raw, doClose);
164     return 1;
165 }
166
167 static int
168 BufCompressedFill (BufFilePtr f)
169 {
170     CompressedFile  *file;
171     register char_type *stackp, *de_stack;
172     register char_type finchar;
173     register code_int code, oldcode, incode;
174     BufChar         *buf, *bufend;
175
176     file = (CompressedFile *) f->hidden;
177
178     buf = f->buffer;
179     bufend = buf + BUFFILESIZE;
180     stackp = file->stackp;
181     de_stack = file->de_stack;
182     finchar = file->finchar;
183     oldcode = file->oldcode;
184     while (buf < bufend) {
185         while (stackp > de_stack && buf < bufend)
186             *buf++ = *--stackp;
187
188         if (buf == bufend)
189             break;
190
191         if (oldcode == -1)
192             break;
193
194         code = getcode (file);
195         if (code == -1)
196             break;
197     
198         if ( (code == CLEAR) && file->block_compress ) {
199             for ( code = 255; code >= 0; code-- )
200                 file->tab_prefix[code] = 0;
201             file->clear_flg = 1;
202             file->free_ent = FIRST - 1;
203             if ( (code = getcode (file)) == -1 )        /* O, untimely death! */
204                 break;
205         }
206         incode = code;
207         /*
208          * Special case for KwKwK string.
209          */
210         if ( code >= file->free_ent ) {
211             *stackp++ = finchar;
212             code = oldcode;
213         }
214     
215         /*
216          * Generate output characters in reverse order
217          */
218         while ( code >= 256 )
219         {
220             *stackp++ = file->tab_suffix[code];
221             code = file->tab_prefix[code];
222         }
223         finchar = file->tab_suffix[code];
224         *stackp++ = finchar;
225     
226         /*
227          * Generate the new entry.
228          */
229         if ( (code=file->free_ent) < file->maxmaxcode ) {
230             file->tab_prefix[code] = (unsigned short)oldcode;
231             file->tab_suffix[code] = finchar;
232             file->free_ent = code+1;
233         } 
234         /*
235          * Remember previous code.
236          */
237         oldcode = incode;
238     }
239     file->oldcode = oldcode;
240     file->stackp = stackp;
241     file->finchar = finchar;
242     if (buf == f->buffer) {
243         f->left = 0;
244         return BUFFILEEOF;
245     }
246     f->bufp = f->buffer + 1;
247     f->left = (buf - f->buffer) - 1;
248     return f->buffer[0];
249 }
250
251 /*****************************************************************
252  * TAG( getcode )
253  *
254  * Read one code from the standard input.  If BUFFILEEOF, return -1.
255  * Inputs:
256  *      stdin
257  * Outputs:
258  *      code or -1 is returned.
259  */
260
261 static char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
262
263 static code_int
264 getcode(CompressedFile  *file)
265 {
266     register code_int code;
267     register int r_off, bits;
268     register char_type *bp = file->buf;
269     register BufFilePtr raw;
270
271     if ( file->clear_flg > 0 || file->offset >= file->size ||
272         file->free_ent > file->maxcode )
273     {
274         /*
275          * If the next entry will be too big for the current code
276          * size, then we must increase the size.  This implies reading
277          * a new buffer full, too.
278          */
279         if ( file->free_ent > file->maxcode ) {
280             file->n_bits++;
281             if ( file->n_bits == file->maxbits )
282                 file->maxcode = file->maxmaxcode;       /* won't get any bigger now */
283             else
284                 file->maxcode = MAXCODE(file->n_bits);
285         }
286         if ( file->clear_flg > 0) {
287             file->maxcode = MAXCODE (file->n_bits = INIT_BITS);
288             file->clear_flg = 0;
289         }
290         bits = file->n_bits;
291         raw = file->file;
292         while (bits > 0 && (code = BufFileGet (raw)) != BUFFILEEOF)
293         {
294             *bp++ = code;
295             --bits;
296         }
297         bp = file->buf;
298         if (bits == file->n_bits)
299             return -1;                  /* end of file */
300         file->size = file->n_bits - bits;
301         file->offset = 0;
302         /* Round size down to integral number of codes */
303         file->size = (file->size << 3) - (file->n_bits - 1);
304     }
305     r_off = file->offset;
306     bits = file->n_bits;
307     /*
308      * Get to the first byte.
309      */
310     bp += (r_off >> 3);
311     r_off &= 7;
312     /* Get first part (low order bits) */
313 #ifdef NO_UCHAR
314     code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
315 #else
316     code = (*bp++ >> r_off);
317 #endif /* NO_UCHAR */
318     bits -= (8 - r_off);
319     r_off = 8 - r_off;          /* now, offset into code word */
320     /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
321     if ( bits >= 8 ) {
322 #ifdef NO_UCHAR
323         code |= (*bp++ & 0xff) << r_off;
324 #else
325         code |= *bp++ << r_off;
326 #endif /* NO_UCHAR */
327         r_off += 8;
328         bits -= 8;
329     }
330     /* high order bits. */
331     code |= (*bp & rmask[bits]) << r_off;
332     file->offset += file->n_bits;
333
334     return code;
335 }
336
337 static int
338 BufCompressedSkip (
339     BufFilePtr  f,
340     int         bytes)
341 {
342     int             c;
343     while (bytes-- && ((c = BufFileGet(f)) != BUFFILEEOF))
344             ;
345     return c;
346 }
347
348 int
349 _DtHelpCeUncompressFile(
350   char *infile,
351   char *outfile )
352 {
353     BufFilePtr      inputraw, input, output;
354     int             c;
355     int             inFd, outFd;
356     struct stat     statBuf;
357     CECompressInfoPtr   myInfo;
358     
359
360     inFd = open(infile, O_RDONLY);
361     if (inFd < 0) return -1;
362
363     if (fstat(inFd, &statBuf) < 0)
364         {
365         close(inFd);
366         return -1;
367         }
368
369     outFd = open(outfile, O_CREAT | O_WRONLY, 0666);
370     if (outFd < 0)
371         {
372         close(inFd);
373         return -1;
374         }
375
376     myInfo = (CECompressInfoPtr) malloc (sizeof(CECompressInfo));
377     if (myInfo == NULL)
378       {
379         close(inFd);
380         close(outFd);
381         return -1;
382       }
383
384     myInfo->fd   = inFd;
385     myInfo->size = statBuf.st_size;
386
387     inputraw = _DtHelpCeBufFileRdRawZ (myInfo);
388     input    = _DtHelpCeBufFilePushZ (inputraw);
389     output   = _DtHelpCeBufFileOpenWr (outFd);
390     while ((c = BufFileGet (input)) != -1)
391         BufFilePut (c, output);
392
393     c = myInfo->size;
394
395     _DtHelpCeBufFileClose (input, TRUE);
396     _DtHelpCeBufFileClose (output, TRUE);
397
398     if (c != 0) /* didn't consume all the bytes in the file */
399         return -1;
400
401     return 0;
402 }