xapian-core  1.4.27
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, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
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 =
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;
75  }
76 
77  if (deflate_zstream->total_out >= size) {
78  // It didn't get smaller.
79  return NULL;
80  }
81 
82  *p_size = deflate_zstream->total_out;
83  return out;
84 }
85 
86 bool
87 CompressionStream::decompress_chunk(const char* p, int len, string& buf)
88 {
89  Bytef blk[8192];
90 
91  inflate_zstream->next_in =
92  reinterpret_cast<Bytef*>(const_cast<char*>(p));
93  inflate_zstream->avail_in = static_cast<uInt>(len);
94 
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 += ')';
106  }
107  throw Xapian::DatabaseError(msg);
108  }
109 
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;
114  }
115 }
116 
117 void
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;
123  }
124 
125  deflate_zstream = new z_stream;
126 
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);
130 
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();
140  }
141  string msg = "deflateInit2 failed (";
142  if (deflate_zstream->msg) {
143  msg += deflate_zstream->msg;
144  } else {
145  msg += str(err);
146  }
147  msg += ')';
148  delete deflate_zstream;
149  deflate_zstream = 0;
150  throw Xapian::DatabaseError(msg);
151  }
152 }
153 
154 void
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;
160  }
161 
162  inflate_zstream = new z_stream;
163 
164  inflate_zstream->zalloc = reinterpret_cast<alloc_func>(0);
165  inflate_zstream->zfree = reinterpret_cast<free_func>(0);
166 
167  inflate_zstream->next_in = Z_NULL;
168  inflate_zstream->avail_in = 0;
169 
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();
176  }
177  string msg = "inflateInit2 failed (";
178  if (inflate_zstream->msg) {
179  msg += inflate_zstream->msg;
180  } else {
181  msg += str(err);
182  }
183  msg += ')';
184  delete inflate_zstream;
185  inflate_zstream = 0;
186  throw Xapian::DatabaseError(msg);
187  }
188 }
void lazy_alloc_inflate_zstream()
Allocate the zstream for inflating, if not already allocated.
#define usual(COND)
Definition: config.h:576
const char * compress(const char *buf, size_t *p_size)
STL namespace.
Convert types to std::string.
#define rare(COND)
Definition: config.h:575
Hierarchy of classes which Xapian can throw as exceptions.
class wrapper around zlib
void lazy_alloc_deflate_zstream()
Allocate the zstream for deflating, if not already allocated.
bool decompress_chunk(const char *p, int len, std::string &buf)
Returns true if this was the final chunk.
string str(int value)
Convert int to std::string.
Definition: str.cc:90
Various handy helpers which std::string really should provide.
Various assertion macros.
DatabaseError indicates some sort of database related error.
Definition: error.h:367