Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "precompile.h"
21 :
22 : #include <stdio.h>
23 : #include <string.h>
24 : #include <stdlib.h>
25 : #include <errno.h>
26 : #include "hgzip.h"
27 : #include "hstream.h"
28 :
29 : #ifndef local
30 : # define local static
31 : #endif
32 :
33 : #define Z_BUFSIZE (1024 * 4)
34 :
35 : #define ALLOC(size) malloc(size)
36 : #define TRYFREE(p) {if (p) free(p);}
37 :
38 : #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
39 : #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
40 : #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
41 : #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
42 : #define COMMENT 0x10 /* bit 4 set: file comment present */
43 : #define RESERVED 0xE0 /* bits 5..7: reserved */
44 :
45 : local int get_byte(gz_stream * s);
46 : local int destroy(gz_stream * s);
47 : local uLong getLong(gz_stream * s);
48 :
49 : /* ===========================================================================
50 : Opens a gzip (.gz) file for reading or writing. The mode parameter
51 : is as in fopen ("rb" or "wb"). The file is given either by file descriptor
52 : or path name (if fd == -1).
53 : gz_open return NULL if the file could not be opened or if there was
54 : insufficient memory to allocate the (de)compression state; errno
55 : can be checked to distinguish the two cases (if errno is zero, the
56 : zlib error is Z_MEM_ERROR).
57 : */
58 1 : gz_stream *gz_open(HStream & _stream)
59 : {
60 : int err;
61 : //int level = Z_DEFAULT_COMPRESSION; /* compression level */
62 :
63 : // char *p = (char*)mode;
64 : //char fmode[80]; /* copy of mode, without the compression level */
65 : //char *m = fmode;
66 : gz_stream *s;
67 :
68 1 : s = (gz_stream *) ALLOC(sizeof(gz_stream));
69 1 : if (!s)
70 0 : return Z_NULL;
71 1 : s->stream.zalloc = (alloc_func) 0;
72 1 : s->stream.zfree = (free_func) 0;
73 1 : s->stream.opaque = (voidpf) 0;
74 1 : s->stream.next_in = s->inbuf = Z_NULL;
75 1 : s->stream.next_out = s->outbuf = Z_NULL;
76 1 : s->stream.avail_in = s->stream.avail_out = 0;
77 : //s->_inputstream = NULL;
78 1 : s->z_err = Z_OK;
79 1 : s->z_eof = 0;
80 1 : s->crc = crc32(0L, Z_NULL, 0);
81 1 : s->msg = NULL;
82 1 : s->transparent = 0;
83 :
84 1 : s->mode = 'r';
85 :
86 : //realking
87 1 : err = inflateInit2(&(s->stream), -MAX_WBITS);
88 1 : s->stream.next_in = s->inbuf = (Byte *) ALLOC(Z_BUFSIZE);
89 :
90 1 : if (err != Z_OK || s->inbuf == Z_NULL)
91 : {
92 0 : return destroy(s), (gz_stream *) Z_NULL;
93 : }
94 :
95 1 : s->stream.avail_out = Z_BUFSIZE;
96 :
97 1 : errno = 0;
98 1 : s->_inputstream = &_stream;
99 :
100 1 : return (gz_stream *) s;
101 : }
102 :
103 :
104 : /* ===========================================================================
105 : Read a byte from a gz_stream; update next_in and avail_in. Return EOF
106 : for end of file.
107 : IN assertion: the stream s has been sucessfully opened for reading.
108 : */
109 8 : local int get_byte(gz_stream * s)
110 : {
111 8 : if (s->z_eof)
112 0 : return EOF;
113 8 : if (s->stream.avail_in == 0)
114 : {
115 0 : errno = 0;
116 :
117 0 : s->stream.avail_in = s->_inputstream->readBytes(s->inbuf, Z_BUFSIZE);
118 0 : if (s->stream.avail_in == 0)
119 : {
120 0 : s->z_eof = 1;
121 0 : return EOF;
122 : }
123 0 : s->stream.next_in = s->inbuf;
124 : }
125 8 : s->stream.avail_in--;
126 8 : return *(s->stream.next_in)++;
127 : }
128 :
129 :
130 : /* ===========================================================================
131 : * Cleanup then free the given gz_stream. Return a zlib error code.
132 : * Try freeing in the reverse order of allocations.
133 : */
134 1 : local int destroy(gz_stream * s)
135 : {
136 1 : int err = Z_OK;
137 :
138 1 : if (!s)
139 0 : return Z_STREAM_ERROR;
140 :
141 1 : TRYFREE(s->msg);
142 :
143 1 : if (s->stream.state != NULL)
144 : {
145 1 : err = inflateEnd(&(s->stream));
146 : }
147 1 : if (s->z_err < 0)
148 0 : err = s->z_err;
149 :
150 1 : TRYFREE(s->inbuf);
151 1 : TRYFREE(s->outbuf);
152 1 : TRYFREE(s);
153 1 : return err;
154 : }
155 :
156 :
157 : // typedef unsigned char Byte
158 : // typedef Byte FAR Bytef;
159 : /* ===========================================================================
160 : Reads the given number of uncompressed bytes from the compressed file.
161 : gz_read returns the number of bytes actually read (0 for end of file).
162 : */
163 3272 : int gz_read(gz_stream * file, voidp buf, unsigned len)
164 : {
165 : //printf("@@ gz_read : len : %d\t",len);
166 3272 : gz_stream *s = (gz_stream *) file;
167 3272 : Bytef *start = (Bytef *) buf; /* starting point for crc computation */
168 : Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
169 3272 : if (s == NULL)
170 0 : return Z_STREAM_ERROR;
171 :
172 3272 : if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)
173 0 : return -1;
174 3272 : if (s->z_err == Z_STREAM_END)
175 0 : return 0; /* EOF */
176 :
177 3272 : s->stream.next_out = next_out = (Bytef *) buf;
178 3272 : s->stream.avail_out = len;
179 :
180 9817 : while (s->stream.avail_out != 0)
181 : {
182 3274 : if (s->transparent)
183 : {
184 : /* Copy first the lookahead bytes: */
185 0 : uInt n = s->stream.avail_in;
186 :
187 0 : if (n > s->stream.avail_out)
188 0 : n = s->stream.avail_out;
189 0 : if (n > 0)
190 : {
191 0 : memcpy(s->stream.next_out, s->stream.next_in, n);
192 0 : next_out += n;
193 0 : s->stream.next_out = next_out;
194 0 : s->stream.next_in += n;
195 0 : s->stream.avail_out -= n;
196 0 : s->stream.avail_in -= n;
197 : }
198 0 : if (s->stream.avail_out > 0)
199 : {
200 : s->stream.avail_out -=
201 0 : s->_inputstream->readBytes(next_out, s->stream.avail_out);
202 : }
203 0 : return (int) (len - s->stream.avail_out);
204 : }
205 3274 : if (s->stream.avail_in == 0 && !s->z_eof)
206 : {
207 :
208 3 : errno = 0;
209 3 : s->stream.avail_in = s->_inputstream->readBytes(s->inbuf, Z_BUFSIZE);
210 3 : if (s->stream.avail_in == 0)
211 : {
212 0 : s->z_eof = 1;
213 0 : break;
214 : }
215 3 : s->stream.next_in = s->inbuf;
216 : }
217 3274 : s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
218 :
219 3274 : if (s->z_err == Z_STREAM_END)
220 : {
221 : /* Check CRC and original size */
222 1 : s->crc = crc32(s->crc, start, (uInt) (s->stream.next_out - start));
223 1 : start = s->stream.next_out;
224 :
225 1 : if (getLong(s) != s->crc || getLong(s) != s->stream.total_out)
226 : {
227 0 : s->z_err = Z_DATA_ERROR;
228 : }
229 1 : else if (s->z_err == Z_OK)
230 : {
231 0 : inflateReset(&(s->stream));
232 0 : s->crc = crc32(0L, Z_NULL, 0);
233 : }
234 : }
235 3274 : if (s->z_err != Z_OK || s->z_eof)
236 1 : break;
237 : }
238 3272 : s->crc = crc32(s->crc, start, (uInt) (s->stream.next_out - start));
239 3272 : return (int) (len - s->stream.avail_out);
240 : }
241 :
242 : /* ===========================================================================
243 : Flushes all pending output into the compressed file. The parameter
244 : flush is as in the deflate() function.
245 : gz_flush should be called only when strictly necessary because it can
246 : degrade compression.
247 : */
248 1 : int gz_flush(gz_stream * file, int flush)
249 : {
250 : uInt len;
251 1 : int done = 0;
252 1 : gz_stream *s = (gz_stream *) file;
253 :
254 1 : if (s == NULL || s->mode != 'w')
255 1 : return Z_STREAM_ERROR;
256 :
257 0 : s->stream.avail_in = 0; /* should be zero already anyway */
258 :
259 0 : for (;;)
260 : {
261 0 : len = Z_BUFSIZE - s->stream.avail_out;
262 0 : if (len != 0)
263 : {
264 : /*
265 : if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
266 : s->z_err = Z_ERRNO;
267 : return Z_ERRNO;
268 : }
269 : */
270 0 : s->stream.next_out = s->outbuf;
271 0 : s->stream.avail_out = Z_BUFSIZE;
272 : }
273 0 : if (done)
274 0 : break;
275 0 : s->z_err = deflate(&(s->stream), flush);
276 :
277 : /* deflate has finished flushing only when it hasn't used up
278 : * all the available space in the output buffer:
279 : */
280 0 : done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
281 :
282 0 : if (s->z_err != Z_OK && s->z_err != Z_STREAM_END)
283 0 : break;
284 : }
285 0 : return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
286 : }
287 :
288 :
289 : /* ===========================================================================
290 : Reads a long in LSB order from the given gz_stream. Sets
291 : */
292 2 : local uLong getLong(gz_stream * s)
293 : {
294 2 : uLong x = (uLong) get_byte(s);
295 : int c;
296 :
297 2 : x += ((uLong) get_byte(s)) << 8;
298 2 : x += ((uLong) get_byte(s)) << 16;
299 2 : c = get_byte(s);
300 2 : if (c == EOF)
301 0 : s->z_err = Z_DATA_ERROR;
302 2 : x += ((uLong) c) << 24;
303 2 : return x;
304 : }
305 :
306 :
307 : /* ===========================================================================
308 : Flushes all pending output if necessary, closes the compressed file
309 : and deallocates all the (de)compression state.
310 : */
311 1 : int gz_close(gz_stream * file)
312 : {
313 : // int err;
314 1 : gz_stream *s = (gz_stream *) file;
315 :
316 1 : if (s == NULL)
317 0 : return Z_STREAM_ERROR;
318 : #if 0
319 : if (s->mode == 'w')
320 : {
321 : err = gz_flush(file, Z_FINISH);
322 : if (err != Z_OK)
323 : return destroy(s);
324 : putLong(s->file, s->crc);
325 : putLong(s->file, s->stream.total_in);
326 : }
327 : #endif
328 1 : return destroy(s);
329 : }
330 :
331 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|