1 /** @file compression_stream.cc
2 * @brief class wrapper around zlib
4 /* Copyright (C) 2007,2009,2012,2013,2014,2016 Olly Betts
5 * Copyright (C) 2009 Richard Boulton
6 * Copyright (C) 2012 Dan Colish
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "compression_stream.h"
28 #include "stringutils.h"
30 #include "xapian/error.h"
34 CompressionStream::~CompressionStream() {
35 if (deflate_zstream
) {
36 // Errors which we care about have already been handled, so just ignore
37 // any which get returned here.
38 (void) deflateEnd(deflate_zstream
);
39 delete deflate_zstream
;
42 if (inflate_zstream
) {
43 // Errors which we care about have already been handled, so just ignore
44 // any which get returned here.
45 (void) inflateEnd(inflate_zstream
);
46 delete inflate_zstream
;
53 CompressionStream::compress(const char* buf
, size_t* p_size
) {
54 lazy_alloc_deflate_zstream();
55 size_t size
= *p_size
;
56 if (!out
|| out_len
< size
- 1) {
59 out
= new char[out_len
];
61 deflate_zstream
->avail_in
= static_cast<uInt
>(size
);
62 deflate_zstream
->next_in
=
63 reinterpret_cast<Bytef
*>(const_cast<char*>(buf
));
64 deflate_zstream
->next_out
= reinterpret_cast<Bytef
*>(out
);
65 deflate_zstream
->avail_out
= static_cast<uInt
>((size
- 1));
66 int zerr
= deflate(deflate_zstream
, Z_FINISH
);
67 if (zerr
!= Z_STREAM_END
) {
68 // Deflate failed - presumably the data wasn't compressible.
72 // If deflate succeeded, then the output was at least one byte smaller than
75 *p_size
= deflate_zstream
->total_out
;
80 CompressionStream::decompress_chunk(const char* p
, int len
, string
& buf
)
84 inflate_zstream
->next_in
=
85 reinterpret_cast<Bytef
*>(const_cast<char*>(p
));
86 inflate_zstream
->avail_in
= static_cast<uInt
>(len
);
89 inflate_zstream
->next_out
= blk
;
90 inflate_zstream
->avail_out
= static_cast<uInt
>(sizeof(blk
));
91 int err
= inflate(inflate_zstream
, Z_SYNC_FLUSH
);
92 if (err
!= Z_OK
&& err
!= Z_STREAM_END
) {
93 if (err
== Z_MEM_ERROR
) throw std::bad_alloc();
94 string msg
= "inflate failed";
95 if (inflate_zstream
->msg
) {
97 msg
+= inflate_zstream
->msg
;
100 throw Xapian::DatabaseError(msg
);
103 buf
.append(reinterpret_cast<const char *>(blk
),
104 inflate_zstream
->next_out
- blk
);
105 if (err
== Z_STREAM_END
) return true;
106 if (inflate_zstream
->avail_in
== 0) return false;
111 CompressionStream::lazy_alloc_deflate_zstream() {
112 if (usual(deflate_zstream
)) {
113 if (usual(deflateReset(deflate_zstream
) == Z_OK
)) return;
114 // Try to recover by deleting the stream and starting from scratch.
115 delete deflate_zstream
;
118 deflate_zstream
= new z_stream
;
120 deflate_zstream
->zalloc
= reinterpret_cast<alloc_func
>(0);
121 deflate_zstream
->zfree
= reinterpret_cast<free_func
>(0);
122 deflate_zstream
->opaque
= static_cast<voidpf
>(0);
124 // -15 means raw deflate with 32K LZ77 window (largest)
125 // memLevel 9 is the highest (8 is default)
126 int err
= deflateInit2(deflate_zstream
, Z_DEFAULT_COMPRESSION
, Z_DEFLATED
,
127 -15, 9, compress_strategy
);
128 if (rare(err
!= Z_OK
)) {
129 if (err
== Z_MEM_ERROR
) {
130 delete deflate_zstream
;
132 throw std::bad_alloc();
134 string msg
= "deflateInit2 failed (";
135 if (deflate_zstream
->msg
) {
136 msg
+= deflate_zstream
->msg
;
141 delete deflate_zstream
;
143 throw Xapian::DatabaseError(msg
);
148 CompressionStream::lazy_alloc_inflate_zstream() {
149 if (usual(inflate_zstream
)) {
150 if (usual(inflateReset(inflate_zstream
) == Z_OK
)) return;
151 // Try to recover by deleting the stream and starting from scratch.
152 delete inflate_zstream
;
155 inflate_zstream
= new z_stream
;
157 inflate_zstream
->zalloc
= reinterpret_cast<alloc_func
>(0);
158 inflate_zstream
->zfree
= reinterpret_cast<free_func
>(0);
160 inflate_zstream
->next_in
= Z_NULL
;
161 inflate_zstream
->avail_in
= 0;
163 int err
= inflateInit2(inflate_zstream
, -15);
164 if (rare(err
!= Z_OK
)) {
165 if (err
== Z_MEM_ERROR
) {
166 delete inflate_zstream
;
168 throw std::bad_alloc();
170 string msg
= "inflateInit2 failed (";
171 if (inflate_zstream
->msg
) {
172 msg
+= inflate_zstream
->msg
;
177 delete inflate_zstream
;
179 throw Xapian::DatabaseError(msg
);