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.
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
38typedef 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
46static int BufBzip2FileClose ( BufFilePtr f, int flag );
47static int BufBzip2FileFill ( BufFilePtr f );
48static int BufBzip2FileSkip ( BufFilePtr f, int c );
49
50_X_HIDDEN BufFilePtr
51BufFilePushBZIP2 (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
82static int
83BufBzip2FileClose(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*/
100static int
101BufBzip2FileFill (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... */
165static int
166BufBzip2FileSkip (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