[ci] Enable IRC notifications from travis
[xapian.git] / xapian-core / common / compression_stream.cc
blobdf25ba439d4c32cad8f38a31f8eb0ae002c6ceb0
1 /** @file compression_stream.cc
2 * @brief class wrapper around zlib
3 */
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
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 - 1) {
57 out_len = size - 1;
58 delete [] out;
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.
69 return NULL;
72 // If deflate succeeded, then the output was at least one byte smaller than
73 // the input.
75 *p_size = deflate_zstream->total_out;
76 return out;
79 bool
80 CompressionStream::decompress_chunk(const char* p, int len, string & buf)
82 Bytef blk[8192];
84 inflate_zstream->next_in =
85 reinterpret_cast<Bytef*>(const_cast<char*>(p));
86 inflate_zstream->avail_in = static_cast<uInt>(len);
88 while (true) {
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) {
96 msg += " (";
97 msg += inflate_zstream->msg;
98 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;
110 void
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;
131 deflate_zstream = 0;
132 throw std::bad_alloc();
134 string msg = "deflateInit2 failed (";
135 if (deflate_zstream->msg) {
136 msg += deflate_zstream->msg;
137 } else {
138 msg += str(err);
140 msg += ')';
141 delete deflate_zstream;
142 deflate_zstream = 0;
143 throw Xapian::DatabaseError(msg);
147 void
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;
167 inflate_zstream = 0;
168 throw std::bad_alloc();
170 string msg = "inflateInit2 failed (";
171 if (inflate_zstream->msg) {
172 msg += inflate_zstream->msg;
173 } else {
174 msg += str(err);
176 msg += ')';
177 delete inflate_zstream;
178 inflate_zstream = 0;
179 throw Xapian::DatabaseError(msg);