1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "precompile.h"
22 #include <sal/types.h>
28 #include "hstream.hxx"
30 #define Z_BUFSIZE (1024 * 4)
32 #define ALLOC(size) malloc(size)
33 #define TRYFREE(p) {if (p) free(p);}
35 static unsigned char get_byte(gz_stream
* s
);
36 static int destroy(gz_stream
* s
);
37 static bool getLongEquals(gz_stream
* s
, uLong value
);
39 /* ===========================================================================
40 Opens a gzip (.gz) file for reading or writing. The mode parameter
41 is as in fopen ("rb" or "wb"). The file is given either by file descriptor
42 or path name (if fd == -1).
43 gz_open return NULL if the file could not be opened or if there was
44 insufficient memory to allocate the (de)compression state; errno
45 can be checked to distinguish the two cases (if errno is zero, the
46 zlib error is Z_MEM_ERROR).
48 gz_stream
*gz_open(HStream
& _stream
)
51 //int level = Z_DEFAULT_COMPRESSION; /* compression level */
53 // char *p = (char*)mode;
54 //char fmode[80]; /* copy of mode, without the compression level */
58 s
= static_cast<gz_stream
*>(ALLOC(sizeof(gz_stream
)));
61 s
->stream
.zalloc
= nullptr;
62 s
->stream
.zfree
= nullptr;
63 s
->stream
.opaque
= nullptr;
64 s
->stream
.next_in
= s
->inbuf
= Z_NULL
;
65 s
->stream
.next_out
= Z_NULL
;
66 s
->stream
.avail_in
= s
->stream
.avail_out
= 0;
67 //s->_inputstream = NULL;
70 s
->crc
= crc32(0, Z_NULL
, 0);
76 err
= inflateInit2(&(s
->stream
), -MAX_WBITS
);
77 s
->stream
.next_in
= s
->inbuf
= static_cast<Byte
*>(ALLOC(Z_BUFSIZE
));
79 if (err
!= Z_OK
|| s
->inbuf
== Z_NULL
)
85 s
->stream
.avail_out
= Z_BUFSIZE
;
88 s
->_inputstream
= &_stream
;
94 /* ===========================================================================
95 Read a byte from a gz_stream; update next_in and avail_in. EOF is flagged
97 IN assertion: the stream s has been successfully opened for reading.
99 static unsigned char get_byte(gz_stream
* s
)
103 if (s
->stream
.avail_in
== 0)
107 s
->stream
.avail_in
= s
->_inputstream
->readBytes(s
->inbuf
, Z_BUFSIZE
);
108 if (s
->stream
.avail_in
== 0)
113 s
->stream
.next_in
= s
->inbuf
;
115 s
->stream
.avail_in
--;
116 return *(s
->stream
.next_in
)++;
120 /* ===========================================================================
121 * Cleanup then free the given gz_stream. Return a zlib error code.
122 * Try freeing in the reverse order of allocations.
124 static int destroy(gz_stream
* s
)
129 return Z_STREAM_ERROR
;
133 if (s
->stream
.state
!= nullptr)
135 err
= inflateEnd(&(s
->stream
));
146 // typedef unsigned char Byte
147 // typedef Byte Bytef;
148 /* ===========================================================================
149 Reads the given number of uncompressed bytes from the compressed file.
150 gz_read returns the number of bytes actually read (0 for end of file).
152 size_t gz_read(gz_stream
* file
, voidp buf
, unsigned len
)
154 //printf("@@ gz_read : len : %d\t",len);
156 Bytef
*start
= static_cast<Bytef
*>(buf
); /* starting point for crc computation */
163 if (s
->z_err
== Z_DATA_ERROR
|| s
->z_err
== Z_ERRNO
)
165 if (s
->z_err
== Z_STREAM_END
)
168 s
->stream
.next_out
= static_cast<Bytef
*>(buf
);
169 s
->stream
.avail_out
= len
;
171 while (s
->stream
.avail_out
!= 0)
173 if (s
->stream
.avail_in
== 0 && !s
->z_eof
)
177 s
->stream
.avail_in
= s
->_inputstream
->readBytes(s
->inbuf
, Z_BUFSIZE
);
178 if (s
->stream
.avail_in
== 0)
183 s
->stream
.next_in
= s
->inbuf
;
185 s
->z_err
= inflate(&(s
->stream
), Z_NO_FLUSH
);
187 if (s
->z_err
== Z_STREAM_END
)
189 /* Check CRC and original size */
190 s
->crc
= crc32(s
->crc
, start
, static_cast<uInt
>(s
->stream
.next_out
- start
));
191 start
= s
->stream
.next_out
;
193 if (!getLongEquals(s
, s
->crc
) || !getLongEquals(s
, s
->stream
.total_out
))
195 s
->z_err
= Z_DATA_ERROR
;
197 else if (s
->z_err
== Z_OK
)
199 inflateReset(&(s
->stream
));
200 s
->crc
= crc32(0, Z_NULL
, 0);
203 if (s
->z_err
!= Z_OK
|| s
->z_eof
)
206 s
->crc
= crc32(s
->crc
, start
, static_cast<uInt
>(s
->stream
.next_out
- start
));
207 return len
- s
->stream
.avail_out
;
210 /* ===========================================================================
211 Flushes all pending output into the compressed file. The parameter
212 flush is as in the deflate() function.
213 gz_flush should be called only when strictly necessary because it can
216 int gz_flush(gz_stream
* file
, int flush
)
222 if (s
== nullptr || s
->mode
!= 'w')
223 return Z_STREAM_ERROR
;
225 s
->stream
.avail_in
= 0; /* should be zero already anyway */
229 len
= Z_BUFSIZE
- s
->stream
.avail_out
;
233 if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
238 s
->stream
.next_out
= nullptr;
239 s
->stream
.avail_out
= Z_BUFSIZE
;
243 s
->z_err
= deflate(&(s
->stream
), flush
);
245 /* deflate has finished flushing only when it hasn't used up
246 * all the available space in the output buffer:
248 done
= (s
->stream
.avail_out
!= 0 || s
->z_err
== Z_STREAM_END
);
250 if (s
->z_err
!= Z_OK
&& s
->z_err
!= Z_STREAM_END
)
253 return s
->z_err
== Z_STREAM_END
? Z_OK
: s
->z_err
;
257 /* ===========================================================================
258 Reads a long in LSB order from the given gz_stream and compares for equality
261 static bool getLongEquals(gz_stream
* s
, uLong val
)
263 uLong x
= get_byte(s
);
264 x
+= static_cast<sal_uInt32
>(get_byte(s
)) << 8;
265 x
+= static_cast<sal_uInt32
>(get_byte(s
)) << 16;
266 x
+= static_cast<sal_uInt32
>(get_byte(s
)) << 24;
269 s
->z_err
= Z_DATA_ERROR
;
276 /* ===========================================================================
277 Flushes all pending output if necessary, closes the compressed file
278 and deallocates all the (de)compression state.
280 int gz_close(gz_stream
* file
)
286 return Z_STREAM_ERROR
;
290 err
= gz_flush(file
, Z_FINISH
);
293 putLong(s
->file
, s
->crc
);
294 putLong(s
->file
, s
->stream
.total_in
);
300 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */