c92494020a22eb8df1c62322889631865bd07aba
[dragonfly.git] / contrib / libarchive-2 / libarchive / archive_read_support_compression_bzip2.c
1 /*-
2  * Copyright (c) 2003-2007 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "archive_platform.h"
27
28 __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_bzip2.c,v 1.15 2007/04/05 05:18:16 kientzle Exp $");
29
30 #ifdef HAVE_ERRNO_H
31 #include <errno.h>
32 #endif
33 #include <stdio.h>
34 #ifdef HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37 #ifdef HAVE_STRING_H
38 #include <string.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #ifdef HAVE_BZLIB_H
44 #include <bzlib.h>
45 #endif
46
47 #include "archive.h"
48 #include "archive_private.h"
49 #include "archive_read_private.h"
50
51 #if HAVE_BZLIB_H
52 struct private_data {
53         bz_stream        stream;
54         char            *uncompressed_buffer;
55         size_t           uncompressed_buffer_size;
56         char            *read_next;
57         int64_t          total_out;
58         char             eof; /* True = found end of compressed data. */
59 };
60
61 static int      finish(struct archive_read *);
62 static ssize_t  read_ahead(struct archive_read *, const void **, size_t);
63 static ssize_t  read_consume(struct archive_read *, size_t);
64 static int      drive_decompressor(struct archive_read *a, struct private_data *);
65 #endif
66
67 /* These two functions are defined even if we lack the library.  See below. */
68 static int      bid(const void *, size_t);
69 static int      init(struct archive_read *, const void *, size_t);
70
71 int
72 archive_read_support_compression_bzip2(struct archive *_a)
73 {
74         struct archive_read *a = (struct archive_read *)_a;
75         if (__archive_read_register_compression(a, bid, init) != NULL)
76                 return (ARCHIVE_OK);
77         return (ARCHIVE_FATAL);
78 }
79
80 /*
81  * Test whether we can handle this data.
82  *
83  * This logic returns zero if any part of the signature fails.  It
84  * also tries to Do The Right Thing if a very short buffer prevents us
85  * from verifying as much as we would like.
86  */
87 static int
88 bid(const void *buff, size_t len)
89 {
90         const unsigned char *buffer;
91         int bits_checked;
92
93         if (len < 1)
94                 return (0);
95
96         buffer = (const unsigned char *)buff;
97         bits_checked = 0;
98         if (buffer[0] != 'B')   /* Verify first ID byte. */
99                 return (0);
100         bits_checked += 8;
101         if (len < 2)
102                 return (bits_checked);
103
104         if (buffer[1] != 'Z')   /* Verify second ID byte. */
105                 return (0);
106         bits_checked += 8;
107         if (len < 3)
108                 return (bits_checked);
109
110         if (buffer[2] != 'h')   /* Verify third ID byte. */
111                 return (0);
112         bits_checked += 8;
113         if (len < 4)
114                 return (bits_checked);
115
116         if (buffer[3] < '1' || buffer[3] > '9')
117                 return (0);
118         bits_checked += 5;
119
120         /*
121          * Research Question: Can we do any more to verify that this
122          * really is BZip2 format??  For 99.9% of the time, the above
123          * test is sufficient, but it would be nice to do a more
124          * thorough check.  It's especially troubling that the BZip2
125          * signature begins with all ASCII characters; a tar archive
126          * whose first filename begins with 'BZh3' would potentially
127          * fool this logic.  (It may also be possible to guard against
128          * such anomalies in archive_read_support_compression_none.)
129          */
130
131         return (bits_checked);
132 }
133
134 #ifndef HAVE_BZLIB_H
135
136 /*
137  * If we don't have the library on this system, we can't actually do the
138  * decompression.  We can, however, still detect compressed archives
139  * and emit a useful message.
140  */
141 static int
142 init(struct archive_read *a, const void *buff, size_t n)
143 {
144         (void)a;        /* UNUSED */
145         (void)buff;     /* UNUSED */
146         (void)n;        /* UNUSED */
147
148         archive_set_error(a, -1,
149             "This version of libarchive was compiled without bzip2 support");
150         return (ARCHIVE_FATAL);
151 }
152
153
154 #else
155
156 /*
157  * Setup the callbacks.
158  */
159 static int
160 init(struct archive_read *a, const void *buff, size_t n)
161 {
162         struct private_data *state;
163         int ret;
164
165         a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
166         a->archive.compression_name = "bzip2";
167
168         state = (struct private_data *)malloc(sizeof(*state));
169         if (state == NULL) {
170                 archive_set_error(&a->archive, ENOMEM,
171                     "Can't allocate data for %s decompression",
172                     a->archive.compression_name);
173                 return (ARCHIVE_FATAL);
174         }
175         memset(state, 0, sizeof(*state));
176
177         state->uncompressed_buffer_size = 64 * 1024;
178         state->uncompressed_buffer = (char *)malloc(state->uncompressed_buffer_size);
179         state->stream.next_out = state->uncompressed_buffer;
180         state->read_next = state->uncompressed_buffer;
181         state->stream.avail_out = state->uncompressed_buffer_size;
182
183         if (state->uncompressed_buffer == NULL) {
184                 archive_set_error(&a->archive, ENOMEM,
185                     "Can't allocate %s decompression buffers",
186                     a->archive.compression_name);
187                 free(state);
188                 return (ARCHIVE_FATAL);
189         }
190
191         /*
192          * A bug in bzlib.h: stream.next_in should be marked 'const'
193          * but isn't (the library never alters data through the
194          * next_in pointer, only reads it).  The result: this ugly
195          * cast to remove 'const'.
196          */
197         state->stream.next_in = (char *)(uintptr_t)(const void *)buff;
198         state->stream.avail_in = n;
199
200         a->decompressor->read_ahead = read_ahead;
201         a->decompressor->consume = read_consume;
202         a->decompressor->skip = NULL; /* not supported */
203         a->decompressor->finish = finish;
204
205         /* Initialize compression library. */
206         ret = BZ2_bzDecompressInit(&(state->stream),
207             0 /* library verbosity */,
208             0 /* don't use slow low-mem algorithm */);
209
210         /* If init fails, try using low-memory algorithm instead. */
211         if (ret == BZ_MEM_ERROR) {
212                 ret = BZ2_bzDecompressInit(&(state->stream),
213                     0 /* library verbosity */,
214                     1 /* do use slow low-mem algorithm */);
215         }
216
217         if (ret == BZ_OK) {
218                 a->decompressor->data = state;
219                 return (ARCHIVE_OK);
220         }
221
222         /* Library setup failed: Clean up. */
223         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
224             "Internal error initializing %s library",
225             a->archive.compression_name);
226         free(state->uncompressed_buffer);
227         free(state);
228
229         /* Override the error message if we know what really went wrong. */
230         switch (ret) {
231         case BZ_PARAM_ERROR:
232                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
233                     "Internal error initializing compression library: "
234                     "invalid setup parameter");
235                 break;
236         case BZ_MEM_ERROR:
237                 archive_set_error(&a->archive, ENOMEM,
238                     "Internal error initializing compression library: "
239                     "out of memory");
240                 break;
241         case BZ_CONFIG_ERROR:
242                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
243                     "Internal error initializing compression library: "
244                     "mis-compiled library");
245                 break;
246         }
247
248         return (ARCHIVE_FATAL);
249 }
250
251 /*
252  * Return a block of data from the decompression buffer.  Decompress more
253  * as necessary.
254  */
255 static ssize_t
256 read_ahead(struct archive_read *a, const void **p, size_t min)
257 {
258         struct private_data *state;
259         size_t read_avail, was_avail;
260         int ret;
261
262         state = (struct private_data *)a->decompressor->data;
263         if (!a->client_reader) {
264                 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
265                     "No read callback is registered?  "
266                     "This is probably an internal programming error.");
267                 return (ARCHIVE_FATAL);
268         }
269
270         read_avail = state->stream.next_out - state->read_next;
271
272         if (read_avail + state->stream.avail_out < min) {
273                 memmove(state->uncompressed_buffer, state->read_next,
274                     read_avail);
275                 state->read_next = state->uncompressed_buffer;
276                 state->stream.next_out = state->read_next + read_avail;
277                 state->stream.avail_out
278                     = state->uncompressed_buffer_size - read_avail;
279         }
280
281         while (read_avail < min &&              /* Haven't satisfied min. */
282             read_avail < state->uncompressed_buffer_size) { /* !full */
283                 was_avail = read_avail;
284                 if ((ret = drive_decompressor(a, state)) < ARCHIVE_OK)
285                         return (ret);
286                 if (ret == ARCHIVE_EOF)
287                         break; /* Break on EOF even if we haven't met min. */
288                 read_avail = state->stream.next_out - state->read_next;
289                 if (was_avail == read_avail) /* No progress? */
290                         break;
291         }
292
293         *p = state->read_next;
294         return (read_avail);
295 }
296
297 /*
298  * Mark a previously-returned block of data as read.
299  */
300 static ssize_t
301 read_consume(struct archive_read *a, size_t n)
302 {
303         struct private_data *state;
304
305         state = (struct private_data *)a->decompressor->data;
306         a->archive.file_position += n;
307         state->read_next += n;
308         if (state->read_next > state->stream.next_out)
309                 __archive_errx(1, "Request to consume too many "
310                     "bytes from bzip2 decompressor");
311         return (n);
312 }
313
314 /*
315  * Clean up the decompressor.
316  */
317 static int
318 finish(struct archive_read *a)
319 {
320         struct private_data *state;
321         int ret;
322
323         state = (struct private_data *)a->decompressor->data;
324         ret = ARCHIVE_OK;
325         switch (BZ2_bzDecompressEnd(&(state->stream))) {
326         case BZ_OK:
327                 break;
328         default:
329                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
330                     "Failed to clean up %s compressor",
331                     a->archive.compression_name);
332                 ret = ARCHIVE_FATAL;
333         }
334
335         free(state->uncompressed_buffer);
336         free(state);
337
338         a->decompressor->data = NULL;
339         return (ret);
340 }
341
342 /*
343  * Utility function to pull data through decompressor, reading input
344  * blocks as necessary.
345  */
346 static int
347 drive_decompressor(struct archive_read *a, struct private_data *state)
348 {
349         ssize_t ret;
350         int decompressed, total_decompressed;
351         char *output;
352         const void *read_buf;
353
354         if (state->eof)
355                 return (ARCHIVE_EOF);
356         total_decompressed = 0;
357         for (;;) {
358                 if (state->stream.avail_in == 0) {
359                         read_buf = state->stream.next_in;
360                         ret = (a->client_reader)(&a->archive, a->client_data,
361                             &read_buf);
362                         state->stream.next_in = (void *)(uintptr_t)read_buf;
363                         if (ret < 0) {
364                                 /*
365                                  * TODO: Find a better way to handle
366                                  * this read failure.
367                                  */
368                                 goto fatal;
369                         }
370                         if (ret == 0  &&  total_decompressed == 0) {
371                                 archive_set_error(&a->archive, EIO,
372                                     "Premature end of %s compressed data",
373                                     a->archive.compression_name);
374                                 return (ARCHIVE_FATAL);
375                         }
376                         a->archive.raw_position += ret;
377                         state->stream.avail_in = ret;
378                 }
379
380                 {
381                         output = state->stream.next_out;
382
383                         /* Decompress some data. */
384                         ret = BZ2_bzDecompress(&(state->stream));
385                         decompressed = state->stream.next_out - output;
386
387                         /* Accumulate the total bytes of output. */
388                         state->total_out += decompressed;
389                         total_decompressed += decompressed;
390
391                         switch (ret) {
392                         case BZ_OK: /* Decompressor made some progress. */
393                                 if (decompressed > 0)
394                                         return (ARCHIVE_OK);
395                                 break;
396                         case BZ_STREAM_END:     /* Found end of stream. */
397                                 state->eof = 1;
398                                 return (ARCHIVE_OK);
399                         default:
400                                 /* Any other return value is an error. */
401                                 goto fatal;
402                         }
403                 }
404         }
405         return (ARCHIVE_OK);
406
407         /* Return a fatal error. */
408 fatal:
409         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
410             "%s decompression failed", a->archive.compression_name);
411         return (ARCHIVE_FATAL);
412 }
413
414 #endif /* HAVE_BZLIB_H */