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