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