Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / contrib / libarchive-2.0 / 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.13 2007/03/03 07:37:36 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 };
59
60 static int      finish(struct archive_read *);
61 static ssize_t  read_ahead(struct archive_read *, const void **, size_t);
62 static ssize_t  read_consume(struct archive_read *, size_t);
63 static int      drive_decompressor(struct archive_read *a, struct private_data *);
64 #endif
65
66 /* These two functions are defined even if we lack bzlib.  See below. */
67 static int      bid(const void *, size_t);
68 static int      init(struct archive_read *, const void *, size_t);
69
70 int
71 archive_read_support_compression_bzip2(struct archive *_a)
72 {
73         struct archive_read *a = (struct archive_read *)_a;
74         return (__archive_read_register_compression(a, bid, init));
75 }
76
77 /*
78  * Test whether we can handle this data.
79  *
80  * This logic returns zero if any part of the signature fails.  It
81  * also tries to Do The Right Thing if a very short buffer prevents us
82  * from verifying as much as we would like.
83  */
84 static int
85 bid(const void *buff, size_t len)
86 {
87         const unsigned char *buffer;
88         int bits_checked;
89
90         if (len < 1)
91                 return (0);
92
93         buffer = (const unsigned char *)buff;
94         bits_checked = 0;
95         if (buffer[0] != 'B')   /* Verify first ID byte. */
96                 return (0);
97         bits_checked += 8;
98         if (len < 2)
99                 return (bits_checked);
100
101         if (buffer[1] != 'Z')   /* Verify second ID byte. */
102                 return (0);
103         bits_checked += 8;
104         if (len < 3)
105                 return (bits_checked);
106
107         if (buffer[2] != 'h')   /* Verify third ID byte. */
108                 return (0);
109         bits_checked += 8;
110         if (len < 4)
111                 return (bits_checked);
112
113         if (buffer[3] < '1' || buffer[3] > '9')
114                 return (0);
115         bits_checked += 5;
116
117         /*
118          * Research Question: Can we do any more to verify that this
119          * really is BZip2 format??  For 99.9% of the time, the above
120          * test is sufficient, but it would be nice to do a more
121          * thorough check.  It's especially troubling that the BZip2
122          * signature begins with all ASCII characters; a tar archive
123          * whose first filename begins with 'BZh3' would potentially
124          * fool this logic.  (It may also be possible to guard against
125          * such anomalies in archive_read_support_compression_none.)
126          */
127
128         return (bits_checked);
129 }
130
131 #ifndef HAVE_BZLIB_H
132
133 /*
134  * If we don't have bzlib on this system, we can't actually do the
135  * decompression.  We can, however, still detect bzip2-compressed
136  * archives and emit a useful message.
137  */
138 static int
139 init(struct archive *a, const void *buff, size_t n)
140 {
141         (void)a;        /* UNUSED */
142         (void)buff;     /* UNUSED */
143         (void)n;        /* UNUSED */
144
145         archive_set_error(a, -1,
146             "This version of libarchive was compiled without bzip2 support");
147         return (ARCHIVE_FATAL);
148 }
149
150
151 #else
152
153 /*
154  * Setup the callbacks.
155  */
156 static int
157 init(struct archive_read *a, const void *buff, size_t n)
158 {
159         struct private_data *state;
160         int ret;
161
162         a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
163         a->archive.compression_name = "bzip2";
164
165         state = (struct private_data *)malloc(sizeof(*state));
166         if (state == NULL) {
167                 archive_set_error(&a->archive, ENOMEM,
168                     "Can't allocate data for %s decompression",
169                     a->archive.compression_name);
170                 return (ARCHIVE_FATAL);
171         }
172         memset(state, 0, sizeof(*state));
173
174         state->uncompressed_buffer_size = 64 * 1024;
175         state->uncompressed_buffer = (char *)malloc(state->uncompressed_buffer_size);
176         state->stream.next_out = state->uncompressed_buffer;
177         state->read_next = state->uncompressed_buffer;
178         state->stream.avail_out = state->uncompressed_buffer_size;
179
180         if (state->uncompressed_buffer == NULL) {
181                 archive_set_error(&a->archive, ENOMEM,
182                     "Can't allocate %s decompression buffers",
183                     a->archive.compression_name);
184                 free(state);
185                 return (ARCHIVE_FATAL);
186         }
187
188         /*
189          * A bug in bzlib.h: stream.next_in should be marked 'const'
190          * but isn't (the library never alters data through the
191          * next_in pointer, only reads it).  The result: this ugly
192          * cast to remove 'const'.
193          */
194         state->stream.next_in = (char *)(uintptr_t)(const void *)buff;
195         state->stream.avail_in = n;
196
197         a->compression_read_ahead = read_ahead;
198         a->compression_read_consume = read_consume;
199         a->compression_skip = NULL; /* not supported */
200         a->compression_finish = finish;
201
202         /* Initialize compression library. */
203         ret = BZ2_bzDecompressInit(&(state->stream),
204             0 /* library verbosity */,
205             0 /* don't use slow low-mem algorithm */);
206
207         /* If init fails, try using low-memory algorithm instead. */
208         if (ret == BZ_MEM_ERROR) {
209                 ret = BZ2_bzDecompressInit(&(state->stream),
210                     0 /* library verbosity */,
211                     1 /* do use slow low-mem algorithm */);
212         }
213
214         if (ret == BZ_OK) {
215                 a->compression_data = state;
216                 return (ARCHIVE_OK);
217         }
218
219         /* Library setup failed: Clean up. */
220         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
221             "Internal error initializing %s library",
222             a->archive.compression_name);
223         free(state->uncompressed_buffer);
224         free(state);
225
226         /* Override the error message if we know what really went wrong. */
227         switch (ret) {
228         case BZ_PARAM_ERROR:
229                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
230                     "Internal error initializing compression library: "
231                     "invalid setup parameter");
232                 break;
233         case BZ_MEM_ERROR:
234                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
235                     "Internal error initializing compression library: "
236                     "out of memory");
237                 break;
238         case BZ_CONFIG_ERROR:
239                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
240                     "Internal error initializing compression library: "
241                     "mis-compiled library");
242                 break;
243         }
244
245         return (ARCHIVE_FATAL);
246 }
247
248 /*
249  * Return a block of data from the decompression buffer.  Decompress more
250  * as necessary.
251  */
252 static ssize_t
253 read_ahead(struct archive_read *a, const void **p, size_t min)
254 {
255         struct private_data *state;
256         int read_avail, was_avail, ret;
257
258         state = (struct private_data *)a->compression_data;
259         was_avail = -1;
260         if (!a->client_reader) {
261                 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
262                     "No read callback is registered?  "
263                     "This is probably an internal programming error.");
264                 return (ARCHIVE_FATAL);
265         }
266
267         read_avail = state->stream.next_out - state->read_next;
268
269         if (read_avail + state->stream.avail_out < min) {
270                 memmove(state->uncompressed_buffer, state->read_next,
271                     read_avail);
272                 state->read_next = state->uncompressed_buffer;
273                 state->stream.next_out = state->read_next + read_avail;
274                 state->stream.avail_out
275                     = state->uncompressed_buffer_size - read_avail;
276         }
277
278         while (was_avail < read_avail &&        /* Made some progress. */
279             read_avail < (int)min &&            /* Haven't satisfied min. */
280             read_avail < (int)state->uncompressed_buffer_size) { /* !full */
281                 if ((ret = drive_decompressor(a, state)) != ARCHIVE_OK)
282                         return (ret);
283                 was_avail = read_avail;
284                 read_avail = state->stream.next_out - state->read_next;
285         }
286
287         *p = state->read_next;
288         return (read_avail);
289 }
290
291 /*
292  * Mark a previously-returned block of data as read.
293  */
294 static ssize_t
295 read_consume(struct archive_read *a, size_t n)
296 {
297         struct private_data *state;
298
299         state = (struct private_data *)a->compression_data;
300         a->archive.file_position += n;
301         state->read_next += n;
302         if (state->read_next > state->stream.next_out)
303                 __archive_errx(1, "Request to consume too many "
304                     "bytes from bzip2 decompressor");
305         return (n);
306 }
307
308 /*
309  * Clean up the decompressor.
310  */
311 static int
312 finish(struct archive_read *a)
313 {
314         struct private_data *state;
315         int ret;
316
317         state = (struct private_data *)a->compression_data;
318         ret = ARCHIVE_OK;
319         switch (BZ2_bzDecompressEnd(&(state->stream))) {
320         case BZ_OK:
321                 break;
322         default:
323                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
324                     "Failed to clean up %s compressor",
325                     a->archive.compression_name);
326                 ret = ARCHIVE_FATAL;
327         }
328
329         free(state->uncompressed_buffer);
330         free(state);
331
332         a->compression_data = NULL;
333         if (a->client_closer != NULL)
334                 (a->client_closer)(&a->archive, a->client_data);
335
336         return (ret);
337 }
338
339 /*
340  * Utility function to pull data through decompressor, reading input
341  * blocks as necessary.
342  */
343 static int
344 drive_decompressor(struct archive_read *a, struct private_data *state)
345 {
346         ssize_t ret;
347         int decompressed, total_decompressed;
348         char *output;
349
350         total_decompressed = 0;
351         for (;;) {
352                 if (state->stream.avail_in == 0) {
353                         ret = (a->client_reader)(&a->archive, a->client_data,
354                             (const void **)&state->stream.next_in);
355                         if (ret < 0) {
356                                 /*
357                                  * TODO: Find a better way to handle
358                                  * this read failure.
359                                  */
360                                 goto fatal;
361                         }
362                         if (ret == 0  &&  total_decompressed == 0) {
363                                 archive_set_error(&a->archive, EIO,
364                                     "Premature end of %s compressed data",
365                                     a->archive.compression_name);
366                                 return (ARCHIVE_FATAL);
367                         }
368                         a->archive.raw_position += ret;
369                         state->stream.avail_in = ret;
370                 }
371
372                 {
373                         output = state->stream.next_out;
374
375                         /* Decompress some data. */
376                         ret = BZ2_bzDecompress(&(state->stream));
377                         decompressed = state->stream.next_out - output;
378
379                         /* Accumulate the total bytes of output. */
380                         state->total_out += decompressed;
381                         total_decompressed += decompressed;
382
383                         switch (ret) {
384                         case BZ_OK: /* Decompressor made some progress. */
385                                 if (decompressed > 0)
386                                         return (ARCHIVE_OK);
387                                 break;
388                         case BZ_STREAM_END:     /* Found end of stream. */
389                                 return (ARCHIVE_OK);
390                         default:
391                                 /* Any other return value is an error. */
392                                 goto fatal;
393                         }
394                 }
395         }
396         return (ARCHIVE_OK);
397
398         /* Return a fatal error. */
399 fatal:
400         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
401             "%s decompression failed", a->archive.compression_name);
402         return (ARCHIVE_FATAL);
403 }
404
405 #endif /* HAVE_BZLIB_H */