1 /* Based on src/fontfile/gunzip.c
2    written by Mark Eichin <eichin@kitten.gen.ma.us> September 1996.
3    intended for inclusion in X11 public releases. */
4 
5 /*
6  * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the next
16  * paragraph) shall be included in all copies or substantial portions of the
17  * Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26  */
27 
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 #include "libxfontint.h"
33 
34 #include <X11/fonts/fontmisc.h>
35 #include <X11/fonts/bufio.h>
36 #include <bzlib.h>
37 
38 typedef struct _xzip_buf {
39     bz_stream z;
40     int zstat;
41     BufChar b[BUFFILESIZE];
42     BufChar b_in[BUFFILESIZE];
43     BufFilePtr f;
44 } xzip_buf;
45 
46 static int BufBzip2FileClose ( BufFilePtr f, int flag );
47 static int BufBzip2FileFill ( BufFilePtr f );
48 static int BufBzip2FileSkip ( BufFilePtr f, int c );
49 
50 _X_HIDDEN BufFilePtr
BufFilePushBZIP2(BufFilePtr f)51 BufFilePushBZIP2 (BufFilePtr f)
52 {
53     xzip_buf *x;
54 
55     x = malloc (sizeof (xzip_buf));
56     if (!x) return NULL;
57 
58     bzero(&(x->z), sizeof(bz_stream));
59     x->f = f;
60 
61     x->zstat = BZ2_bzDecompressInit(&(x->z),
62 				    0,	/* verbosity: 0 silent, 4 max */
63 				    0);	/* 0: go faster, 1: use less memory */
64     if (x->zstat != BZ_OK) {
65 	free(x);
66 	return NULL;
67     }
68 
69     /* now that the history buffer is allocated, we provide the data buffer */
70     x->z.next_out = (char *) x->b;
71     x->z.avail_out = BUFFILESIZE;
72     x->z.next_in = (char *) x->b_in;
73     x->z.avail_in = 0;
74 
75     return BufFileCreate((char *)x,
76 			 BufBzip2FileFill,
77 			 NULL,
78 			 BufBzip2FileSkip,
79 			 BufBzip2FileClose);
80 }
81 
82 static int
BufBzip2FileClose(BufFilePtr f,int flag)83 BufBzip2FileClose(BufFilePtr f, int flag)
84 {
85     xzip_buf *x = (xzip_buf *)f->private;
86     BZ2_bzDecompressEnd (&(x->z));
87     BufFileClose (x->f, flag);
88     free (x);
89     return 1;
90 }
91 
92 /* here's the real work.
93    -- we need to put stuff in f.buffer, update f.left and f.bufp,
94    then return the first byte (or BUFFILEEOF).
95    -- to do this, we need to get stuff into avail_in, and next_in,
96    and call BZ2_bzDecompress appropriately.
97    -- we may also need to add CRC maintenance - if BZ2_bzDecompress tells us
98    BZ_STREAM_END, we then have 4bytes CRC and 4bytes length...
99 */
100 static int
BufBzip2FileFill(BufFilePtr f)101 BufBzip2FileFill (BufFilePtr f)
102 {
103     xzip_buf *x = (xzip_buf *)f->private;
104 
105     /* we only get called when left == 0... */
106     /* but just in case, deal */
107     if (f->left >= 0) {
108 	f->left--;
109 	return *(f->bufp++);
110     }
111     /* did we run out last time? */
112     switch (x->zstat) {
113     case BZ_OK:
114 	break;
115     case BZ_STREAM_END:
116     case BZ_DATA_ERROR:
117     case BZ_DATA_ERROR_MAGIC:
118 	f->left = 0;
119 	return BUFFILEEOF;
120     default:
121 	return BUFFILEEOF;
122     }
123     /* now we work to consume what we can */
124     /* let libbz2 know what we can handle */
125     x->z.next_out = (char *) x->b;
126     x->z.avail_out = BUFFILESIZE;
127 
128     /* and try to consume all of it */
129     while (x->z.avail_out > 0) {
130 	/* if we don't have anything to work from... */
131 	if (x->z.avail_in == 0) {
132 	    /* ... fill the z buf from underlying file */
133 	    int i, c;
134 	    for (i = 0; i < sizeof(x->b_in); i++) {
135 		c = BufFileGet(x->f);
136 		if (c == BUFFILEEOF) break;
137 		x->b_in[i] = c;
138 	    }
139 	    x->z.avail_in += i;
140 	    x->z.next_in = (char *) x->b_in;
141 	}
142 	/* so now we have some output space and some input data */
143 	x->zstat = BZ2_bzDecompress(&(x->z));
144 	/* the inflation output happens in the f buffer directly... */
145 	if (x->zstat == BZ_STREAM_END) {
146 	    /* deal with EOF, crc */
147 	    break;
148 	}
149 	if (x->zstat != BZ_OK) {
150 	    break;
151 	}
152     }
153     f->bufp = x->b;
154     f->left = BUFFILESIZE - x->z.avail_out;
155 
156     if (f->left >= 0) {
157 	f->left--;
158 	return *(f->bufp++);
159     } else {
160 	return BUFFILEEOF;
161     }
162 }
163 
164 /* there should be a BufCommonSkip... */
165 static int
BufBzip2FileSkip(BufFilePtr f,int c)166 BufBzip2FileSkip (BufFilePtr f, int c)
167 {
168     /* BufFileRawSkip returns the count unchanged.
169        BufCompressedSkip returns 0.
170        That means it probably never gets called... */
171     int retval = c;
172     while(c--) {
173 	int get = BufFileGet(f);
174 	if (get == BUFFILEEOF) return get;
175     }
176     return retval;
177 }
178