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