xapian-core  2.0.0
compression_stream.cc
Go to the documentation of this file.
1 
4 /* Copyright (C) 2007,2009,2012,2013,2014,2016,2019 Olly Betts
5  * Copyright (C) 2009 Richard Boulton
6  * Copyright (C) 2012 Dan Colish
7  *
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.
12  *
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.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, see
20  * <https://www.gnu.org/licenses/>.
21  */
22 
23 #include <config.h>
24 #include "compression_stream.h"
25 
26 #include "omassert.h"
27 #include "str.h"
28 #include "stringutils.h"
29 
30 #include "xapian/error.h"
31 
32 using namespace std;
33 
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;
40  }
41 
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;
47  }
48 
49  delete [] out;
50 }
51 
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];
61  }
62  deflate_zstream->avail_in = static_cast<uInt>(size);
63  deflate_zstream->next_in = reinterpret_cast<const Bytef*>(buf);
64  deflate_zstream->next_out = reinterpret_cast<Bytef*>(out);
65  // Specify the output buffer size as being the size of the input so zlib
66  // will give up once it discovers it can't compress (while it might seem
67  // we could pass a buffer one byte smaller, in fact that doesn't actually
68  // work and results in us rejecting cases that compress saving one byte).
69  deflate_zstream->avail_out = static_cast<uInt>(size);
70  int zerr = deflate(deflate_zstream, Z_FINISH);
71  if (zerr != Z_STREAM_END) {
72  // Deflate failed - presumably the data wasn't compressible.
73  return NULL;
74  }
75 
76  if (deflate_zstream->total_out >= size) {
77  // It didn't get smaller.
78  return NULL;
79  }
80 
81  *p_size = deflate_zstream->total_out;
82  return out;
83 }
84 
85 bool
86 CompressionStream::decompress_chunk(const char* p, int len, string& buf)
87 {
88  Bytef blk[8192];
89 
90  inflate_zstream->next_in = reinterpret_cast<const Bytef*>(p);
91  inflate_zstream->avail_in = static_cast<uInt>(len);
92 
93  while (true) {
94  inflate_zstream->next_out = blk;
95  inflate_zstream->avail_out = static_cast<uInt>(sizeof(blk));
96  int err = inflate(inflate_zstream, Z_SYNC_FLUSH);
97  if (err != Z_OK && err != Z_STREAM_END) {
98  if (err == Z_MEM_ERROR) throw std::bad_alloc();
99  string msg = "inflate failed";
100  if (inflate_zstream->msg) {
101  msg += " (";
102  msg += inflate_zstream->msg;
103  msg += ')';
104  }
105  throw Xapian::DatabaseError(msg);
106  }
107 
108  buf.append(reinterpret_cast<const char*>(blk),
109  inflate_zstream->next_out - blk);
110  if (err == Z_STREAM_END) return true;
111  if (inflate_zstream->avail_in == 0) return false;
112  }
113 }
114 
115 void
117  if (usual(deflate_zstream)) {
118  if (usual(deflateReset(deflate_zstream) == Z_OK)) return;
119  // Try to recover by deleting the stream and starting from scratch.
120  delete deflate_zstream;
121  }
122 
123  deflate_zstream = new z_stream;
124 
125  deflate_zstream->zalloc = reinterpret_cast<alloc_func>(0);
126  deflate_zstream->zfree = reinterpret_cast<free_func>(0);
127  deflate_zstream->opaque = static_cast<voidpf>(0);
128 
129  // -15 means raw deflate with 32K LZ77 window (largest)
130  // memLevel 9 is the highest (8 is default)
131  int err = deflateInit2(deflate_zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
132  -15, 9, compress_strategy);
133  if (rare(err != Z_OK)) {
134  if (err == Z_MEM_ERROR) {
135  delete deflate_zstream;
136  deflate_zstream = 0;
137  throw std::bad_alloc();
138  }
139  string msg = "deflateInit2 failed (";
140  if (deflate_zstream->msg) {
141  msg += deflate_zstream->msg;
142  } else {
143  msg += str(err);
144  }
145  msg += ')';
146  delete deflate_zstream;
147  deflate_zstream = 0;
148  throw Xapian::DatabaseError(msg);
149  }
150 }
151 
152 void
154  if (usual(inflate_zstream)) {
155  if (usual(inflateReset(inflate_zstream) == Z_OK)) return;
156  // Try to recover by deleting the stream and starting from scratch.
157  delete inflate_zstream;
158  }
159 
160  inflate_zstream = new z_stream;
161 
162  inflate_zstream->zalloc = reinterpret_cast<alloc_func>(0);
163  inflate_zstream->zfree = reinterpret_cast<free_func>(0);
164 
165  inflate_zstream->next_in = Z_NULL;
166  inflate_zstream->avail_in = 0;
167 
168  int err = inflateInit2(inflate_zstream, -15);
169  if (rare(err != Z_OK)) {
170  if (err == Z_MEM_ERROR) {
171  delete inflate_zstream;
172  inflate_zstream = 0;
173  throw std::bad_alloc();
174  }
175  string msg = "inflateInit2 failed (";
176  if (inflate_zstream->msg) {
177  msg += inflate_zstream->msg;
178  } else {
179  msg += str(err);
180  }
181  msg += ')';
182  delete inflate_zstream;
183  inflate_zstream = 0;
184  throw Xapian::DatabaseError(msg);
185  }
186 }
void lazy_alloc_inflate_zstream()
Allocate the zstream for inflating, if not already allocated.
bool decompress_chunk(const char *p, int len, std::string &buf)
Returns true if this was the final chunk.
void lazy_alloc_deflate_zstream()
Allocate the zstream for deflating, if not already allocated.
const char * compress(const char *buf, size_t *p_size)
DatabaseError indicates some sort of database related error.
Definition: error.h:355
class wrapper around zlib
#define usual(COND)
Definition: config.h:608
#define rare(COND)
Definition: config.h:607
PositionList * p
Hierarchy of classes which Xapian can throw as exceptions.
string str(int value)
Convert int to std::string.
Definition: str.cc:91
Various assertion macros.
Convert types to std::string.
Various handy string-related helpers.