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