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 : local int get_byte(gz_stream * s);
39 : local int destroy(gz_stream * s);
40 : local uLong getLong(gz_stream * s);
41 :
42 : /* ===========================================================================
43 : Opens a gzip (.gz) file for reading or writing. The mode parameter
44 : is as in fopen ("rb" or "wb"). The file is given either by file descriptor
45 : or path name (if fd == -1).
46 : gz_open return NULL if the file could not be opened or if there was
47 : insufficient memory to allocate the (de)compression state; errno
48 : can be checked to distinguish the two cases (if errno is zero, the
49 : zlib error is Z_MEM_ERROR).
50 : */
51 2 : gz_stream *gz_open(HStream & _stream)
52 : {
53 : int err;
54 : //int level = Z_DEFAULT_COMPRESSION; /* compression level */
55 :
56 : // char *p = (char*)mode;
57 : //char fmode[80]; /* copy of mode, without the compression level */
58 : //char *m = fmode;
59 : gz_stream *s;
60 :
61 2 : s = (gz_stream *) ALLOC(sizeof(gz_stream));
62 2 : if (!s)
63 0 : return Z_NULL;
64 2 : s->stream.zalloc = (alloc_func) 0;
65 2 : s->stream.zfree = (free_func) 0;
66 2 : s->stream.opaque = (voidpf) 0;
67 2 : s->stream.next_in = s->inbuf = Z_NULL;
68 2 : s->stream.next_out = s->outbuf = Z_NULL;
69 2 : s->stream.avail_in = s->stream.avail_out = 0;
70 : //s->_inputstream = NULL;
71 2 : s->z_err = Z_OK;
72 2 : s->z_eof = 0;
73 2 : s->crc = crc32(0L, Z_NULL, 0);
74 2 : s->msg = NULL;
75 2 : s->transparent = 0;
76 :
77 2 : s->mode = 'r';
78 :
79 : //realking
80 2 : err = inflateInit2(&(s->stream), -MAX_WBITS);
81 2 : s->stream.next_in = s->inbuf = (Byte *) ALLOC(Z_BUFSIZE);
82 :
83 2 : if (err != Z_OK || s->inbuf == Z_NULL)
84 : {
85 0 : return destroy(s), (gz_stream *) Z_NULL;
86 : }
87 :
88 2 : s->stream.avail_out = Z_BUFSIZE;
89 :
90 2 : errno = 0;
91 2 : s->_inputstream = &_stream;
92 :
93 2 : return (gz_stream *) s;
94 : }
95 :
96 :
97 : /* ===========================================================================
98 : Read a byte from a gz_stream; update next_in and avail_in. Return EOF
99 : for end of file.
100 : IN assertion: the stream s has been successfully opened for reading.
101 : */
102 16 : local int get_byte(gz_stream * s)
103 : {
104 16 : if (s->z_eof)
105 0 : return EOF;
106 16 : if (s->stream.avail_in == 0)
107 : {
108 0 : errno = 0;
109 :
110 0 : s->stream.avail_in = s->_inputstream->readBytes(s->inbuf, Z_BUFSIZE);
111 0 : if (s->stream.avail_in == 0)
112 : {
113 0 : s->z_eof = 1;
114 0 : return EOF;
115 : }
116 0 : s->stream.next_in = s->inbuf;
117 : }
118 16 : s->stream.avail_in--;
119 16 : return *(s->stream.next_in)++;
120 : }
121 :
122 :
123 : /* ===========================================================================
124 : * Cleanup then free the given gz_stream. Return a zlib error code.
125 : * Try freeing in the reverse order of allocations.
126 : */
127 2 : local int destroy(gz_stream * s)
128 : {
129 2 : int err = Z_OK;
130 :
131 2 : if (!s)
132 0 : return Z_STREAM_ERROR;
133 :
134 2 : TRYFREE(s->msg);
135 :
136 2 : if (s->stream.state != NULL)
137 : {
138 2 : err = inflateEnd(&(s->stream));
139 : }
140 2 : if (s->z_err < 0)
141 0 : err = s->z_err;
142 :
143 2 : TRYFREE(s->inbuf);
144 2 : TRYFREE(s->outbuf);
145 2 : TRYFREE(s);
146 2 : return err;
147 : }
148 :
149 :
150 : // typedef unsigned char Byte
151 : // typedef Byte FAR Bytef;
152 : /* ===========================================================================
153 : Reads the given number of uncompressed bytes from the compressed file.
154 : gz_read returns the number of bytes actually read (0 for end of file).
155 : */
156 6544 : int gz_read(gz_stream * file, voidp buf, unsigned len)
157 : {
158 : //printf("@@ gz_read : len : %d\t",len);
159 6544 : gz_stream *s = (gz_stream *) file;
160 6544 : Bytef *start = (Bytef *) buf; /* starting point for crc computation */
161 : Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
162 6544 : if (s == NULL)
163 0 : return Z_STREAM_ERROR;
164 :
165 6544 : if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)
166 0 : return -1;
167 6544 : if (s->z_err == Z_STREAM_END)
168 0 : return 0; /* EOF */
169 :
170 6544 : s->stream.next_out = next_out = (Bytef *) buf;
171 6544 : s->stream.avail_out = len;
172 :
173 19634 : while (s->stream.avail_out != 0)
174 : {
175 6548 : if (s->transparent)
176 : {
177 : /* Copy first the lookahead bytes: */
178 0 : uInt n = s->stream.avail_in;
179 :
180 0 : if (n > s->stream.avail_out)
181 0 : n = s->stream.avail_out;
182 0 : if (n > 0)
183 : {
184 0 : memcpy(s->stream.next_out, s->stream.next_in, n);
185 0 : next_out += n;
186 0 : s->stream.next_out = next_out;
187 0 : s->stream.next_in += n;
188 0 : s->stream.avail_out -= n;
189 0 : s->stream.avail_in -= n;
190 : }
191 0 : if (s->stream.avail_out > 0)
192 : {
193 : s->stream.avail_out -=
194 0 : s->_inputstream->readBytes(next_out, s->stream.avail_out);
195 : }
196 0 : return (int) (len - s->stream.avail_out);
197 : }
198 6548 : if (s->stream.avail_in == 0 && !s->z_eof)
199 : {
200 :
201 6 : errno = 0;
202 6 : s->stream.avail_in = s->_inputstream->readBytes(s->inbuf, Z_BUFSIZE);
203 6 : if (s->stream.avail_in == 0)
204 : {
205 0 : s->z_eof = 1;
206 0 : break;
207 : }
208 6 : s->stream.next_in = s->inbuf;
209 : }
210 6548 : s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
211 :
212 6548 : if (s->z_err == Z_STREAM_END)
213 : {
214 : /* Check CRC and original size */
215 2 : s->crc = crc32(s->crc, start, (uInt) (s->stream.next_out - start));
216 2 : start = s->stream.next_out;
217 :
218 2 : if (getLong(s) != s->crc || getLong(s) != s->stream.total_out)
219 : {
220 0 : s->z_err = Z_DATA_ERROR;
221 : }
222 2 : else if (s->z_err == Z_OK)
223 : {
224 0 : inflateReset(&(s->stream));
225 0 : s->crc = crc32(0L, Z_NULL, 0);
226 : }
227 : }
228 6548 : if (s->z_err != Z_OK || s->z_eof)
229 : break;
230 : }
231 6544 : s->crc = crc32(s->crc, start, (uInt) (s->stream.next_out - start));
232 6544 : return (int) (len - s->stream.avail_out);
233 : }
234 :
235 : /* ===========================================================================
236 : Flushes all pending output into the compressed file. The parameter
237 : flush is as in the deflate() function.
238 : gz_flush should be called only when strictly necessary because it can
239 : degrade compression.
240 : */
241 2 : int gz_flush(gz_stream * file, int flush)
242 : {
243 : uInt len;
244 2 : bool done = false;
245 2 : gz_stream *s = (gz_stream *) file;
246 :
247 2 : if (s == NULL || s->mode != 'w')
248 2 : return Z_STREAM_ERROR;
249 :
250 0 : s->stream.avail_in = 0; /* should be zero already anyway */
251 :
252 : for (;;)
253 : {
254 0 : len = Z_BUFSIZE - s->stream.avail_out;
255 0 : if (len != 0)
256 : {
257 : /*
258 : if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
259 : s->z_err = Z_ERRNO;
260 : return Z_ERRNO;
261 : }
262 : */
263 0 : s->stream.next_out = s->outbuf;
264 0 : s->stream.avail_out = Z_BUFSIZE;
265 : }
266 0 : if (done)
267 0 : break;
268 0 : s->z_err = deflate(&(s->stream), flush);
269 :
270 : /* deflate has finished flushing only when it hasn't used up
271 : * all the available space in the output buffer:
272 : */
273 0 : done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
274 :
275 0 : if (s->z_err != Z_OK && s->z_err != Z_STREAM_END)
276 0 : break;
277 : }
278 0 : return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
279 : }
280 :
281 :
282 : /* ===========================================================================
283 : Reads a long in LSB order from the given gz_stream. Sets
284 : */
285 4 : local uLong getLong(gz_stream * s)
286 : {
287 4 : uLong x = (unsigned char) get_byte(s);
288 :
289 4 : x += ((unsigned char) get_byte(s)) << 8;
290 4 : x += ((unsigned char) get_byte(s)) << 16;
291 4 : x += ((unsigned char) get_byte(s)) << 24;
292 4 : if (s->z_eof)
293 : {
294 0 : s->z_err = Z_DATA_ERROR;
295 : }
296 4 : return x;
297 : }
298 :
299 :
300 : /* ===========================================================================
301 : Flushes all pending output if necessary, closes the compressed file
302 : and deallocates all the (de)compression state.
303 : */
304 2 : int gz_close(gz_stream * file)
305 : {
306 : // int err;
307 2 : gz_stream *s = (gz_stream *) file;
308 :
309 2 : if (s == NULL)
310 0 : return Z_STREAM_ERROR;
311 : #if 0
312 : if (s->mode == 'w')
313 : {
314 : err = gz_flush(file, Z_FINISH);
315 : if (err != Z_OK)
316 : return destroy(s);
317 : putLong(s->file, s->crc);
318 : putLong(s->file, s->stream.total_in);
319 : }
320 : #endif
321 2 : return destroy(s);
322 : }
323 :
324 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|