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