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