Line data Source code
1 : /*
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 : *
6 : * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
7 : */
8 :
9 : /* streams working on a lzma/xz-compressed disk file */
10 :
11 : #include "monetdb_config.h"
12 : #include "stream.h"
13 : #include "stream_internal.h"
14 : #include "pump.h"
15 :
16 :
17 : #ifdef HAVE_LIBBZ2
18 :
19 : struct inner_state {
20 : bz_stream strm;
21 : int (*work)(bz_stream *strm, int flush);
22 : int (*end)(bz_stream *strm);
23 : void (*reset)(inner_state_t *inner_state);
24 : bool eof_reached;
25 : char buf[64*1024];
26 : };
27 :
28 :
29 : static pump_buffer
30 3535 : get_src_win(inner_state_t *inner_state)
31 : {
32 3535 : return (pump_buffer) {
33 3675 : .start = (void*) inner_state->strm.next_in,
34 3675 : .count = inner_state->strm.avail_in,
35 : };
36 : }
37 :
38 : static void
39 1293 : set_src_win(inner_state_t *inner_state, pump_buffer buf)
40 : {
41 1293 : assert(buf.count < UINT_MAX);
42 1293 : inner_state->strm.next_in = buf.start;
43 1293 : inner_state->strm.avail_in = (unsigned int)buf.count;
44 1293 : }
45 :
46 : static pump_buffer
47 3271 : get_dst_win(inner_state_t *inner_state)
48 : {
49 3271 : return (pump_buffer) {
50 3411 : .start = inner_state->strm.next_out,
51 3411 : .count = inner_state->strm.avail_out,
52 : };
53 : }
54 :
55 : static void
56 826 : set_dst_win(inner_state_t *inner_state, pump_buffer buf)
57 : {
58 826 : assert(buf.count < UINT_MAX);
59 826 : inner_state->strm.next_out = buf.start;
60 826 : inner_state->strm.avail_out = (unsigned int)buf.count;
61 826 : }
62 :
63 : static pump_buffer
64 1349 : get_buffer(inner_state_t *inner_state)
65 : {
66 1349 : return (pump_buffer) {
67 1349 : .start = (char*)inner_state->buf,
68 : .count = sizeof(inner_state->buf),
69 : };
70 : }
71 :
72 : static pump_result
73 1363 : work(inner_state_t *inner_state, pump_action action)
74 : {
75 1363 : if (inner_state->eof_reached)
76 : return PUMP_END;
77 :
78 : int a;
79 : switch (action) {
80 : case PUMP_NO_FLUSH:
81 : a = BZ_RUN;
82 : break;
83 : case PUMP_FLUSH_DATA:
84 : a = BZ_FLUSH;
85 : break;
86 : case PUMP_FLUSH_ALL:
87 : a = BZ_FLUSH;
88 : break;
89 : case PUMP_FINISH:
90 : a = BZ_FINISH;
91 : break;
92 : default:
93 0 : assert(0 /* unknown action */);
94 : return PUMP_ERROR;
95 : }
96 :
97 1363 : int ret = inner_state->work(&inner_state->strm, a);
98 :
99 1363 : switch (ret) {
100 1222 : case BZ_OK:
101 : case BZ_RUN_OK:
102 1222 : if (a == PUMP_NO_FLUSH)
103 : return PUMP_OK;
104 : else
105 : /* when flushing or finishing, done */
106 474 : return PUMP_END;
107 : case BZ_FLUSH_OK:
108 : case BZ_FINISH_OK:
109 : /* flushing and finishing is not yet done */
110 : return PUMP_OK;
111 141 : case BZ_STREAM_END:
112 141 : if (action == PUMP_NO_FLUSH && inner_state->reset != NULL) {
113 : // attempt to read concatenated additional bz2 stream
114 140 : inner_state->reset(inner_state);
115 140 : return PUMP_OK;
116 : }
117 1 : inner_state->eof_reached = true;
118 1 : return PUMP_END;
119 0 : default:
120 0 : return PUMP_ERROR;
121 : }
122 : }
123 :
124 : static void
125 141 : finalizer(inner_state_t *inner_state)
126 : {
127 141 : inner_state->end(&inner_state->strm);
128 141 : free(inner_state);
129 141 : }
130 :
131 : static const char*
132 0 : bz2_get_error(inner_state_t *inner_state)
133 : {
134 : int dummy;
135 0 : return BZ2_bzerror(&inner_state->strm, &dummy);
136 : }
137 :
138 : static int
139 643 : BZ2_bzDecompress_wrapper(bz_stream *strm, int a)
140 : {
141 : (void)a;
142 643 : return BZ2_bzDecompress(strm);
143 : }
144 :
145 : static void
146 140 : bz2_decompress_reset(inner_state_t *inner_state)
147 : {
148 : pump_buffer src = get_src_win(inner_state);
149 : pump_buffer dst = get_dst_win(inner_state);
150 140 : BZ2_bzDecompressEnd(&inner_state->strm);
151 140 : BZ2_bzDecompressInit(&inner_state->strm, 0, 0);
152 140 : set_src_win(inner_state, src);
153 140 : set_dst_win(inner_state, dst);
154 140 : }
155 :
156 : stream *
157 141 : bz2_stream(stream *inner, int level)
158 : {
159 141 : inner_state_t *bz = calloc(1, sizeof(inner_state_t));
160 141 : pump_state *state = calloc(1, sizeof(pump_state));
161 141 : if (bz == NULL || state == NULL) {
162 0 : free(bz);
163 0 : free(state);
164 0 : mnstr_set_open_error(inner->name, errno, "couldn't initialize bz2 stream");
165 0 : return NULL;
166 : }
167 :
168 141 : state->inner_state = bz;
169 141 : state->get_src_win = get_src_win;
170 141 : state->set_src_win = set_src_win;
171 141 : state->get_dst_win = get_dst_win;
172 141 : state->set_dst_win = set_dst_win;
173 141 : state->get_buffer = get_buffer;
174 141 : state->worker = work;
175 141 : state->get_error = bz2_get_error;
176 141 : state->finalizer = finalizer;
177 :
178 : int ret;
179 141 : if (inner->readonly) {
180 140 : bz->work = BZ2_bzDecompress_wrapper;
181 140 : bz->end = BZ2_bzDecompressEnd;
182 140 : bz->reset = bz2_decompress_reset;
183 140 : ret = BZ2_bzDecompressInit(&bz->strm, 0, 0);
184 : } else {
185 1 : bz->work = BZ2_bzCompress;
186 1 : bz->end = BZ2_bzCompressEnd;
187 1 : if (level == 0)
188 : level = 6;
189 1 : ret = BZ2_bzCompressInit(&bz->strm, level, 0, 0);
190 : }
191 :
192 141 : if (ret != BZ_OK) {
193 0 : free(bz);
194 0 : free(state);
195 0 : mnstr_set_open_error(inner->name, 0, "failed to initialize bz2: code %d", ret);
196 0 : return NULL;
197 : }
198 :
199 141 : stream *s = pump_stream(inner, state);
200 :
201 141 : if (s == NULL) {
202 0 : bz->end(&bz->strm);
203 0 : free(bz);
204 0 : free(state);
205 0 : return NULL;
206 : }
207 :
208 : return s;
209 : }
210 :
211 : static stream *
212 0 : open_bzstream(const char *restrict filename, const char *restrict flags)
213 : {
214 : stream *inner;
215 : int preset = 6;
216 :
217 0 : inner = open_stream(filename, flags);
218 0 : if (inner == NULL)
219 : return NULL;
220 :
221 0 : return bz2_stream(inner, preset);
222 : }
223 :
224 : stream *
225 0 : open_bzrstream(const char *filename)
226 : {
227 0 : stream *s = open_bzstream(filename, "rb");
228 0 : if (s == NULL)
229 : return NULL;
230 :
231 0 : assert(s->readonly == true);
232 0 : assert(s->binary == true);
233 : return s;
234 : }
235 :
236 : stream *
237 0 : open_bzwstream(const char *restrict filename, const char *restrict mode)
238 : {
239 0 : stream *s = open_bzstream(filename, mode);
240 0 : if (s == NULL)
241 : return NULL;
242 :
243 0 : assert(s->readonly == false);
244 0 : assert(s->binary == true);
245 : return s;
246 : }
247 :
248 : stream *
249 0 : open_bzrastream(const char *filename)
250 : {
251 0 : stream *s = open_bzstream(filename, "r");
252 0 : s = create_text_stream(s);
253 0 : if (s == NULL)
254 : return NULL;
255 :
256 0 : assert(s->readonly == true);
257 0 : assert(s->binary == false);
258 : return s;
259 : }
260 :
261 : stream *
262 0 : open_bzwastream(const char *restrict filename, const char *restrict mode)
263 : {
264 0 : stream *s = open_bzstream(filename, mode);
265 0 : s = create_text_stream(s);
266 0 : if (s == NULL)
267 : return NULL;
268 0 : assert(s->readonly == false);
269 0 : assert(s->binary == false);
270 : return s;
271 : }
272 : #else
273 :
274 : stream *
275 : bz2_stream(stream *inner, int preset)
276 : {
277 : (void) inner;
278 : (void) preset;
279 : mnstr_set_open_error(inner->name, 0, "BZIP2 support has been left out of this MonetDB");
280 : return NULL;
281 : }
282 :
283 : stream *
284 : open_bzrstream(const char *filename)
285 : {
286 : mnstr_set_open_error(filename, 0, "BZIP2 support has been left out of this MonetDB");
287 : return NULL;
288 : }
289 :
290 : stream *
291 : open_bzwstream(const char *restrict filename, const char *restrict mode)
292 : {
293 : (void) mode;
294 : mnstr_set_open_error(filename, 0, "BZIP2 support has been left out of this MonetDB");
295 : return NULL;
296 : }
297 :
298 : stream *
299 : open_bzrastream(const char *filename)
300 : {
301 : mnstr_set_open_error(filename, 0, "BZIP2 support has been left out of this MonetDB");
302 : return NULL;
303 : }
304 :
305 : stream *
306 : open_bzwastream(const char *restrict filename, const char *restrict mode)
307 : {
308 : (void) mode;
309 : mnstr_set_open_error(filename, 0, "BZIP2 support has been left out of this MonetDB");
310 : return NULL;
311 : }
312 :
313 : #endif
|