Update for 1.4.18
[xapian.git] / xapian-core / common / compression_stream.cc
blob8696f9950308f781e91b3e3d58e5b62e0d678198
1 /** @file
2 * @brief class wrapper around zlib
3 */
4 /* Copyright (C) 2007,2009,2012,2013,2014,2016,2019 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
23 #include <config.h>
24 #include "compression_stream.h"
26 #include "omassert.h"
27 #include "str.h"
28 #include "stringutils.h"
30 #include "xapian/error.h"
32 using namespace std;
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;
49 delete [] out;
52 const char*
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) {
57 out_len = size;
58 delete [] out;
59 out = NULL;
60 out = new char[size];
62 deflate_zstream->avail_in = static_cast<uInt>(size);
63 deflate_zstream->next_in =
64 reinterpret_cast<Bytef*>(const_cast<char*>(buf));
65 deflate_zstream->next_out = reinterpret_cast<Bytef*>(out);
66 // Specify the output buffer size as being the size of the input so zlib
67 // will give up once it discovers it can't compress (while it might seem
68 // we could pass a buffer one byte smaller, in fact that doesn't actually
69 // work and results in us rejecting cases that compress saving one byte).
70 deflate_zstream->avail_out = static_cast<uInt>(size);
71 int zerr = deflate(deflate_zstream, Z_FINISH);
72 if (zerr != Z_STREAM_END) {
73 // Deflate failed - presumably the data wasn't compressible.
74 return NULL;
77 if (deflate_zstream->total_out >= size) {
78 // It didn't get smaller.
79 return NULL;
82 *p_size = deflate_zstream->total_out;
83 return out;
86 bool
87 CompressionStream::decompress_chunk(const char* p, int len, string& buf)
89 Bytef blk[8192];
91 inflate_zstream->next_in =
92 reinterpret_cast<Bytef*>(const_cast<char*>(p));
93 inflate_zstream->avail_in = static_cast<uInt>(len);
95 while (true) {
96 inflate_zstream->next_out = blk;
97 inflate_zstream->avail_out = static_cast<uInt>(sizeof(blk));
98 int err = inflate(inflate_zstream, Z_SYNC_FLUSH);
99 if (err != Z_OK && err != Z_STREAM_END) {
100 if (err == Z_MEM_ERROR) throw std::bad_alloc();
101 string msg = "inflate failed";
102 if (inflate_zstream->msg) {
103 msg += " (";
104 msg += inflate_zstream->msg;
105 msg += ')';
107 throw Xapian::DatabaseError(msg);
110 buf.append(reinterpret_cast<const char*>(blk),
111 inflate_zstream->next_out - blk);
112 if (err == Z_STREAM_END) return true;
113 if (inflate_zstream->avail_in == 0) return false;
117 void
118 CompressionStream::lazy_alloc_deflate_zstream() {
119 if (usual(deflate_zstream)) {
120 if (usual(deflateReset(deflate_zstream) == Z_OK)) return;
121 // Try to recover by deleting the stream and starting from scratch.
122 delete deflate_zstream;
125 deflate_zstream = new z_stream;
127 deflate_zstream->zalloc = reinterpret_cast<alloc_func>(0);
128 deflate_zstream->zfree = reinterpret_cast<free_func>(0);
129 deflate_zstream->opaque = static_cast<voidpf>(0);
131 // -15 means raw deflate with 32K LZ77 window (largest)
132 // memLevel 9 is the highest (8 is default)
133 int err = deflateInit2(deflate_zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
134 -15, 9, compress_strategy);
135 if (rare(err != Z_OK)) {
136 if (err == Z_MEM_ERROR) {
137 delete deflate_zstream;
138 deflate_zstream = 0;
139 throw std::bad_alloc();
141 string msg = "deflateInit2 failed (";
142 if (deflate_zstream->msg) {
143 msg += deflate_zstream->msg;
144 } else {
145 msg += str(err);
147 msg += ')';
148 delete deflate_zstream;
149 deflate_zstream = 0;
150 throw Xapian::DatabaseError(msg);
154 void
155 CompressionStream::lazy_alloc_inflate_zstream() {
156 if (usual(inflate_zstream)) {
157 if (usual(inflateReset(inflate_zstream) == Z_OK)) return;
158 // Try to recover by deleting the stream and starting from scratch.
159 delete inflate_zstream;
162 inflate_zstream = new z_stream;
164 inflate_zstream->zalloc = reinterpret_cast<alloc_func>(0);
165 inflate_zstream->zfree = reinterpret_cast<free_func>(0);
167 inflate_zstream->next_in = Z_NULL;
168 inflate_zstream->avail_in = 0;
170 int err = inflateInit2(inflate_zstream, -15);
171 if (rare(err != Z_OK)) {
172 if (err == Z_MEM_ERROR) {
173 delete inflate_zstream;
174 inflate_zstream = 0;
175 throw std::bad_alloc();
177 string msg = "inflateInit2 failed (";
178 if (inflate_zstream->msg) {
179 msg += inflate_zstream->msg;
180 } else {
181 msg += str(err);
183 msg += ')';
184 delete inflate_zstream;
185 inflate_zstream = 0;
186 throw Xapian::DatabaseError(msg);