1acc60b03SMartin Matuska /*-
2acc60b03SMartin Matuska * Copyright (c) 2003-2007 Tim Kientzle
3acc60b03SMartin Matuska * Copyright (c) 2012 Michihiro NAKAJIMA
4acc60b03SMartin Matuska * All rights reserved.
5acc60b03SMartin Matuska *
6acc60b03SMartin Matuska * Redistribution and use in source and binary forms, with or without
7acc60b03SMartin Matuska * modification, are permitted provided that the following conditions
8acc60b03SMartin Matuska * are met:
9acc60b03SMartin Matuska * 1. Redistributions of source code must retain the above copyright
10acc60b03SMartin Matuska * notice, this list of conditions and the following disclaimer.
11acc60b03SMartin Matuska * 2. Redistributions in binary form must reproduce the above copyright
12acc60b03SMartin Matuska * notice, this list of conditions and the following disclaimer in the
13acc60b03SMartin Matuska * documentation and/or other materials provided with the distribution.
14acc60b03SMartin Matuska *
15acc60b03SMartin Matuska * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16acc60b03SMartin Matuska * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17acc60b03SMartin Matuska * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18acc60b03SMartin Matuska * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19acc60b03SMartin Matuska * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20acc60b03SMartin Matuska * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21acc60b03SMartin Matuska * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22acc60b03SMartin Matuska * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23acc60b03SMartin Matuska * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24acc60b03SMartin Matuska * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25acc60b03SMartin Matuska */
26acc60b03SMartin Matuska
27acc60b03SMartin Matuska #include "archive_platform.h"
28acc60b03SMartin Matuska
29acc60b03SMartin Matuska #ifdef HAVE_UNISTD_H
30acc60b03SMartin Matuska #include <unistd.h>
31acc60b03SMartin Matuska #endif
32acc60b03SMartin Matuska #ifdef HAVE_ERRNO_H
33acc60b03SMartin Matuska #include <errno.h>
34acc60b03SMartin Matuska #endif
35acc60b03SMartin Matuska #ifdef HAVE_STDLIB_H
36acc60b03SMartin Matuska #include <stdlib.h>
37acc60b03SMartin Matuska #endif
38acc60b03SMartin Matuska #ifdef HAVE_STRING_H
39acc60b03SMartin Matuska #include <string.h>
40acc60b03SMartin Matuska #endif
41acc60b03SMartin Matuska #ifdef HAVE_UNISTD_H
42acc60b03SMartin Matuska #include <unistd.h>
43acc60b03SMartin Matuska #endif
44acc60b03SMartin Matuska #ifdef HAVE_LZO_LZOCONF_H
45acc60b03SMartin Matuska #include <lzo/lzoconf.h>
46acc60b03SMartin Matuska #endif
47acc60b03SMartin Matuska #ifdef HAVE_LZO_LZO1X_H
48acc60b03SMartin Matuska #include <lzo/lzo1x.h>
49acc60b03SMartin Matuska #endif
50acc60b03SMartin Matuska #ifdef HAVE_ZLIB_H
51acc60b03SMartin Matuska #include <zlib.h> /* for crc32 and adler32 */
52acc60b03SMartin Matuska #endif
53acc60b03SMartin Matuska
54acc60b03SMartin Matuska #include "archive.h"
55acc60b03SMartin Matuska #if !defined(HAVE_ZLIB_H) &&\
56acc60b03SMartin Matuska defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
57acc60b03SMartin Matuska #include "archive_crc32.h"
58acc60b03SMartin Matuska #endif
59acc60b03SMartin Matuska #include "archive_endian.h"
60acc60b03SMartin Matuska #include "archive_private.h"
61acc60b03SMartin Matuska #include "archive_read_private.h"
62acc60b03SMartin Matuska
63acc60b03SMartin Matuska #ifndef HAVE_ZLIB_H
64acc60b03SMartin Matuska #define adler32 lzo_adler32
65acc60b03SMartin Matuska #endif
66acc60b03SMartin Matuska
67acc60b03SMartin Matuska #define LZOP_HEADER_MAGIC "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a"
68acc60b03SMartin Matuska #define LZOP_HEADER_MAGIC_LEN 9
69acc60b03SMartin Matuska
70acc60b03SMartin Matuska #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
71acc60b03SMartin Matuska struct read_lzop {
72acc60b03SMartin Matuska unsigned char *out_block;
73acc60b03SMartin Matuska size_t out_block_size;
74acc60b03SMartin Matuska int64_t total_out;
75acc60b03SMartin Matuska int flags;
76acc60b03SMartin Matuska uint32_t compressed_cksum;
77acc60b03SMartin Matuska uint32_t uncompressed_cksum;
78acc60b03SMartin Matuska size_t compressed_size;
79acc60b03SMartin Matuska size_t uncompressed_size;
80acc60b03SMartin Matuska size_t unconsumed_bytes;
81acc60b03SMartin Matuska char in_stream;
82acc60b03SMartin Matuska char eof; /* True = found end of compressed data. */
83acc60b03SMartin Matuska };
84acc60b03SMartin Matuska
85acc60b03SMartin Matuska #define FILTER 0x0800
86acc60b03SMartin Matuska #define CRC32_HEADER 0x1000
87acc60b03SMartin Matuska #define EXTRA_FIELD 0x0040
88acc60b03SMartin Matuska #define ADLER32_UNCOMPRESSED 0x0001
89acc60b03SMartin Matuska #define ADLER32_COMPRESSED 0x0002
90acc60b03SMartin Matuska #define CRC32_UNCOMPRESSED 0x0100
91acc60b03SMartin Matuska #define CRC32_COMPRESSED 0x0200
92acc60b03SMartin Matuska #define MAX_BLOCK_SIZE (64 * 1024 * 1024)
93acc60b03SMartin Matuska
94acc60b03SMartin Matuska static ssize_t lzop_filter_read(struct archive_read_filter *, const void **);
95acc60b03SMartin Matuska static int lzop_filter_close(struct archive_read_filter *);
96acc60b03SMartin Matuska #endif
97acc60b03SMartin Matuska
98acc60b03SMartin Matuska static int lzop_bidder_bid(struct archive_read_filter_bidder *,
99acc60b03SMartin Matuska struct archive_read_filter *);
100acc60b03SMartin Matuska static int lzop_bidder_init(struct archive_read_filter *);
101acc60b03SMartin Matuska
102833a452eSMartin Matuska static const struct archive_read_filter_bidder_vtable
103833a452eSMartin Matuska lzop_bidder_vtable = {
104833a452eSMartin Matuska .bid = lzop_bidder_bid,
105833a452eSMartin Matuska .init = lzop_bidder_init,
106833a452eSMartin Matuska };
107833a452eSMartin Matuska
108acc60b03SMartin Matuska int
archive_read_support_filter_lzop(struct archive * _a)109acc60b03SMartin Matuska archive_read_support_filter_lzop(struct archive *_a)
110acc60b03SMartin Matuska {
111acc60b03SMartin Matuska struct archive_read *a = (struct archive_read *)_a;
112acc60b03SMartin Matuska
113833a452eSMartin Matuska if (__archive_read_register_bidder(a, NULL, NULL,
114833a452eSMartin Matuska &lzop_bidder_vtable) != ARCHIVE_OK)
115acc60b03SMartin Matuska return (ARCHIVE_FATAL);
116acc60b03SMartin Matuska
117acc60b03SMartin Matuska /* Signal the extent of lzop support with the return value here. */
118acc60b03SMartin Matuska #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
119acc60b03SMartin Matuska return (ARCHIVE_OK);
120acc60b03SMartin Matuska #else
121acc60b03SMartin Matuska /* Return ARCHIVE_WARN since this always uses an external program. */
122acc60b03SMartin Matuska archive_set_error(_a, ARCHIVE_ERRNO_MISC,
123acc60b03SMartin Matuska "Using external lzop program for lzop decompression");
124acc60b03SMartin Matuska return (ARCHIVE_WARN);
125acc60b03SMartin Matuska #endif
126acc60b03SMartin Matuska }
127acc60b03SMartin Matuska
128acc60b03SMartin Matuska /*
129acc60b03SMartin Matuska * Bidder just verifies the header and returns the number of verified bits.
130acc60b03SMartin Matuska */
131acc60b03SMartin Matuska static int
lzop_bidder_bid(struct archive_read_filter_bidder * self,struct archive_read_filter * filter)132acc60b03SMartin Matuska lzop_bidder_bid(struct archive_read_filter_bidder *self,
133acc60b03SMartin Matuska struct archive_read_filter *filter)
134acc60b03SMartin Matuska {
135acc60b03SMartin Matuska const unsigned char *p;
136acc60b03SMartin Matuska ssize_t avail;
137acc60b03SMartin Matuska
138acc60b03SMartin Matuska (void)self; /* UNUSED */
139acc60b03SMartin Matuska
140acc60b03SMartin Matuska p = __archive_read_filter_ahead(filter, LZOP_HEADER_MAGIC_LEN, &avail);
141acc60b03SMartin Matuska if (p == NULL || avail == 0)
142acc60b03SMartin Matuska return (0);
143acc60b03SMartin Matuska
144acc60b03SMartin Matuska if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
145acc60b03SMartin Matuska return (0);
146acc60b03SMartin Matuska
147acc60b03SMartin Matuska return (LZOP_HEADER_MAGIC_LEN * 8);
148acc60b03SMartin Matuska }
149acc60b03SMartin Matuska
150acc60b03SMartin Matuska #if !defined(HAVE_LZO_LZOCONF_H) || !defined(HAVE_LZO_LZO1X_H)
151acc60b03SMartin Matuska /*
152acc60b03SMartin Matuska * If we don't have the library on this system, we can't do the
153acc60b03SMartin Matuska * decompression directly. We can, however, try to run "lzop -d"
154acc60b03SMartin Matuska * in case that's available.
155acc60b03SMartin Matuska */
156acc60b03SMartin Matuska static int
lzop_bidder_init(struct archive_read_filter * self)157acc60b03SMartin Matuska lzop_bidder_init(struct archive_read_filter *self)
158acc60b03SMartin Matuska {
159acc60b03SMartin Matuska int r;
160acc60b03SMartin Matuska
161acc60b03SMartin Matuska r = __archive_read_program(self, "lzop -d");
162acc60b03SMartin Matuska /* Note: We set the format here even if __archive_read_program()
163acc60b03SMartin Matuska * above fails. We do, after all, know what the format is
164acc60b03SMartin Matuska * even if we weren't able to read it. */
165acc60b03SMartin Matuska self->code = ARCHIVE_FILTER_LZOP;
166acc60b03SMartin Matuska self->name = "lzop";
167acc60b03SMartin Matuska return (r);
168acc60b03SMartin Matuska }
169acc60b03SMartin Matuska #else
170833a452eSMartin Matuska
171833a452eSMartin Matuska static const struct archive_read_filter_vtable
172833a452eSMartin Matuska lzop_reader_vtable = {
173833a452eSMartin Matuska .read = lzop_filter_read,
174833a452eSMartin Matuska .close = lzop_filter_close
175833a452eSMartin Matuska };
176833a452eSMartin Matuska
177acc60b03SMartin Matuska /*
178acc60b03SMartin Matuska * Initialize the filter object.
179acc60b03SMartin Matuska */
180acc60b03SMartin Matuska static int
lzop_bidder_init(struct archive_read_filter * self)181acc60b03SMartin Matuska lzop_bidder_init(struct archive_read_filter *self)
182acc60b03SMartin Matuska {
183acc60b03SMartin Matuska struct read_lzop *state;
184acc60b03SMartin Matuska
185acc60b03SMartin Matuska self->code = ARCHIVE_FILTER_LZOP;
186acc60b03SMartin Matuska self->name = "lzop";
187acc60b03SMartin Matuska
188*b9128a37SMartin Matuska state = (struct read_lzop *)calloc(1, sizeof(*state));
189acc60b03SMartin Matuska if (state == NULL) {
190acc60b03SMartin Matuska archive_set_error(&self->archive->archive, ENOMEM,
191acc60b03SMartin Matuska "Can't allocate data for lzop decompression");
192acc60b03SMartin Matuska return (ARCHIVE_FATAL);
193acc60b03SMartin Matuska }
194acc60b03SMartin Matuska
195acc60b03SMartin Matuska self->data = state;
196833a452eSMartin Matuska self->vtable = &lzop_reader_vtable;
197acc60b03SMartin Matuska
198acc60b03SMartin Matuska return (ARCHIVE_OK);
199acc60b03SMartin Matuska }
200acc60b03SMartin Matuska
201acc60b03SMartin Matuska static int
consume_header(struct archive_read_filter * self)202acc60b03SMartin Matuska consume_header(struct archive_read_filter *self)
203acc60b03SMartin Matuska {
204acc60b03SMartin Matuska struct read_lzop *state = (struct read_lzop *)self->data;
205acc60b03SMartin Matuska const unsigned char *p, *_p;
206acc60b03SMartin Matuska unsigned checksum, flags, len, method, version;
207acc60b03SMartin Matuska
208acc60b03SMartin Matuska /*
209acc60b03SMartin Matuska * Check LZOP magic code.
210acc60b03SMartin Matuska */
211acc60b03SMartin Matuska p = __archive_read_filter_ahead(self->upstream,
212acc60b03SMartin Matuska LZOP_HEADER_MAGIC_LEN, NULL);
213acc60b03SMartin Matuska if (p == NULL)
214acc60b03SMartin Matuska return (ARCHIVE_EOF);
215acc60b03SMartin Matuska
216acc60b03SMartin Matuska if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
217acc60b03SMartin Matuska return (ARCHIVE_EOF);
218acc60b03SMartin Matuska __archive_read_filter_consume(self->upstream,
219acc60b03SMartin Matuska LZOP_HEADER_MAGIC_LEN);
220acc60b03SMartin Matuska
221acc60b03SMartin Matuska p = __archive_read_filter_ahead(self->upstream, 29, NULL);
222acc60b03SMartin Matuska if (p == NULL)
223acc60b03SMartin Matuska goto truncated;
224acc60b03SMartin Matuska _p = p;
225acc60b03SMartin Matuska version = archive_be16dec(p);
226acc60b03SMartin Matuska p += 4;/* version(2 bytes) + library version(2 bytes) */
227acc60b03SMartin Matuska
228acc60b03SMartin Matuska if (version >= 0x940) {
229acc60b03SMartin Matuska unsigned reqversion = archive_be16dec(p); p += 2;
230acc60b03SMartin Matuska if (reqversion < 0x900) {
231acc60b03SMartin Matuska archive_set_error(&self->archive->archive,
232acc60b03SMartin Matuska ARCHIVE_ERRNO_MISC, "Invalid required version");
233acc60b03SMartin Matuska return (ARCHIVE_FAILED);
234acc60b03SMartin Matuska }
235acc60b03SMartin Matuska }
236acc60b03SMartin Matuska
237acc60b03SMartin Matuska method = *p++;
238acc60b03SMartin Matuska if (method < 1 || method > 3) {
239acc60b03SMartin Matuska archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
240acc60b03SMartin Matuska "Unsupported method");
241acc60b03SMartin Matuska return (ARCHIVE_FAILED);
242acc60b03SMartin Matuska }
243acc60b03SMartin Matuska
244acc60b03SMartin Matuska if (version >= 0x940) {
245acc60b03SMartin Matuska unsigned level = *p++;
246cdf63a70SMartin Matuska #if 0
247cdf63a70SMartin Matuska unsigned default_level[] = {0, 3, 1, 9};
248cdf63a70SMartin Matuska #endif
249cdf63a70SMartin Matuska if (level == 0)
250cdf63a70SMartin Matuska /* Method is 1..3 here due to check above. */
251cdf63a70SMartin Matuska #if 0 /* Avoid an error Clang Static Analyzer claims
252cdf63a70SMartin Matuska "Value stored to 'level' is never read". */
253cdf63a70SMartin Matuska level = default_level[method];
254cdf63a70SMartin Matuska #else
255cdf63a70SMartin Matuska ;/* NOP */
256cdf63a70SMartin Matuska #endif
257cdf63a70SMartin Matuska else if (level > 9) {
258acc60b03SMartin Matuska archive_set_error(&self->archive->archive,
259acc60b03SMartin Matuska ARCHIVE_ERRNO_MISC, "Invalid level");
260acc60b03SMartin Matuska return (ARCHIVE_FAILED);
261acc60b03SMartin Matuska }
262acc60b03SMartin Matuska }
263acc60b03SMartin Matuska
264acc60b03SMartin Matuska flags = archive_be32dec(p); p += 4;
265acc60b03SMartin Matuska
266acc60b03SMartin Matuska if (flags & FILTER)
267acc60b03SMartin Matuska p += 4; /* Skip filter */
268acc60b03SMartin Matuska p += 4; /* Skip mode */
269acc60b03SMartin Matuska if (version >= 0x940)
270acc60b03SMartin Matuska p += 8; /* Skip mtime */
271acc60b03SMartin Matuska else
272acc60b03SMartin Matuska p += 4; /* Skip mtime */
273acc60b03SMartin Matuska len = *p++; /* Read filename length */
274acc60b03SMartin Matuska len += p - _p;
275acc60b03SMartin Matuska /* Make sure we have all bytes we need to calculate checksum. */
276acc60b03SMartin Matuska p = __archive_read_filter_ahead(self->upstream, len + 4, NULL);
277acc60b03SMartin Matuska if (p == NULL)
278acc60b03SMartin Matuska goto truncated;
279acc60b03SMartin Matuska if (flags & CRC32_HEADER)
280acc60b03SMartin Matuska checksum = crc32(crc32(0, NULL, 0), p, len);
281acc60b03SMartin Matuska else
282acc60b03SMartin Matuska checksum = adler32(adler32(0, NULL, 0), p, len);
283bd5e624aSMartin Matuska #ifndef DONT_FAIL_ON_CRC_ERROR
284*b9128a37SMartin Matuska if (archive_be32dec(p + len) != checksum)
285acc60b03SMartin Matuska goto corrupted;
286bd5e624aSMartin Matuska #endif
287acc60b03SMartin Matuska __archive_read_filter_consume(self->upstream, len + 4);
288acc60b03SMartin Matuska if (flags & EXTRA_FIELD) {
289acc60b03SMartin Matuska /* Skip extra field */
290acc60b03SMartin Matuska p = __archive_read_filter_ahead(self->upstream, 4, NULL);
291acc60b03SMartin Matuska if (p == NULL)
292acc60b03SMartin Matuska goto truncated;
293acc60b03SMartin Matuska len = archive_be32dec(p);
294acc60b03SMartin Matuska __archive_read_filter_consume(self->upstream, len + 4 + 4);
295acc60b03SMartin Matuska }
296acc60b03SMartin Matuska state->flags = flags;
297acc60b03SMartin Matuska state->in_stream = 1;
298acc60b03SMartin Matuska return (ARCHIVE_OK);
299acc60b03SMartin Matuska truncated:
300acc60b03SMartin Matuska archive_set_error(&self->archive->archive,
301acc60b03SMartin Matuska ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
302acc60b03SMartin Matuska return (ARCHIVE_FAILED);
303acc60b03SMartin Matuska corrupted:
304acc60b03SMartin Matuska archive_set_error(&self->archive->archive,
305acc60b03SMartin Matuska ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
306acc60b03SMartin Matuska return (ARCHIVE_FAILED);
307acc60b03SMartin Matuska }
308acc60b03SMartin Matuska
309acc60b03SMartin Matuska static int
consume_block_info(struct archive_read_filter * self)310acc60b03SMartin Matuska consume_block_info(struct archive_read_filter *self)
311acc60b03SMartin Matuska {
312acc60b03SMartin Matuska struct read_lzop *state = (struct read_lzop *)self->data;
313acc60b03SMartin Matuska const unsigned char *p;
314acc60b03SMartin Matuska unsigned flags = state->flags;
315acc60b03SMartin Matuska
316acc60b03SMartin Matuska p = __archive_read_filter_ahead(self->upstream, 4, NULL);
317acc60b03SMartin Matuska if (p == NULL)
318acc60b03SMartin Matuska goto truncated;
319acc60b03SMartin Matuska state->uncompressed_size = archive_be32dec(p);
320acc60b03SMartin Matuska __archive_read_filter_consume(self->upstream, 4);
321acc60b03SMartin Matuska if (state->uncompressed_size == 0)
322acc60b03SMartin Matuska return (ARCHIVE_EOF);
323acc60b03SMartin Matuska if (state->uncompressed_size > MAX_BLOCK_SIZE)
324acc60b03SMartin Matuska goto corrupted;
325acc60b03SMartin Matuska
326acc60b03SMartin Matuska p = __archive_read_filter_ahead(self->upstream, 4, NULL);
327acc60b03SMartin Matuska if (p == NULL)
328acc60b03SMartin Matuska goto truncated;
329acc60b03SMartin Matuska state->compressed_size = archive_be32dec(p);
330acc60b03SMartin Matuska __archive_read_filter_consume(self->upstream, 4);
331acc60b03SMartin Matuska if (state->compressed_size > state->uncompressed_size)
332acc60b03SMartin Matuska goto corrupted;
333acc60b03SMartin Matuska
334acc60b03SMartin Matuska if (flags & (CRC32_UNCOMPRESSED | ADLER32_UNCOMPRESSED)) {
335acc60b03SMartin Matuska p = __archive_read_filter_ahead(self->upstream, 4, NULL);
336acc60b03SMartin Matuska if (p == NULL)
337acc60b03SMartin Matuska goto truncated;
338acc60b03SMartin Matuska state->compressed_cksum = state->uncompressed_cksum =
339acc60b03SMartin Matuska archive_be32dec(p);
340acc60b03SMartin Matuska __archive_read_filter_consume(self->upstream, 4);
341acc60b03SMartin Matuska }
342acc60b03SMartin Matuska if ((flags & (CRC32_COMPRESSED | ADLER32_COMPRESSED)) &&
343acc60b03SMartin Matuska state->compressed_size < state->uncompressed_size) {
344acc60b03SMartin Matuska p = __archive_read_filter_ahead(self->upstream, 4, NULL);
345acc60b03SMartin Matuska if (p == NULL)
346acc60b03SMartin Matuska goto truncated;
347acc60b03SMartin Matuska state->compressed_cksum = archive_be32dec(p);
348acc60b03SMartin Matuska __archive_read_filter_consume(self->upstream, 4);
349acc60b03SMartin Matuska }
350acc60b03SMartin Matuska return (ARCHIVE_OK);
351acc60b03SMartin Matuska truncated:
352acc60b03SMartin Matuska archive_set_error(&self->archive->archive,
353acc60b03SMartin Matuska ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
354acc60b03SMartin Matuska return (ARCHIVE_FAILED);
355acc60b03SMartin Matuska corrupted:
356acc60b03SMartin Matuska archive_set_error(&self->archive->archive,
357acc60b03SMartin Matuska ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
358acc60b03SMartin Matuska return (ARCHIVE_FAILED);
359acc60b03SMartin Matuska }
360acc60b03SMartin Matuska
361acc60b03SMartin Matuska static ssize_t
lzop_filter_read(struct archive_read_filter * self,const void ** p)362acc60b03SMartin Matuska lzop_filter_read(struct archive_read_filter *self, const void **p)
363acc60b03SMartin Matuska {
364acc60b03SMartin Matuska struct read_lzop *state = (struct read_lzop *)self->data;
365acc60b03SMartin Matuska const void *b;
366acc60b03SMartin Matuska lzo_uint out_size;
367acc60b03SMartin Matuska uint32_t cksum;
368acc60b03SMartin Matuska int ret, r;
369acc60b03SMartin Matuska
370acc60b03SMartin Matuska if (state->unconsumed_bytes) {
371acc60b03SMartin Matuska __archive_read_filter_consume(self->upstream,
372acc60b03SMartin Matuska state->unconsumed_bytes);
373acc60b03SMartin Matuska state->unconsumed_bytes = 0;
374acc60b03SMartin Matuska }
375acc60b03SMartin Matuska if (state->eof)
376acc60b03SMartin Matuska return (0);
377acc60b03SMartin Matuska
378acc60b03SMartin Matuska for (;;) {
379acc60b03SMartin Matuska if (!state->in_stream) {
380acc60b03SMartin Matuska ret = consume_header(self);
381acc60b03SMartin Matuska if (ret < ARCHIVE_OK)
382acc60b03SMartin Matuska return (ret);
383acc60b03SMartin Matuska if (ret == ARCHIVE_EOF) {
384acc60b03SMartin Matuska state->eof = 1;
385acc60b03SMartin Matuska return (0);
386acc60b03SMartin Matuska }
387acc60b03SMartin Matuska }
388acc60b03SMartin Matuska ret = consume_block_info(self);
389acc60b03SMartin Matuska if (ret < ARCHIVE_OK)
390acc60b03SMartin Matuska return (ret);
391acc60b03SMartin Matuska if (ret == ARCHIVE_EOF)
392acc60b03SMartin Matuska state->in_stream = 0;
393acc60b03SMartin Matuska else
394acc60b03SMartin Matuska break;
395acc60b03SMartin Matuska }
396acc60b03SMartin Matuska
397acc60b03SMartin Matuska if (state->out_block == NULL ||
398acc60b03SMartin Matuska state->out_block_size < state->uncompressed_size) {
399acc60b03SMartin Matuska void *new_block;
400acc60b03SMartin Matuska
401acc60b03SMartin Matuska new_block = realloc(state->out_block, state->uncompressed_size);
402acc60b03SMartin Matuska if (new_block == NULL) {
403acc60b03SMartin Matuska archive_set_error(&self->archive->archive, ENOMEM,
404acc60b03SMartin Matuska "Can't allocate data for lzop decompression");
405acc60b03SMartin Matuska return (ARCHIVE_FATAL);
406acc60b03SMartin Matuska }
407acc60b03SMartin Matuska state->out_block = new_block;
408acc60b03SMartin Matuska state->out_block_size = state->uncompressed_size;
409acc60b03SMartin Matuska }
410acc60b03SMartin Matuska
411acc60b03SMartin Matuska b = __archive_read_filter_ahead(self->upstream,
412acc60b03SMartin Matuska state->compressed_size, NULL);
413acc60b03SMartin Matuska if (b == NULL) {
414acc60b03SMartin Matuska archive_set_error(&self->archive->archive,
415acc60b03SMartin Matuska ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
416acc60b03SMartin Matuska return (ARCHIVE_FATAL);
417acc60b03SMartin Matuska }
418acc60b03SMartin Matuska if (state->flags & CRC32_COMPRESSED)
419acc60b03SMartin Matuska cksum = crc32(crc32(0, NULL, 0), b, state->compressed_size);
420acc60b03SMartin Matuska else if (state->flags & ADLER32_COMPRESSED)
421acc60b03SMartin Matuska cksum = adler32(adler32(0, NULL, 0), b, state->compressed_size);
422acc60b03SMartin Matuska else
423acc60b03SMartin Matuska cksum = state->compressed_cksum;
424acc60b03SMartin Matuska if (cksum != state->compressed_cksum) {
425acc60b03SMartin Matuska archive_set_error(&self->archive->archive,
426acc60b03SMartin Matuska ARCHIVE_ERRNO_MISC, "Corrupted data");
427acc60b03SMartin Matuska return (ARCHIVE_FATAL);
428acc60b03SMartin Matuska }
429acc60b03SMartin Matuska
430acc60b03SMartin Matuska /*
431acc60b03SMartin Matuska * If the both uncompressed size and compressed size are the same,
432acc60b03SMartin Matuska * we do not decompress this block.
433acc60b03SMartin Matuska */
434acc60b03SMartin Matuska if (state->uncompressed_size == state->compressed_size) {
435acc60b03SMartin Matuska *p = b;
436acc60b03SMartin Matuska state->total_out += state->compressed_size;
437acc60b03SMartin Matuska state->unconsumed_bytes = state->compressed_size;
438acc60b03SMartin Matuska return ((ssize_t)state->uncompressed_size);
439acc60b03SMartin Matuska }
440acc60b03SMartin Matuska
441acc60b03SMartin Matuska /*
4422dbf8c4aSMartin Matuska * Drive lzo uncompression.
443acc60b03SMartin Matuska */
444acc60b03SMartin Matuska out_size = (lzo_uint)state->uncompressed_size;
445acc60b03SMartin Matuska r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size,
446acc60b03SMartin Matuska state->out_block, &out_size, NULL);
447acc60b03SMartin Matuska switch (r) {
448acc60b03SMartin Matuska case LZO_E_OK:
449acc60b03SMartin Matuska if (out_size == state->uncompressed_size)
450acc60b03SMartin Matuska break;
451acc60b03SMartin Matuska archive_set_error(&self->archive->archive,
452acc60b03SMartin Matuska ARCHIVE_ERRNO_MISC, "Corrupted data");
453acc60b03SMartin Matuska return (ARCHIVE_FATAL);
454acc60b03SMartin Matuska case LZO_E_OUT_OF_MEMORY:
455acc60b03SMartin Matuska archive_set_error(&self->archive->archive, ENOMEM,
456acc60b03SMartin Matuska "lzop decompression failed: out of memory");
457acc60b03SMartin Matuska return (ARCHIVE_FATAL);
458acc60b03SMartin Matuska default:
459acc60b03SMartin Matuska archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
460acc60b03SMartin Matuska "lzop decompression failed: %d", r);
461acc60b03SMartin Matuska return (ARCHIVE_FATAL);
462acc60b03SMartin Matuska }
463acc60b03SMartin Matuska
464acc60b03SMartin Matuska if (state->flags & CRC32_UNCOMPRESSED)
465acc60b03SMartin Matuska cksum = crc32(crc32(0, NULL, 0), state->out_block,
466acc60b03SMartin Matuska state->uncompressed_size);
467acc60b03SMartin Matuska else if (state->flags & ADLER32_UNCOMPRESSED)
468acc60b03SMartin Matuska cksum = adler32(adler32(0, NULL, 0), state->out_block,
469acc60b03SMartin Matuska state->uncompressed_size);
470acc60b03SMartin Matuska else
471acc60b03SMartin Matuska cksum = state->uncompressed_cksum;
472acc60b03SMartin Matuska if (cksum != state->uncompressed_cksum) {
473acc60b03SMartin Matuska archive_set_error(&self->archive->archive,
474acc60b03SMartin Matuska ARCHIVE_ERRNO_MISC, "Corrupted data");
475acc60b03SMartin Matuska return (ARCHIVE_FATAL);
476acc60b03SMartin Matuska }
477acc60b03SMartin Matuska
478acc60b03SMartin Matuska __archive_read_filter_consume(self->upstream, state->compressed_size);
479acc60b03SMartin Matuska *p = state->out_block;
480acc60b03SMartin Matuska state->total_out += out_size;
481acc60b03SMartin Matuska return ((ssize_t)out_size);
482acc60b03SMartin Matuska }
483acc60b03SMartin Matuska
484acc60b03SMartin Matuska /*
485acc60b03SMartin Matuska * Clean up the decompressor.
486acc60b03SMartin Matuska */
487acc60b03SMartin Matuska static int
lzop_filter_close(struct archive_read_filter * self)488acc60b03SMartin Matuska lzop_filter_close(struct archive_read_filter *self)
489acc60b03SMartin Matuska {
490acc60b03SMartin Matuska struct read_lzop *state = (struct read_lzop *)self->data;
491acc60b03SMartin Matuska
492acc60b03SMartin Matuska free(state->out_block);
493acc60b03SMartin Matuska free(state);
494acc60b03SMartin Matuska return (ARCHIVE_OK);
495acc60b03SMartin Matuska }
496acc60b03SMartin Matuska
497acc60b03SMartin Matuska #endif
498