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