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