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"
27 #include "hstream.hxx"
29 #define Z_BUFSIZE (1024 * 4)
31 #define ALLOC(size) malloc(size)
32 #define TRYFREE(p) {if (p) free(p);}
34 static int get_byte(gz_stream
* s
);
35 static int destroy(gz_stream
* s
);
36 static uLong
getLong(gz_stream
* s
);
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).
47 gz_stream
*gz_open(HStream
& _stream
)
50 //int level = Z_DEFAULT_COMPRESSION; /* compression level */
52 // char *p = (char*)mode;
53 //char fmode[80]; /* copy of mode, without the compression level */
57 s
= static_cast<gz_stream
*>(ALLOC(sizeof(gz_stream
)));
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;
69 s
->crc
= crc32(0, Z_NULL
, 0);
75 err
= inflateInit2(&(s
->stream
), -MAX_WBITS
);
76 s
->stream
.next_in
= s
->inbuf
= static_cast<Byte
*>(ALLOC(Z_BUFSIZE
));
78 if (err
!= Z_OK
|| s
->inbuf
== Z_NULL
)
84 s
->stream
.avail_out
= Z_BUFSIZE
;
87 s
->_inputstream
= &_stream
;
93 /* ===========================================================================
94 Read a byte from a gz_stream; update next_in and avail_in. Return EOF
96 IN assertion: the stream s has been successfully opened for reading.
98 static int get_byte(gz_stream
* s
)
102 if (s
->stream
.avail_in
== 0)
106 s
->stream
.avail_in
= s
->_inputstream
->readBytes(s
->inbuf
, Z_BUFSIZE
);
107 if (s
->stream
.avail_in
== 0)
112 s
->stream
.next_in
= s
->inbuf
;
114 s
->stream
.avail_in
--;
115 return *(s
->stream
.next_in
)++;
119 /* ===========================================================================
120 * Cleanup then free the given gz_stream. Return a zlib error code.
121 * Try freeing in the reverse order of allocations.
123 static int destroy(gz_stream
* s
)
128 return Z_STREAM_ERROR
;
132 if (s
->stream
.state
!= nullptr)
134 err
= inflateEnd(&(s
->stream
));
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).
151 size_t gz_read(gz_stream
* file
, voidp buf
, unsigned len
)
153 //printf("@@ gz_read : len : %d\t",len);
155 Bytef
*start
= static_cast<Bytef
*>(buf
); /* starting point for crc computation */
162 if (s
->z_err
== Z_DATA_ERROR
|| s
->z_err
== Z_ERRNO
)
164 if (s
->z_err
== Z_STREAM_END
)
167 s
->stream
.next_out
= static_cast<Bytef
*>(buf
);
168 s
->stream
.avail_out
= len
;
170 while (s
->stream
.avail_out
!= 0)
172 if (s
->stream
.avail_in
== 0 && !s
->z_eof
)
176 s
->stream
.avail_in
= s
->_inputstream
->readBytes(s
->inbuf
, Z_BUFSIZE
);
177 if (s
->stream
.avail_in
== 0)
182 s
->stream
.next_in
= s
->inbuf
;
184 s
->z_err
= inflate(&(s
->stream
), Z_NO_FLUSH
);
186 if (s
->z_err
== Z_STREAM_END
)
188 /* Check CRC and original size */
189 s
->crc
= crc32(s
->crc
, start
, static_cast<uInt
>(s
->stream
.next_out
- start
));
190 start
= s
->stream
.next_out
;
192 if (getLong(s
) != s
->crc
|| getLong(s
) != s
->stream
.total_out
)
194 s
->z_err
= Z_DATA_ERROR
;
196 else if (s
->z_err
== Z_OK
)
198 inflateReset(&(s
->stream
));
199 s
->crc
= crc32(0, Z_NULL
, 0);
202 if (s
->z_err
!= Z_OK
|| s
->z_eof
)
205 s
->crc
= crc32(s
->crc
, start
, static_cast<uInt
>(s
->stream
.next_out
- start
));
206 return len
- s
->stream
.avail_out
;
209 /* ===========================================================================
210 Flushes all pending output into the compressed file. The parameter
211 flush is as in the deflate() function.
212 gz_flush should be called only when strictly necessary because it can
215 int gz_flush(gz_stream
* file
, int flush
)
221 if (s
== nullptr || s
->mode
!= 'w')
222 return Z_STREAM_ERROR
;
224 s
->stream
.avail_in
= 0; /* should be zero already anyway */
228 len
= Z_BUFSIZE
- s
->stream
.avail_out
;
232 if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
237 s
->stream
.next_out
= nullptr;
238 s
->stream
.avail_out
= Z_BUFSIZE
;
242 s
->z_err
= deflate(&(s
->stream
), flush
);
244 /* deflate has finished flushing only when it hasn't used up
245 * all the available space in the output buffer:
247 done
= (s
->stream
.avail_out
!= 0 || s
->z_err
== Z_STREAM_END
);
249 if (s
->z_err
!= Z_OK
&& s
->z_err
!= Z_STREAM_END
)
252 return s
->z_err
== Z_STREAM_END
? Z_OK
: s
->z_err
;
256 /* ===========================================================================
257 Reads a long in LSB order from the given gz_stream. Sets
259 static uLong
getLong(gz_stream
* s
)
261 uLong x
= static_cast<unsigned char>(get_byte(s
));
263 x
+= static_cast<unsigned char>(get_byte(s
)) << 8;
264 x
+= static_cast<unsigned char>(get_byte(s
)) << 16;
265 x
+= static_cast<unsigned char>(get_byte(s
)) << 24;
268 s
->z_err
= Z_DATA_ERROR
;
274 /* ===========================================================================
275 Flushes all pending output if necessary, closes the compressed file
276 and deallocates all the (de)compression state.
278 int gz_close(gz_stream
* file
)
284 return Z_STREAM_ERROR
;
288 err
= gz_flush(file
, Z_FINISH
);
291 putLong(s
->file
, s
->crc
);
292 putLong(s
->file
, s
->stream
.total_in
);
298 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */