1c09f92d2SPeter Avalos /*-
259bf7050SPeter Avalos * Copyright (c) 2010-2012 Michihiro NAKAJIMA
3c09f92d2SPeter Avalos * All rights reserved.
4c09f92d2SPeter Avalos *
5c09f92d2SPeter Avalos * Redistribution and use in source and binary forms, with or without
6c09f92d2SPeter Avalos * modification, are permitted provided that the following conditions
7c09f92d2SPeter Avalos * are met:
8c09f92d2SPeter Avalos * 1. Redistributions of source code must retain the above copyright
9c09f92d2SPeter Avalos * notice, this list of conditions and the following disclaimer.
10c09f92d2SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright
11c09f92d2SPeter Avalos * notice, this list of conditions and the following disclaimer in the
12c09f92d2SPeter Avalos * documentation and/or other materials provided with the distribution.
13c09f92d2SPeter Avalos *
14c09f92d2SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15c09f92d2SPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16c09f92d2SPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17c09f92d2SPeter Avalos * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18c09f92d2SPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19c09f92d2SPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20c09f92d2SPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21c09f92d2SPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22c09f92d2SPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23c09f92d2SPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24c09f92d2SPeter Avalos */
25c09f92d2SPeter Avalos
26c09f92d2SPeter Avalos #include "archive_platform.h"
27c09f92d2SPeter Avalos
28c09f92d2SPeter Avalos #ifdef HAVE_ERRNO_H
29c09f92d2SPeter Avalos #include <errno.h>
30c09f92d2SPeter Avalos #endif
31c09f92d2SPeter Avalos #ifdef HAVE_LIMITS_H
32c09f92d2SPeter Avalos #include <limits.h>
33c09f92d2SPeter Avalos #endif
34c09f92d2SPeter Avalos #ifdef HAVE_STDLIB_H
35c09f92d2SPeter Avalos #include <stdlib.h>
36c09f92d2SPeter Avalos #endif
37c09f92d2SPeter Avalos #ifdef HAVE_STRING_H
38c09f92d2SPeter Avalos #include <string.h>
39c09f92d2SPeter Avalos #endif
40c09f92d2SPeter Avalos #ifdef HAVE_ZLIB_H
41c09f92d2SPeter Avalos #include <zlib.h>
42c09f92d2SPeter Avalos #endif
43c09f92d2SPeter Avalos
44c09f92d2SPeter Avalos #include "archive.h"
45c09f92d2SPeter Avalos #include "archive_entry.h"
46c09f92d2SPeter Avalos #include "archive_entry_locale.h"
47c09f92d2SPeter Avalos #include "archive_private.h"
48c09f92d2SPeter Avalos #include "archive_read_private.h"
49c09f92d2SPeter Avalos #include "archive_endian.h"
50c09f92d2SPeter Avalos
51c09f92d2SPeter Avalos
52c09f92d2SPeter Avalos struct lzx_dec {
53c09f92d2SPeter Avalos /* Decoding status. */
54c09f92d2SPeter Avalos int state;
55c09f92d2SPeter Avalos
56c09f92d2SPeter Avalos /*
57c09f92d2SPeter Avalos * Window to see last decoded data, from 32KBi to 2MBi.
58c09f92d2SPeter Avalos */
59c09f92d2SPeter Avalos int w_size;
60c09f92d2SPeter Avalos int w_mask;
61c09f92d2SPeter Avalos /* Window buffer, which is a loop buffer. */
62c09f92d2SPeter Avalos unsigned char *w_buff;
63c09f92d2SPeter Avalos /* The insert position to the window. */
64c09f92d2SPeter Avalos int w_pos;
65c09f92d2SPeter Avalos /* The position where we can copy decoded code from the window. */
66c09f92d2SPeter Avalos int copy_pos;
67c09f92d2SPeter Avalos /* The length how many bytes we can copy decoded code from
68c09f92d2SPeter Avalos * the window. */
69c09f92d2SPeter Avalos int copy_len;
70e95abc47Szrj /* Translation reversal for x86 processor CALL byte sequence(E8).
71c09f92d2SPeter Avalos * This is used for LZX only. */
72c09f92d2SPeter Avalos uint32_t translation_size;
73c09f92d2SPeter Avalos char translation;
74c09f92d2SPeter Avalos char block_type;
75c09f92d2SPeter Avalos #define VERBATIM_BLOCK 1
76c09f92d2SPeter Avalos #define ALIGNED_OFFSET_BLOCK 2
77c09f92d2SPeter Avalos #define UNCOMPRESSED_BLOCK 3
78c09f92d2SPeter Avalos size_t block_size;
79c09f92d2SPeter Avalos size_t block_bytes_avail;
80c09f92d2SPeter Avalos /* Repeated offset. */
81c09f92d2SPeter Avalos int r0, r1, r2;
82c09f92d2SPeter Avalos unsigned char rbytes[4];
83c09f92d2SPeter Avalos int rbytes_avail;
84c09f92d2SPeter Avalos int length_header;
85c09f92d2SPeter Avalos int position_slot;
86c09f92d2SPeter Avalos int offset_bits;
87c09f92d2SPeter Avalos
88c09f92d2SPeter Avalos struct lzx_pos_tbl {
89c09f92d2SPeter Avalos int base;
90c09f92d2SPeter Avalos int footer_bits;
91c09f92d2SPeter Avalos } *pos_tbl;
92c09f92d2SPeter Avalos /*
93c09f92d2SPeter Avalos * Bit stream reader.
94c09f92d2SPeter Avalos */
95c09f92d2SPeter Avalos struct lzx_br {
96c09f92d2SPeter Avalos #define CACHE_TYPE uint64_t
97c09f92d2SPeter Avalos #define CACHE_BITS (8 * sizeof(CACHE_TYPE))
98c09f92d2SPeter Avalos /* Cache buffer. */
99c09f92d2SPeter Avalos CACHE_TYPE cache_buffer;
100c09f92d2SPeter Avalos /* Indicates how many bits avail in cache_buffer. */
101c09f92d2SPeter Avalos int cache_avail;
102c09f92d2SPeter Avalos unsigned char odd;
103c09f92d2SPeter Avalos char have_odd;
104c09f92d2SPeter Avalos } br;
105c09f92d2SPeter Avalos
106c09f92d2SPeter Avalos /*
107c09f92d2SPeter Avalos * Huffman coding.
108c09f92d2SPeter Avalos */
109c09f92d2SPeter Avalos struct huffman {
110c09f92d2SPeter Avalos int len_size;
111c09f92d2SPeter Avalos int freq[17];
112c09f92d2SPeter Avalos unsigned char *bitlen;
113c09f92d2SPeter Avalos
114c09f92d2SPeter Avalos /*
115c09f92d2SPeter Avalos * Use a index table. It's faster than searching a huffman
116c09f92d2SPeter Avalos * coding tree, which is a binary tree. But a use of a large
117c09f92d2SPeter Avalos * index table causes L1 cache read miss many times.
118c09f92d2SPeter Avalos */
119c09f92d2SPeter Avalos int max_bits;
120c09f92d2SPeter Avalos int tbl_bits;
121c09f92d2SPeter Avalos int tree_used;
122c09f92d2SPeter Avalos /* Direct access table. */
123c09f92d2SPeter Avalos uint16_t *tbl;
124c09f92d2SPeter Avalos } at, lt, mt, pt;
125c09f92d2SPeter Avalos
126c09f92d2SPeter Avalos int loop;
127c09f92d2SPeter Avalos int error;
128c09f92d2SPeter Avalos };
129c09f92d2SPeter Avalos
130c09f92d2SPeter Avalos static const int slots[] = {
131c09f92d2SPeter Avalos 30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
132c09f92d2SPeter Avalos };
133c09f92d2SPeter Avalos #define SLOT_BASE 15
134c09f92d2SPeter Avalos #define SLOT_MAX 21/*->25*/
135c09f92d2SPeter Avalos
136c09f92d2SPeter Avalos struct lzx_stream {
137c09f92d2SPeter Avalos const unsigned char *next_in;
138c09f92d2SPeter Avalos int64_t avail_in;
139c09f92d2SPeter Avalos int64_t total_in;
140c09f92d2SPeter Avalos unsigned char *next_out;
141c09f92d2SPeter Avalos int64_t avail_out;
142c09f92d2SPeter Avalos int64_t total_out;
143c09f92d2SPeter Avalos struct lzx_dec *ds;
144c09f92d2SPeter Avalos };
145c09f92d2SPeter Avalos
146c09f92d2SPeter Avalos /*
147c09f92d2SPeter Avalos * Cabinet file definitions.
148c09f92d2SPeter Avalos */
149c09f92d2SPeter Avalos /* CFHEADER offset */
150c09f92d2SPeter Avalos #define CFHEADER_signature 0
151c09f92d2SPeter Avalos #define CFHEADER_cbCabinet 8
152c09f92d2SPeter Avalos #define CFHEADER_coffFiles 16
153c09f92d2SPeter Avalos #define CFHEADER_versionMinor 24
154c09f92d2SPeter Avalos #define CFHEADER_versionMajor 25
155c09f92d2SPeter Avalos #define CFHEADER_cFolders 26
156c09f92d2SPeter Avalos #define CFHEADER_cFiles 28
157c09f92d2SPeter Avalos #define CFHEADER_flags 30
158c09f92d2SPeter Avalos #define CFHEADER_setID 32
159c09f92d2SPeter Avalos #define CFHEADER_iCabinet 34
160c09f92d2SPeter Avalos #define CFHEADER_cbCFHeader 36
161c09f92d2SPeter Avalos #define CFHEADER_cbCFFolder 38
162c09f92d2SPeter Avalos #define CFHEADER_cbCFData 39
163c09f92d2SPeter Avalos
164c09f92d2SPeter Avalos /* CFFOLDER offset */
165c09f92d2SPeter Avalos #define CFFOLDER_coffCabStart 0
166c09f92d2SPeter Avalos #define CFFOLDER_cCFData 4
167c09f92d2SPeter Avalos #define CFFOLDER_typeCompress 6
168c09f92d2SPeter Avalos #define CFFOLDER_abReserve 8
169c09f92d2SPeter Avalos
170c09f92d2SPeter Avalos /* CFFILE offset */
171c09f92d2SPeter Avalos #define CFFILE_cbFile 0
172c09f92d2SPeter Avalos #define CFFILE_uoffFolderStart 4
173c09f92d2SPeter Avalos #define CFFILE_iFolder 8
174c09f92d2SPeter Avalos #define CFFILE_date_time 10
175c09f92d2SPeter Avalos #define CFFILE_attribs 14
176c09f92d2SPeter Avalos
177c09f92d2SPeter Avalos /* CFDATA offset */
178c09f92d2SPeter Avalos #define CFDATA_csum 0
179c09f92d2SPeter Avalos #define CFDATA_cbData 4
180c09f92d2SPeter Avalos #define CFDATA_cbUncomp 6
181c09f92d2SPeter Avalos
182e95abc47Szrj static const char * const compression_name[] = {
183c09f92d2SPeter Avalos "NONE",
184c09f92d2SPeter Avalos "MSZIP",
185c09f92d2SPeter Avalos "Quantum",
186c09f92d2SPeter Avalos "LZX",
187c09f92d2SPeter Avalos };
188c09f92d2SPeter Avalos
189c09f92d2SPeter Avalos struct cfdata {
190c09f92d2SPeter Avalos /* Sum value of this CFDATA. */
191c09f92d2SPeter Avalos uint32_t sum;
192c09f92d2SPeter Avalos uint16_t compressed_size;
193c09f92d2SPeter Avalos uint16_t compressed_bytes_remaining;
194c09f92d2SPeter Avalos uint16_t uncompressed_size;
195c09f92d2SPeter Avalos uint16_t uncompressed_bytes_remaining;
196c09f92d2SPeter Avalos /* To know how many bytes we have decompressed. */
197c09f92d2SPeter Avalos uint16_t uncompressed_avail;
198c09f92d2SPeter Avalos /* Offset from the beginning of compressed data of this CFDATA */
199c09f92d2SPeter Avalos uint16_t read_offset;
200c09f92d2SPeter Avalos int64_t unconsumed;
201c09f92d2SPeter Avalos /* To keep memory image of this CFDATA to compute the sum. */
202c09f92d2SPeter Avalos size_t memimage_size;
203c09f92d2SPeter Avalos unsigned char *memimage;
204c09f92d2SPeter Avalos /* Result of calculation of sum. */
205c09f92d2SPeter Avalos uint32_t sum_calculated;
206c09f92d2SPeter Avalos unsigned char sum_extra[4];
207c09f92d2SPeter Avalos int sum_extra_avail;
208c09f92d2SPeter Avalos const void *sum_ptr;
209c09f92d2SPeter Avalos };
210c09f92d2SPeter Avalos
211c09f92d2SPeter Avalos struct cffolder {
212c09f92d2SPeter Avalos uint32_t cfdata_offset_in_cab;
213c09f92d2SPeter Avalos uint16_t cfdata_count;
214c09f92d2SPeter Avalos uint16_t comptype;
215c09f92d2SPeter Avalos #define COMPTYPE_NONE 0x0000
216c09f92d2SPeter Avalos #define COMPTYPE_MSZIP 0x0001
217c09f92d2SPeter Avalos #define COMPTYPE_QUANTUM 0x0002
218c09f92d2SPeter Avalos #define COMPTYPE_LZX 0x0003
219c09f92d2SPeter Avalos uint16_t compdata;
220c09f92d2SPeter Avalos const char *compname;
221c09f92d2SPeter Avalos /* At the time reading CFDATA */
222c09f92d2SPeter Avalos struct cfdata cfdata;
223c09f92d2SPeter Avalos int cfdata_index;
224c09f92d2SPeter Avalos /* Flags to mark progress of decompression. */
225c09f92d2SPeter Avalos char decompress_init;
226c09f92d2SPeter Avalos };
227c09f92d2SPeter Avalos
228c09f92d2SPeter Avalos struct cffile {
229c09f92d2SPeter Avalos uint32_t uncompressed_size;
230c09f92d2SPeter Avalos uint32_t offset;
231c09f92d2SPeter Avalos time_t mtime;
232c09f92d2SPeter Avalos uint16_t folder;
233c09f92d2SPeter Avalos #define iFoldCONTINUED_FROM_PREV 0xFFFD
234c09f92d2SPeter Avalos #define iFoldCONTINUED_TO_NEXT 0xFFFE
235c09f92d2SPeter Avalos #define iFoldCONTINUED_PREV_AND_NEXT 0xFFFF
236c09f92d2SPeter Avalos unsigned char attr;
237c09f92d2SPeter Avalos #define ATTR_RDONLY 0x01
238c09f92d2SPeter Avalos #define ATTR_NAME_IS_UTF 0x80
239c09f92d2SPeter Avalos struct archive_string pathname;
240c09f92d2SPeter Avalos };
241c09f92d2SPeter Avalos
242c09f92d2SPeter Avalos struct cfheader {
243c09f92d2SPeter Avalos /* Total bytes of all file size in a Cabinet. */
244c09f92d2SPeter Avalos uint32_t total_bytes;
245c09f92d2SPeter Avalos uint32_t files_offset;
246c09f92d2SPeter Avalos uint16_t folder_count;
247c09f92d2SPeter Avalos uint16_t file_count;
248c09f92d2SPeter Avalos uint16_t flags;
249c09f92d2SPeter Avalos #define PREV_CABINET 0x0001
250c09f92d2SPeter Avalos #define NEXT_CABINET 0x0002
251c09f92d2SPeter Avalos #define RESERVE_PRESENT 0x0004
252c09f92d2SPeter Avalos uint16_t setid;
253c09f92d2SPeter Avalos uint16_t cabinet;
254c09f92d2SPeter Avalos /* Version number. */
255c09f92d2SPeter Avalos unsigned char major;
256c09f92d2SPeter Avalos unsigned char minor;
257c09f92d2SPeter Avalos unsigned char cffolder;
258c09f92d2SPeter Avalos unsigned char cfdata;
259c09f92d2SPeter Avalos /* All folders in a cabinet. */
260c09f92d2SPeter Avalos struct cffolder *folder_array;
261c09f92d2SPeter Avalos /* All files in a cabinet. */
262c09f92d2SPeter Avalos struct cffile *file_array;
263c09f92d2SPeter Avalos int file_index;
264c09f92d2SPeter Avalos };
265c09f92d2SPeter Avalos
266c09f92d2SPeter Avalos struct cab {
267c09f92d2SPeter Avalos /* entry_bytes_remaining is the number of bytes we expect. */
268c09f92d2SPeter Avalos int64_t entry_offset;
269c09f92d2SPeter Avalos int64_t entry_bytes_remaining;
270c09f92d2SPeter Avalos int64_t entry_unconsumed;
271c09f92d2SPeter Avalos int64_t entry_compressed_bytes_read;
272c09f92d2SPeter Avalos int64_t entry_uncompressed_bytes_read;
273c09f92d2SPeter Avalos struct cffolder *entry_cffolder;
274c09f92d2SPeter Avalos struct cffile *entry_cffile;
275c09f92d2SPeter Avalos struct cfdata *entry_cfdata;
276c09f92d2SPeter Avalos
277c09f92d2SPeter Avalos /* Offset from beginning of a cabinet file. */
278c09f92d2SPeter Avalos int64_t cab_offset;
279c09f92d2SPeter Avalos struct cfheader cfheader;
280c09f92d2SPeter Avalos struct archive_wstring ws;
281c09f92d2SPeter Avalos
282c09f92d2SPeter Avalos /* Flag to mark progress that an archive was read their first header.*/
283c09f92d2SPeter Avalos char found_header;
284c09f92d2SPeter Avalos char end_of_archive;
285c09f92d2SPeter Avalos char end_of_entry;
286c09f92d2SPeter Avalos char end_of_entry_cleanup;
28759bf7050SPeter Avalos char read_data_invoked;
28859bf7050SPeter Avalos int64_t bytes_skipped;
289c09f92d2SPeter Avalos
290c09f92d2SPeter Avalos unsigned char *uncompressed_buffer;
291c09f92d2SPeter Avalos size_t uncompressed_buffer_size;
292c09f92d2SPeter Avalos
293c09f92d2SPeter Avalos int init_default_conversion;
294c09f92d2SPeter Avalos struct archive_string_conv *sconv;
295c09f92d2SPeter Avalos struct archive_string_conv *sconv_default;
296c09f92d2SPeter Avalos struct archive_string_conv *sconv_utf8;
297c09f92d2SPeter Avalos char format_name[64];
298c09f92d2SPeter Avalos
299c09f92d2SPeter Avalos #ifdef HAVE_ZLIB_H
300c09f92d2SPeter Avalos z_stream stream;
301c09f92d2SPeter Avalos char stream_valid;
302c09f92d2SPeter Avalos #endif
303c09f92d2SPeter Avalos struct lzx_stream xstrm;
304c09f92d2SPeter Avalos };
305c09f92d2SPeter Avalos
306c09f92d2SPeter Avalos static int archive_read_format_cab_bid(struct archive_read *, int);
307c09f92d2SPeter Avalos static int archive_read_format_cab_options(struct archive_read *,
308c09f92d2SPeter Avalos const char *, const char *);
309c09f92d2SPeter Avalos static int archive_read_format_cab_read_header(struct archive_read *,
310c09f92d2SPeter Avalos struct archive_entry *);
311c09f92d2SPeter Avalos static int archive_read_format_cab_read_data(struct archive_read *,
312c09f92d2SPeter Avalos const void **, size_t *, int64_t *);
313c09f92d2SPeter Avalos static int archive_read_format_cab_read_data_skip(struct archive_read *);
314c09f92d2SPeter Avalos static int archive_read_format_cab_cleanup(struct archive_read *);
315c09f92d2SPeter Avalos
316c09f92d2SPeter Avalos static int cab_skip_sfx(struct archive_read *);
317c09f92d2SPeter Avalos static time_t cab_dos_time(const unsigned char *);
318c09f92d2SPeter Avalos static int cab_read_data(struct archive_read *, const void **,
319c09f92d2SPeter Avalos size_t *, int64_t *);
320c09f92d2SPeter Avalos static int cab_read_header(struct archive_read *);
321c09f92d2SPeter Avalos static uint32_t cab_checksum_cfdata_4(const void *, size_t bytes, uint32_t);
322c09f92d2SPeter Avalos static uint32_t cab_checksum_cfdata(const void *, size_t bytes, uint32_t);
323c09f92d2SPeter Avalos static void cab_checksum_update(struct archive_read *, size_t);
324c09f92d2SPeter Avalos static int cab_checksum_finish(struct archive_read *);
325c09f92d2SPeter Avalos static int cab_next_cfdata(struct archive_read *);
326c09f92d2SPeter Avalos static const void *cab_read_ahead_cfdata(struct archive_read *, ssize_t *);
327c09f92d2SPeter Avalos static const void *cab_read_ahead_cfdata_none(struct archive_read *, ssize_t *);
328c09f92d2SPeter Avalos static const void *cab_read_ahead_cfdata_deflate(struct archive_read *,
329c09f92d2SPeter Avalos ssize_t *);
330c09f92d2SPeter Avalos static const void *cab_read_ahead_cfdata_lzx(struct archive_read *,
331c09f92d2SPeter Avalos ssize_t *);
332c09f92d2SPeter Avalos static int64_t cab_consume_cfdata(struct archive_read *, int64_t);
333c09f92d2SPeter Avalos static int64_t cab_minimum_consume_cfdata(struct archive_read *, int64_t);
334c09f92d2SPeter Avalos static int lzx_decode_init(struct lzx_stream *, int);
335c09f92d2SPeter Avalos static int lzx_read_blocks(struct lzx_stream *, int);
336c09f92d2SPeter Avalos static int lzx_decode_blocks(struct lzx_stream *, int);
337c09f92d2SPeter Avalos static void lzx_decode_free(struct lzx_stream *);
338c09f92d2SPeter Avalos static void lzx_translation(struct lzx_stream *, void *, size_t, uint32_t);
339c09f92d2SPeter Avalos static void lzx_cleanup_bitstream(struct lzx_stream *);
340c09f92d2SPeter Avalos static int lzx_decode(struct lzx_stream *, int);
341c09f92d2SPeter Avalos static int lzx_read_pre_tree(struct lzx_stream *);
342c09f92d2SPeter Avalos static int lzx_read_bitlen(struct lzx_stream *, struct huffman *, int);
343c09f92d2SPeter Avalos static int lzx_huffman_init(struct huffman *, size_t, int);
344c09f92d2SPeter Avalos static void lzx_huffman_free(struct huffman *);
345c09f92d2SPeter Avalos static int lzx_make_huffman_table(struct huffman *);
34659bf7050SPeter Avalos static inline int lzx_decode_huffman(struct huffman *, unsigned);
347c09f92d2SPeter Avalos
348c09f92d2SPeter Avalos
349c09f92d2SPeter Avalos int
archive_read_support_format_cab(struct archive * _a)350c09f92d2SPeter Avalos archive_read_support_format_cab(struct archive *_a)
351c09f92d2SPeter Avalos {
352c09f92d2SPeter Avalos struct archive_read *a = (struct archive_read *)_a;
353c09f92d2SPeter Avalos struct cab *cab;
354c09f92d2SPeter Avalos int r;
355c09f92d2SPeter Avalos
356c09f92d2SPeter Avalos archive_check_magic(_a, ARCHIVE_READ_MAGIC,
357c09f92d2SPeter Avalos ARCHIVE_STATE_NEW, "archive_read_support_format_cab");
358c09f92d2SPeter Avalos
359c09f92d2SPeter Avalos cab = (struct cab *)calloc(1, sizeof(*cab));
360c09f92d2SPeter Avalos if (cab == NULL) {
361c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
362c09f92d2SPeter Avalos "Can't allocate CAB data");
363c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
364c09f92d2SPeter Avalos }
365c09f92d2SPeter Avalos archive_string_init(&cab->ws);
366c09f92d2SPeter Avalos archive_wstring_ensure(&cab->ws, 256);
367c09f92d2SPeter Avalos
368c09f92d2SPeter Avalos r = __archive_read_register_format(a,
369c09f92d2SPeter Avalos cab,
370c09f92d2SPeter Avalos "cab",
371c09f92d2SPeter Avalos archive_read_format_cab_bid,
372c09f92d2SPeter Avalos archive_read_format_cab_options,
373c09f92d2SPeter Avalos archive_read_format_cab_read_header,
374c09f92d2SPeter Avalos archive_read_format_cab_read_data,
375c09f92d2SPeter Avalos archive_read_format_cab_read_data_skip,
376d4d8193eSPeter Avalos NULL,
3776b384f39SPeter Avalos archive_read_format_cab_cleanup,
3786b384f39SPeter Avalos NULL,
3796b384f39SPeter Avalos NULL);
380c09f92d2SPeter Avalos
381c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
382c09f92d2SPeter Avalos free(cab);
383c09f92d2SPeter Avalos return (ARCHIVE_OK);
384c09f92d2SPeter Avalos }
385c09f92d2SPeter Avalos
386c09f92d2SPeter Avalos static int
find_cab_magic(const char * p)387c09f92d2SPeter Avalos find_cab_magic(const char *p)
388c09f92d2SPeter Avalos {
389c09f92d2SPeter Avalos switch (p[4]) {
390c09f92d2SPeter Avalos case 0:
391c09f92d2SPeter Avalos /*
392c09f92d2SPeter Avalos * Note: Self-Extraction program has 'MSCF' string in their
393c09f92d2SPeter Avalos * program. If we were finding 'MSCF' string only, we got
394c09f92d2SPeter Avalos * wrong place for Cabinet header, thus, we have to check
395c09f92d2SPeter Avalos * following four bytes which are reserved and must be set
396c09f92d2SPeter Avalos * to zero.
397c09f92d2SPeter Avalos */
398c09f92d2SPeter Avalos if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)
399c09f92d2SPeter Avalos return 0;
400c09f92d2SPeter Avalos return 5;
401c09f92d2SPeter Avalos case 'F': return 1;
402c09f92d2SPeter Avalos case 'C': return 2;
403c09f92d2SPeter Avalos case 'S': return 3;
404c09f92d2SPeter Avalos case 'M': return 4;
405c09f92d2SPeter Avalos default: return 5;
406c09f92d2SPeter Avalos }
407c09f92d2SPeter Avalos }
408c09f92d2SPeter Avalos
409c09f92d2SPeter Avalos static int
archive_read_format_cab_bid(struct archive_read * a,int best_bid)410c09f92d2SPeter Avalos archive_read_format_cab_bid(struct archive_read *a, int best_bid)
411c09f92d2SPeter Avalos {
412c09f92d2SPeter Avalos const char *p;
413c09f92d2SPeter Avalos ssize_t bytes_avail, offset, window;
414c09f92d2SPeter Avalos
415c09f92d2SPeter Avalos /* If there's already a better bid than we can ever
416c09f92d2SPeter Avalos make, don't bother testing. */
417c09f92d2SPeter Avalos if (best_bid > 64)
418c09f92d2SPeter Avalos return (-1);
419c09f92d2SPeter Avalos
420c09f92d2SPeter Avalos if ((p = __archive_read_ahead(a, 8, NULL)) == NULL)
421c09f92d2SPeter Avalos return (-1);
422c09f92d2SPeter Avalos
423c09f92d2SPeter Avalos if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)
424c09f92d2SPeter Avalos return (64);
425c09f92d2SPeter Avalos
426c09f92d2SPeter Avalos /*
427c09f92d2SPeter Avalos * Attempt to handle self-extracting archives
428c09f92d2SPeter Avalos * by noting a PE header and searching forward
429c09f92d2SPeter Avalos * up to 128k for a 'MSCF' marker.
430c09f92d2SPeter Avalos */
431c09f92d2SPeter Avalos if (p[0] == 'M' && p[1] == 'Z') {
432c09f92d2SPeter Avalos offset = 0;
433c09f92d2SPeter Avalos window = 4096;
434c09f92d2SPeter Avalos while (offset < (1024 * 128)) {
435c09f92d2SPeter Avalos const char *h = __archive_read_ahead(a, offset + window,
436c09f92d2SPeter Avalos &bytes_avail);
437c09f92d2SPeter Avalos if (h == NULL) {
438c09f92d2SPeter Avalos /* Remaining bytes are less than window. */
439c09f92d2SPeter Avalos window >>= 1;
440c09f92d2SPeter Avalos if (window < 128)
441c09f92d2SPeter Avalos return (0);
442c09f92d2SPeter Avalos continue;
443c09f92d2SPeter Avalos }
444c09f92d2SPeter Avalos p = h + offset;
445c09f92d2SPeter Avalos while (p + 8 < h + bytes_avail) {
446c09f92d2SPeter Avalos int next;
447c09f92d2SPeter Avalos if ((next = find_cab_magic(p)) == 0)
448c09f92d2SPeter Avalos return (64);
449c09f92d2SPeter Avalos p += next;
450c09f92d2SPeter Avalos }
451c09f92d2SPeter Avalos offset = p - h;
452c09f92d2SPeter Avalos }
453c09f92d2SPeter Avalos }
454c09f92d2SPeter Avalos return (0);
455c09f92d2SPeter Avalos }
456c09f92d2SPeter Avalos
457c09f92d2SPeter Avalos static int
archive_read_format_cab_options(struct archive_read * a,const char * key,const char * val)458c09f92d2SPeter Avalos archive_read_format_cab_options(struct archive_read *a,
459c09f92d2SPeter Avalos const char *key, const char *val)
460c09f92d2SPeter Avalos {
461c09f92d2SPeter Avalos struct cab *cab;
462c09f92d2SPeter Avalos int ret = ARCHIVE_FAILED;
463c09f92d2SPeter Avalos
464c09f92d2SPeter Avalos cab = (struct cab *)(a->format->data);
465c09f92d2SPeter Avalos if (strcmp(key, "hdrcharset") == 0) {
466c09f92d2SPeter Avalos if (val == NULL || val[0] == 0)
467c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
468c09f92d2SPeter Avalos "cab: hdrcharset option needs a character-set name");
469c09f92d2SPeter Avalos else {
470c09f92d2SPeter Avalos cab->sconv = archive_string_conversion_from_charset(
471c09f92d2SPeter Avalos &a->archive, val, 0);
472c09f92d2SPeter Avalos if (cab->sconv != NULL)
473c09f92d2SPeter Avalos ret = ARCHIVE_OK;
474c09f92d2SPeter Avalos else
475c09f92d2SPeter Avalos ret = ARCHIVE_FATAL;
476c09f92d2SPeter Avalos }
477c09f92d2SPeter Avalos return (ret);
478c09f92d2SPeter Avalos }
479c09f92d2SPeter Avalos
48059bf7050SPeter Avalos /* Note: The "warn" return is just to inform the options
48159bf7050SPeter Avalos * supervisor that we didn't handle it. It will generate
48259bf7050SPeter Avalos * a suitable error if no one used this option. */
48359bf7050SPeter Avalos return (ARCHIVE_WARN);
48459bf7050SPeter Avalos }
48559bf7050SPeter Avalos
486c09f92d2SPeter Avalos static int
cab_skip_sfx(struct archive_read * a)487c09f92d2SPeter Avalos cab_skip_sfx(struct archive_read *a)
488c09f92d2SPeter Avalos {
489c09f92d2SPeter Avalos const char *p, *q;
490c09f92d2SPeter Avalos size_t skip;
491c09f92d2SPeter Avalos ssize_t bytes, window;
492c09f92d2SPeter Avalos
493c09f92d2SPeter Avalos window = 4096;
494c09f92d2SPeter Avalos for (;;) {
495c09f92d2SPeter Avalos const char *h = __archive_read_ahead(a, window, &bytes);
496c09f92d2SPeter Avalos if (h == NULL) {
497c09f92d2SPeter Avalos /* Remaining size are less than window. */
498c09f92d2SPeter Avalos window >>= 1;
499c09f92d2SPeter Avalos if (window < 128) {
500c09f92d2SPeter Avalos archive_set_error(&a->archive,
501c09f92d2SPeter Avalos ARCHIVE_ERRNO_FILE_FORMAT,
502c09f92d2SPeter Avalos "Couldn't find out CAB header");
503c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
504c09f92d2SPeter Avalos }
505c09f92d2SPeter Avalos continue;
506c09f92d2SPeter Avalos }
507c09f92d2SPeter Avalos p = h;
508c09f92d2SPeter Avalos q = p + bytes;
509c09f92d2SPeter Avalos
510c09f92d2SPeter Avalos /*
511c09f92d2SPeter Avalos * Scan ahead until we find something that looks
512c09f92d2SPeter Avalos * like the cab header.
513c09f92d2SPeter Avalos */
514c09f92d2SPeter Avalos while (p + 8 < q) {
515c09f92d2SPeter Avalos int next;
516c09f92d2SPeter Avalos if ((next = find_cab_magic(p)) == 0) {
517c09f92d2SPeter Avalos skip = p - h;
518c09f92d2SPeter Avalos __archive_read_consume(a, skip);
519c09f92d2SPeter Avalos return (ARCHIVE_OK);
520c09f92d2SPeter Avalos }
521c09f92d2SPeter Avalos p += next;
522c09f92d2SPeter Avalos }
523c09f92d2SPeter Avalos skip = p - h;
524c09f92d2SPeter Avalos __archive_read_consume(a, skip);
525c09f92d2SPeter Avalos }
526c09f92d2SPeter Avalos }
527c09f92d2SPeter Avalos
528c09f92d2SPeter Avalos static int
truncated_error(struct archive_read * a)529c09f92d2SPeter Avalos truncated_error(struct archive_read *a)
530c09f92d2SPeter Avalos {
531c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
532c09f92d2SPeter Avalos "Truncated CAB header");
533c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
534c09f92d2SPeter Avalos }
535c09f92d2SPeter Avalos
536d4d8193eSPeter Avalos static ssize_t
cab_strnlen(const unsigned char * p,size_t maxlen)537c09f92d2SPeter Avalos cab_strnlen(const unsigned char *p, size_t maxlen)
538c09f92d2SPeter Avalos {
539c09f92d2SPeter Avalos size_t i;
540c09f92d2SPeter Avalos
541c09f92d2SPeter Avalos for (i = 0; i <= maxlen; i++) {
542c09f92d2SPeter Avalos if (p[i] == 0)
543c09f92d2SPeter Avalos break;
544c09f92d2SPeter Avalos }
545c09f92d2SPeter Avalos if (i > maxlen)
546c09f92d2SPeter Avalos return (-1);/* invalid */
547d4d8193eSPeter Avalos return ((ssize_t)i);
548c09f92d2SPeter Avalos }
549c09f92d2SPeter Avalos
550c09f92d2SPeter Avalos /* Read bytes as much as remaining. */
551c09f92d2SPeter Avalos static const void *
cab_read_ahead_remaining(struct archive_read * a,size_t min,ssize_t * avail)552c09f92d2SPeter Avalos cab_read_ahead_remaining(struct archive_read *a, size_t min, ssize_t *avail)
553c09f92d2SPeter Avalos {
554c09f92d2SPeter Avalos const void *p;
555c09f92d2SPeter Avalos
556c09f92d2SPeter Avalos while (min > 0) {
557c09f92d2SPeter Avalos p = __archive_read_ahead(a, min, avail);
558c09f92d2SPeter Avalos if (p != NULL)
559c09f92d2SPeter Avalos return (p);
560c09f92d2SPeter Avalos min--;
561c09f92d2SPeter Avalos }
562c09f92d2SPeter Avalos return (NULL);
563c09f92d2SPeter Avalos }
564c09f92d2SPeter Avalos
565c09f92d2SPeter Avalos /* Convert a path separator '\' -> '/' */
566c09f92d2SPeter Avalos static int
cab_convert_path_separator_1(struct archive_string * fn,unsigned char attr)567c09f92d2SPeter Avalos cab_convert_path_separator_1(struct archive_string *fn, unsigned char attr)
568c09f92d2SPeter Avalos {
569c09f92d2SPeter Avalos size_t i;
570c09f92d2SPeter Avalos int mb;
571c09f92d2SPeter Avalos
572c09f92d2SPeter Avalos /* Easy check if we have '\' in multi-byte string. */
573c09f92d2SPeter Avalos mb = 0;
574c09f92d2SPeter Avalos for (i = 0; i < archive_strlen(fn); i++) {
575c09f92d2SPeter Avalos if (fn->s[i] == '\\') {
576c09f92d2SPeter Avalos if (mb) {
577c09f92d2SPeter Avalos /* This may be second byte of multi-byte
578c09f92d2SPeter Avalos * character. */
579c09f92d2SPeter Avalos break;
580c09f92d2SPeter Avalos }
581c09f92d2SPeter Avalos fn->s[i] = '/';
582c09f92d2SPeter Avalos mb = 0;
583c09f92d2SPeter Avalos } else if ((fn->s[i] & 0x80) && !(attr & ATTR_NAME_IS_UTF))
584c09f92d2SPeter Avalos mb = 1;
585c09f92d2SPeter Avalos else
586c09f92d2SPeter Avalos mb = 0;
587c09f92d2SPeter Avalos }
588c09f92d2SPeter Avalos if (i == archive_strlen(fn))
589c09f92d2SPeter Avalos return (0);
590c09f92d2SPeter Avalos return (-1);
591c09f92d2SPeter Avalos }
592c09f92d2SPeter Avalos
593c09f92d2SPeter Avalos /*
594c09f92d2SPeter Avalos * Replace a character '\' with '/' in wide character.
595c09f92d2SPeter Avalos */
596c09f92d2SPeter Avalos static void
cab_convert_path_separator_2(struct cab * cab,struct archive_entry * entry)597c09f92d2SPeter Avalos cab_convert_path_separator_2(struct cab *cab, struct archive_entry *entry)
598c09f92d2SPeter Avalos {
599c09f92d2SPeter Avalos const wchar_t *wp;
600c09f92d2SPeter Avalos size_t i;
601c09f92d2SPeter Avalos
602c09f92d2SPeter Avalos /* If a conversion to wide character failed, force the replacement. */
603c09f92d2SPeter Avalos if ((wp = archive_entry_pathname_w(entry)) != NULL) {
604c09f92d2SPeter Avalos archive_wstrcpy(&(cab->ws), wp);
605c09f92d2SPeter Avalos for (i = 0; i < archive_strlen(&(cab->ws)); i++) {
606c09f92d2SPeter Avalos if (cab->ws.s[i] == L'\\')
607c09f92d2SPeter Avalos cab->ws.s[i] = L'/';
608c09f92d2SPeter Avalos }
609c09f92d2SPeter Avalos archive_entry_copy_pathname_w(entry, cab->ws.s);
610c09f92d2SPeter Avalos }
611c09f92d2SPeter Avalos }
612c09f92d2SPeter Avalos
613c09f92d2SPeter Avalos /*
614c09f92d2SPeter Avalos * Read CFHEADER, CFFOLDER and CFFILE.
615c09f92d2SPeter Avalos */
616c09f92d2SPeter Avalos static int
cab_read_header(struct archive_read * a)617c09f92d2SPeter Avalos cab_read_header(struct archive_read *a)
618c09f92d2SPeter Avalos {
619c09f92d2SPeter Avalos const unsigned char *p;
620c09f92d2SPeter Avalos struct cab *cab;
621c09f92d2SPeter Avalos struct cfheader *hd;
622c09f92d2SPeter Avalos size_t bytes, used;
623d4d8193eSPeter Avalos ssize_t len;
624c09f92d2SPeter Avalos int64_t skip;
625d4d8193eSPeter Avalos int err, i;
626c09f92d2SPeter Avalos int cur_folder, prev_folder;
627c09f92d2SPeter Avalos uint32_t offset32;
628c09f92d2SPeter Avalos
629c09f92d2SPeter Avalos a->archive.archive_format = ARCHIVE_FORMAT_CAB;
630c09f92d2SPeter Avalos if (a->archive.archive_format_name == NULL)
631c09f92d2SPeter Avalos a->archive.archive_format_name = "CAB";
632c09f92d2SPeter Avalos
633c09f92d2SPeter Avalos if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)
634c09f92d2SPeter Avalos return (truncated_error(a));
635c09f92d2SPeter Avalos
636c09f92d2SPeter Avalos cab = (struct cab *)(a->format->data);
637c09f92d2SPeter Avalos if (cab->found_header == 0 &&
638c09f92d2SPeter Avalos p[0] == 'M' && p[1] == 'Z') {
639c09f92d2SPeter Avalos /* This is an executable? Must be self-extracting... */
640c09f92d2SPeter Avalos err = cab_skip_sfx(a);
641c09f92d2SPeter Avalos if (err < ARCHIVE_WARN)
642c09f92d2SPeter Avalos return (err);
643c09f92d2SPeter Avalos
644e95abc47Szrj /* Re-read header after processing the SFX. */
645e95abc47Szrj if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)
646c09f92d2SPeter Avalos return (truncated_error(a));
647c09f92d2SPeter Avalos }
648c09f92d2SPeter Avalos
649c09f92d2SPeter Avalos cab->cab_offset = 0;
650c09f92d2SPeter Avalos /*
651c09f92d2SPeter Avalos * Read CFHEADER.
652c09f92d2SPeter Avalos */
653c09f92d2SPeter Avalos hd = &cab->cfheader;
654c09f92d2SPeter Avalos if (p[CFHEADER_signature+0] != 'M' || p[CFHEADER_signature+1] != 'S' ||
655c09f92d2SPeter Avalos p[CFHEADER_signature+2] != 'C' || p[CFHEADER_signature+3] != 'F') {
656c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
657c09f92d2SPeter Avalos "Couldn't find out CAB header");
658c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
659c09f92d2SPeter Avalos }
660c09f92d2SPeter Avalos hd->total_bytes = archive_le32dec(p + CFHEADER_cbCabinet);
661c09f92d2SPeter Avalos hd->files_offset = archive_le32dec(p + CFHEADER_coffFiles);
662c09f92d2SPeter Avalos hd->minor = p[CFHEADER_versionMinor];
663c09f92d2SPeter Avalos hd->major = p[CFHEADER_versionMajor];
664c09f92d2SPeter Avalos hd->folder_count = archive_le16dec(p + CFHEADER_cFolders);
665c09f92d2SPeter Avalos if (hd->folder_count == 0)
666c09f92d2SPeter Avalos goto invalid;
667c09f92d2SPeter Avalos hd->file_count = archive_le16dec(p + CFHEADER_cFiles);
668c09f92d2SPeter Avalos if (hd->file_count == 0)
669c09f92d2SPeter Avalos goto invalid;
670c09f92d2SPeter Avalos hd->flags = archive_le16dec(p + CFHEADER_flags);
671c09f92d2SPeter Avalos hd->setid = archive_le16dec(p + CFHEADER_setID);
672c09f92d2SPeter Avalos hd->cabinet = archive_le16dec(p + CFHEADER_iCabinet);
673c09f92d2SPeter Avalos used = CFHEADER_iCabinet + 2;
674c09f92d2SPeter Avalos if (hd->flags & RESERVE_PRESENT) {
675c09f92d2SPeter Avalos uint16_t cfheader;
676c09f92d2SPeter Avalos cfheader = archive_le16dec(p + CFHEADER_cbCFHeader);
677c09f92d2SPeter Avalos if (cfheader > 60000U)
678c09f92d2SPeter Avalos goto invalid;
679c09f92d2SPeter Avalos hd->cffolder = p[CFHEADER_cbCFFolder];
680c09f92d2SPeter Avalos hd->cfdata = p[CFHEADER_cbCFData];
681c09f92d2SPeter Avalos used += 4;/* cbCFHeader, cbCFFolder and cbCFData */
682c09f92d2SPeter Avalos used += cfheader;/* abReserve */
683c09f92d2SPeter Avalos } else
684c09f92d2SPeter Avalos hd->cffolder = 0;/* Avoid compiling warning. */
685c09f92d2SPeter Avalos if (hd->flags & PREV_CABINET) {
686c09f92d2SPeter Avalos /* How many bytes are used for szCabinetPrev. */
687c09f92d2SPeter Avalos if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
688c09f92d2SPeter Avalos return (truncated_error(a));
689c09f92d2SPeter Avalos if ((len = cab_strnlen(p + used, 255)) <= 0)
690c09f92d2SPeter Avalos goto invalid;
691c09f92d2SPeter Avalos used += len + 1;
692c09f92d2SPeter Avalos /* How many bytes are used for szDiskPrev. */
693c09f92d2SPeter Avalos if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
694c09f92d2SPeter Avalos return (truncated_error(a));
695c09f92d2SPeter Avalos if ((len = cab_strnlen(p + used, 255)) <= 0)
696c09f92d2SPeter Avalos goto invalid;
697c09f92d2SPeter Avalos used += len + 1;
698c09f92d2SPeter Avalos }
699c09f92d2SPeter Avalos if (hd->flags & NEXT_CABINET) {
700c09f92d2SPeter Avalos /* How many bytes are used for szCabinetNext. */
701c09f92d2SPeter Avalos if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
702c09f92d2SPeter Avalos return (truncated_error(a));
703c09f92d2SPeter Avalos if ((len = cab_strnlen(p + used, 255)) <= 0)
704c09f92d2SPeter Avalos goto invalid;
705c09f92d2SPeter Avalos used += len + 1;
706c09f92d2SPeter Avalos /* How many bytes are used for szDiskNext. */
707c09f92d2SPeter Avalos if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
708c09f92d2SPeter Avalos return (truncated_error(a));
709c09f92d2SPeter Avalos if ((len = cab_strnlen(p + used, 255)) <= 0)
710c09f92d2SPeter Avalos goto invalid;
711c09f92d2SPeter Avalos used += len + 1;
712c09f92d2SPeter Avalos }
713c09f92d2SPeter Avalos __archive_read_consume(a, used);
714c09f92d2SPeter Avalos cab->cab_offset += used;
715c09f92d2SPeter Avalos used = 0;
716c09f92d2SPeter Avalos
717c09f92d2SPeter Avalos /*
718c09f92d2SPeter Avalos * Read CFFOLDER.
719c09f92d2SPeter Avalos */
720c09f92d2SPeter Avalos hd->folder_array = (struct cffolder *)calloc(
721c09f92d2SPeter Avalos hd->folder_count, sizeof(struct cffolder));
722c09f92d2SPeter Avalos if (hd->folder_array == NULL)
723c09f92d2SPeter Avalos goto nomem;
724c09f92d2SPeter Avalos
725c09f92d2SPeter Avalos bytes = 8;
726c09f92d2SPeter Avalos if (hd->flags & RESERVE_PRESENT)
727c09f92d2SPeter Avalos bytes += hd->cffolder;
728c09f92d2SPeter Avalos bytes *= hd->folder_count;
729c09f92d2SPeter Avalos if ((p = __archive_read_ahead(a, bytes, NULL)) == NULL)
730c09f92d2SPeter Avalos return (truncated_error(a));
731c09f92d2SPeter Avalos offset32 = 0;
732c09f92d2SPeter Avalos for (i = 0; i < hd->folder_count; i++) {
733c09f92d2SPeter Avalos struct cffolder *folder = &(hd->folder_array[i]);
734c09f92d2SPeter Avalos folder->cfdata_offset_in_cab =
735c09f92d2SPeter Avalos archive_le32dec(p + CFFOLDER_coffCabStart);
736c09f92d2SPeter Avalos folder->cfdata_count = archive_le16dec(p+CFFOLDER_cCFData);
737c09f92d2SPeter Avalos folder->comptype =
738c09f92d2SPeter Avalos archive_le16dec(p+CFFOLDER_typeCompress) & 0x0F;
739c09f92d2SPeter Avalos folder->compdata =
740c09f92d2SPeter Avalos archive_le16dec(p+CFFOLDER_typeCompress) >> 8;
741c09f92d2SPeter Avalos /* Get a compression name. */
742c09f92d2SPeter Avalos if (folder->comptype <
743c09f92d2SPeter Avalos sizeof(compression_name) / sizeof(compression_name[0]))
744c09f92d2SPeter Avalos folder->compname = compression_name[folder->comptype];
745c09f92d2SPeter Avalos else
746c09f92d2SPeter Avalos folder->compname = "UNKNOWN";
747c09f92d2SPeter Avalos p += 8;
748c09f92d2SPeter Avalos used += 8;
749c09f92d2SPeter Avalos if (hd->flags & RESERVE_PRESENT) {
750c09f92d2SPeter Avalos p += hd->cffolder;/* abReserve */
751c09f92d2SPeter Avalos used += hd->cffolder;
752c09f92d2SPeter Avalos }
753c09f92d2SPeter Avalos /*
754c09f92d2SPeter Avalos * Sanity check if each data is acceptable.
755c09f92d2SPeter Avalos */
756c09f92d2SPeter Avalos if (offset32 >= folder->cfdata_offset_in_cab)
757c09f92d2SPeter Avalos goto invalid;
758c09f92d2SPeter Avalos offset32 = folder->cfdata_offset_in_cab;
759c09f92d2SPeter Avalos
760c09f92d2SPeter Avalos /* Set a request to initialize zlib for the CFDATA of
761c09f92d2SPeter Avalos * this folder. */
762c09f92d2SPeter Avalos folder->decompress_init = 0;
763c09f92d2SPeter Avalos }
764c09f92d2SPeter Avalos __archive_read_consume(a, used);
765c09f92d2SPeter Avalos cab->cab_offset += used;
766c09f92d2SPeter Avalos
767c09f92d2SPeter Avalos /*
768c09f92d2SPeter Avalos * Read CFFILE.
769c09f92d2SPeter Avalos */
770c09f92d2SPeter Avalos /* Seek read pointer to the offset of CFFILE if needed. */
771c09f92d2SPeter Avalos skip = (int64_t)hd->files_offset - cab->cab_offset;
772c09f92d2SPeter Avalos if (skip < 0) {
773c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
774c09f92d2SPeter Avalos "Invalid offset of CFFILE %jd < %jd",
775c09f92d2SPeter Avalos (intmax_t)hd->files_offset, (intmax_t)cab->cab_offset);
776c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
777c09f92d2SPeter Avalos }
778c09f92d2SPeter Avalos if (skip) {
779c09f92d2SPeter Avalos __archive_read_consume(a, skip);
780c09f92d2SPeter Avalos cab->cab_offset += skip;
781c09f92d2SPeter Avalos }
782c09f92d2SPeter Avalos /* Allocate memory for CFDATA */
783c09f92d2SPeter Avalos hd->file_array = (struct cffile *)calloc(
784c09f92d2SPeter Avalos hd->file_count, sizeof(struct cffile));
785c09f92d2SPeter Avalos if (hd->file_array == NULL)
786c09f92d2SPeter Avalos goto nomem;
787c09f92d2SPeter Avalos
788c09f92d2SPeter Avalos prev_folder = -1;
789c09f92d2SPeter Avalos for (i = 0; i < hd->file_count; i++) {
790c09f92d2SPeter Avalos struct cffile *file = &(hd->file_array[i]);
791c09f92d2SPeter Avalos ssize_t avail;
792c09f92d2SPeter Avalos
793c09f92d2SPeter Avalos if ((p = __archive_read_ahead(a, 16, NULL)) == NULL)
794c09f92d2SPeter Avalos return (truncated_error(a));
795c09f92d2SPeter Avalos file->uncompressed_size = archive_le32dec(p + CFFILE_cbFile);
796c09f92d2SPeter Avalos file->offset = archive_le32dec(p + CFFILE_uoffFolderStart);
797c09f92d2SPeter Avalos file->folder = archive_le16dec(p + CFFILE_iFolder);
798c09f92d2SPeter Avalos file->mtime = cab_dos_time(p + CFFILE_date_time);
79959bf7050SPeter Avalos file->attr = (uint8_t)archive_le16dec(p + CFFILE_attribs);
800c09f92d2SPeter Avalos __archive_read_consume(a, 16);
801c09f92d2SPeter Avalos
802c09f92d2SPeter Avalos cab->cab_offset += 16;
803c09f92d2SPeter Avalos if ((p = cab_read_ahead_remaining(a, 256, &avail)) == NULL)
804c09f92d2SPeter Avalos return (truncated_error(a));
805c09f92d2SPeter Avalos if ((len = cab_strnlen(p, avail-1)) <= 0)
806c09f92d2SPeter Avalos goto invalid;
807c09f92d2SPeter Avalos
808c09f92d2SPeter Avalos /* Copy a pathname. */
809c09f92d2SPeter Avalos archive_string_init(&(file->pathname));
810c09f92d2SPeter Avalos archive_strncpy(&(file->pathname), p, len);
811c09f92d2SPeter Avalos __archive_read_consume(a, len + 1);
812c09f92d2SPeter Avalos cab->cab_offset += len + 1;
813c09f92d2SPeter Avalos
814c09f92d2SPeter Avalos /*
815c09f92d2SPeter Avalos * Sanity check if each data is acceptable.
816c09f92d2SPeter Avalos */
817c09f92d2SPeter Avalos if (file->uncompressed_size > 0x7FFF8000)
818c09f92d2SPeter Avalos goto invalid;/* Too large */
819c09f92d2SPeter Avalos if ((int64_t)file->offset + (int64_t)file->uncompressed_size
820c09f92d2SPeter Avalos > ARCHIVE_LITERAL_LL(0x7FFF8000))
821c09f92d2SPeter Avalos goto invalid;/* Too large */
822c09f92d2SPeter Avalos switch (file->folder) {
823c09f92d2SPeter Avalos case iFoldCONTINUED_TO_NEXT:
824c09f92d2SPeter Avalos /* This must be last file in a folder. */
825c09f92d2SPeter Avalos if (i != hd->file_count -1)
826c09f92d2SPeter Avalos goto invalid;
827c09f92d2SPeter Avalos cur_folder = hd->folder_count -1;
828c09f92d2SPeter Avalos break;
829c09f92d2SPeter Avalos case iFoldCONTINUED_PREV_AND_NEXT:
830c09f92d2SPeter Avalos /* This must be only one file in a folder. */
831c09f92d2SPeter Avalos if (hd->file_count != 1)
832c09f92d2SPeter Avalos goto invalid;
833c09f92d2SPeter Avalos /* FALL THROUGH */
834c09f92d2SPeter Avalos case iFoldCONTINUED_FROM_PREV:
835c09f92d2SPeter Avalos /* This must be first file in a folder. */
836c09f92d2SPeter Avalos if (i != 0)
837c09f92d2SPeter Avalos goto invalid;
838c09f92d2SPeter Avalos prev_folder = cur_folder = 0;
839c09f92d2SPeter Avalos offset32 = file->offset;
840c09f92d2SPeter Avalos break;
841c09f92d2SPeter Avalos default:
842c09f92d2SPeter Avalos if (file->folder >= hd->folder_count)
843c09f92d2SPeter Avalos goto invalid;
844c09f92d2SPeter Avalos cur_folder = file->folder;
845c09f92d2SPeter Avalos break;
846c09f92d2SPeter Avalos }
847c09f92d2SPeter Avalos /* Dot not back track. */
848c09f92d2SPeter Avalos if (cur_folder < prev_folder)
849c09f92d2SPeter Avalos goto invalid;
850c09f92d2SPeter Avalos if (cur_folder != prev_folder)
851c09f92d2SPeter Avalos offset32 = 0;
852c09f92d2SPeter Avalos prev_folder = cur_folder;
853c09f92d2SPeter Avalos
854c09f92d2SPeter Avalos /* Make sure there are not any blanks from last file
855c09f92d2SPeter Avalos * contents. */
856c09f92d2SPeter Avalos if (offset32 != file->offset)
857c09f92d2SPeter Avalos goto invalid;
858c09f92d2SPeter Avalos offset32 += file->uncompressed_size;
859c09f92d2SPeter Avalos
860c09f92d2SPeter Avalos /* CFDATA is available for file contents. */
861c09f92d2SPeter Avalos if (file->uncompressed_size > 0 &&
862c09f92d2SPeter Avalos hd->folder_array[cur_folder].cfdata_count == 0)
863c09f92d2SPeter Avalos goto invalid;
864c09f92d2SPeter Avalos }
865c09f92d2SPeter Avalos
866c09f92d2SPeter Avalos if (hd->cabinet != 0 || hd->flags & (PREV_CABINET | NEXT_CABINET)) {
867c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
868c09f92d2SPeter Avalos "Multivolume cabinet file is unsupported");
869c09f92d2SPeter Avalos return (ARCHIVE_WARN);
870c09f92d2SPeter Avalos }
871c09f92d2SPeter Avalos return (ARCHIVE_OK);
872c09f92d2SPeter Avalos invalid:
873c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
874c09f92d2SPeter Avalos "Invalid CAB header");
875c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
876c09f92d2SPeter Avalos nomem:
877c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
878c09f92d2SPeter Avalos "Can't allocate memory for CAB data");
879c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
880c09f92d2SPeter Avalos }
881c09f92d2SPeter Avalos
882c09f92d2SPeter Avalos static int
archive_read_format_cab_read_header(struct archive_read * a,struct archive_entry * entry)883c09f92d2SPeter Avalos archive_read_format_cab_read_header(struct archive_read *a,
884c09f92d2SPeter Avalos struct archive_entry *entry)
885c09f92d2SPeter Avalos {
886c09f92d2SPeter Avalos struct cab *cab;
887c09f92d2SPeter Avalos struct cfheader *hd;
888c09f92d2SPeter Avalos struct cffolder *prev_folder;
889c09f92d2SPeter Avalos struct cffile *file;
890c09f92d2SPeter Avalos struct archive_string_conv *sconv;
891c09f92d2SPeter Avalos int err = ARCHIVE_OK, r;
892c09f92d2SPeter Avalos
893c09f92d2SPeter Avalos cab = (struct cab *)(a->format->data);
894c09f92d2SPeter Avalos if (cab->found_header == 0) {
895c09f92d2SPeter Avalos err = cab_read_header(a);
896c09f92d2SPeter Avalos if (err < ARCHIVE_WARN)
897c09f92d2SPeter Avalos return (err);
898c09f92d2SPeter Avalos /* We've found the header. */
899c09f92d2SPeter Avalos cab->found_header = 1;
900c09f92d2SPeter Avalos }
901c09f92d2SPeter Avalos hd = &cab->cfheader;
902c09f92d2SPeter Avalos
903c09f92d2SPeter Avalos if (hd->file_index >= hd->file_count) {
904c09f92d2SPeter Avalos cab->end_of_archive = 1;
905c09f92d2SPeter Avalos return (ARCHIVE_EOF);
906c09f92d2SPeter Avalos }
907c09f92d2SPeter Avalos file = &hd->file_array[hd->file_index++];
908c09f92d2SPeter Avalos
909c09f92d2SPeter Avalos cab->end_of_entry = 0;
910c09f92d2SPeter Avalos cab->end_of_entry_cleanup = 0;
911c09f92d2SPeter Avalos cab->entry_compressed_bytes_read = 0;
912c09f92d2SPeter Avalos cab->entry_uncompressed_bytes_read = 0;
913c09f92d2SPeter Avalos cab->entry_unconsumed = 0;
914c09f92d2SPeter Avalos cab->entry_cffile = file;
915c09f92d2SPeter Avalos
916c09f92d2SPeter Avalos /*
917c09f92d2SPeter Avalos * Choose a proper folder.
918c09f92d2SPeter Avalos */
919c09f92d2SPeter Avalos prev_folder = cab->entry_cffolder;
920c09f92d2SPeter Avalos switch (file->folder) {
921c09f92d2SPeter Avalos case iFoldCONTINUED_FROM_PREV:
922c09f92d2SPeter Avalos case iFoldCONTINUED_PREV_AND_NEXT:
923c09f92d2SPeter Avalos cab->entry_cffolder = &hd->folder_array[0];
924c09f92d2SPeter Avalos break;
925c09f92d2SPeter Avalos case iFoldCONTINUED_TO_NEXT:
926c09f92d2SPeter Avalos cab->entry_cffolder = &hd->folder_array[hd->folder_count-1];
927c09f92d2SPeter Avalos break;
928c09f92d2SPeter Avalos default:
929c09f92d2SPeter Avalos cab->entry_cffolder = &hd->folder_array[file->folder];
930c09f92d2SPeter Avalos break;
931c09f92d2SPeter Avalos }
932c09f92d2SPeter Avalos /* If a cffolder of this file is changed, reset a cfdata to read
933c09f92d2SPeter Avalos * file contents from next cfdata. */
934c09f92d2SPeter Avalos if (prev_folder != cab->entry_cffolder)
935c09f92d2SPeter Avalos cab->entry_cfdata = NULL;
936c09f92d2SPeter Avalos
937c09f92d2SPeter Avalos /* If a pathname is UTF-8, prepare a string conversion object
938c09f92d2SPeter Avalos * for UTF-8 and use it. */
939c09f92d2SPeter Avalos if (file->attr & ATTR_NAME_IS_UTF) {
940c09f92d2SPeter Avalos if (cab->sconv_utf8 == NULL) {
941c09f92d2SPeter Avalos cab->sconv_utf8 =
942c09f92d2SPeter Avalos archive_string_conversion_from_charset(
943c09f92d2SPeter Avalos &(a->archive), "UTF-8", 1);
944c09f92d2SPeter Avalos if (cab->sconv_utf8 == NULL)
945c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
946c09f92d2SPeter Avalos }
947c09f92d2SPeter Avalos sconv = cab->sconv_utf8;
948c09f92d2SPeter Avalos } else if (cab->sconv != NULL) {
949c09f92d2SPeter Avalos /* Choose the conversion specified by the option. */
950c09f92d2SPeter Avalos sconv = cab->sconv;
951c09f92d2SPeter Avalos } else {
952c09f92d2SPeter Avalos /* Choose the default conversion. */
953c09f92d2SPeter Avalos if (!cab->init_default_conversion) {
954c09f92d2SPeter Avalos cab->sconv_default =
955c09f92d2SPeter Avalos archive_string_default_conversion_for_read(
956c09f92d2SPeter Avalos &(a->archive));
957c09f92d2SPeter Avalos cab->init_default_conversion = 1;
958c09f92d2SPeter Avalos }
959c09f92d2SPeter Avalos sconv = cab->sconv_default;
960c09f92d2SPeter Avalos }
961c09f92d2SPeter Avalos
962c09f92d2SPeter Avalos /*
963c09f92d2SPeter Avalos * Set a default value and common data
964c09f92d2SPeter Avalos */
965c09f92d2SPeter Avalos r = cab_convert_path_separator_1(&(file->pathname), file->attr);
966c09f92d2SPeter Avalos if (archive_entry_copy_pathname_l(entry, file->pathname.s,
967c09f92d2SPeter Avalos archive_strlen(&(file->pathname)), sconv) != 0) {
968c09f92d2SPeter Avalos if (errno == ENOMEM) {
969c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
970c09f92d2SPeter Avalos "Can't allocate memory for Pathname");
971c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
972c09f92d2SPeter Avalos }
973c09f92d2SPeter Avalos archive_set_error(&a->archive,
974c09f92d2SPeter Avalos ARCHIVE_ERRNO_FILE_FORMAT,
975c09f92d2SPeter Avalos "Pathname cannot be converted "
976c09f92d2SPeter Avalos "from %s to current locale.",
977c09f92d2SPeter Avalos archive_string_conversion_charset_name(sconv));
978c09f92d2SPeter Avalos err = ARCHIVE_WARN;
979c09f92d2SPeter Avalos }
980c09f92d2SPeter Avalos if (r < 0) {
981c09f92d2SPeter Avalos /* Convert a path separator '\' -> '/' */
982c09f92d2SPeter Avalos cab_convert_path_separator_2(cab, entry);
983c09f92d2SPeter Avalos }
984c09f92d2SPeter Avalos
985c09f92d2SPeter Avalos archive_entry_set_size(entry, file->uncompressed_size);
986c09f92d2SPeter Avalos if (file->attr & ATTR_RDONLY)
987c09f92d2SPeter Avalos archive_entry_set_mode(entry, AE_IFREG | 0555);
988c09f92d2SPeter Avalos else
98959bf7050SPeter Avalos archive_entry_set_mode(entry, AE_IFREG | 0666);
990c09f92d2SPeter Avalos archive_entry_set_mtime(entry, file->mtime, 0);
991c09f92d2SPeter Avalos
992c09f92d2SPeter Avalos cab->entry_bytes_remaining = file->uncompressed_size;
993c09f92d2SPeter Avalos cab->entry_offset = 0;
994c09f92d2SPeter Avalos /* We don't need compress data. */
995c09f92d2SPeter Avalos if (file->uncompressed_size == 0)
996c09f92d2SPeter Avalos cab->end_of_entry_cleanup = cab->end_of_entry = 1;
997c09f92d2SPeter Avalos
998c09f92d2SPeter Avalos /* Set up a more descriptive format name. */
999c09f92d2SPeter Avalos sprintf(cab->format_name, "CAB %d.%d (%s)",
1000c09f92d2SPeter Avalos hd->major, hd->minor, cab->entry_cffolder->compname);
1001c09f92d2SPeter Avalos a->archive.archive_format_name = cab->format_name;
1002c09f92d2SPeter Avalos
1003c09f92d2SPeter Avalos return (err);
1004c09f92d2SPeter Avalos }
1005c09f92d2SPeter Avalos
1006c09f92d2SPeter Avalos static int
archive_read_format_cab_read_data(struct archive_read * a,const void ** buff,size_t * size,int64_t * offset)1007c09f92d2SPeter Avalos archive_read_format_cab_read_data(struct archive_read *a,
1008c09f92d2SPeter Avalos const void **buff, size_t *size, int64_t *offset)
1009c09f92d2SPeter Avalos {
1010c09f92d2SPeter Avalos struct cab *cab = (struct cab *)(a->format->data);
1011c09f92d2SPeter Avalos int r;
1012c09f92d2SPeter Avalos
1013c09f92d2SPeter Avalos switch (cab->entry_cffile->folder) {
1014c09f92d2SPeter Avalos case iFoldCONTINUED_FROM_PREV:
1015c09f92d2SPeter Avalos case iFoldCONTINUED_TO_NEXT:
1016c09f92d2SPeter Avalos case iFoldCONTINUED_PREV_AND_NEXT:
1017c09f92d2SPeter Avalos *buff = NULL;
1018c09f92d2SPeter Avalos *size = 0;
1019c09f92d2SPeter Avalos *offset = 0;
1020c09f92d2SPeter Avalos archive_clear_error(&a->archive);
1021c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
1022c09f92d2SPeter Avalos "Cannot restore this file split in multivolume.");
1023c09f92d2SPeter Avalos return (ARCHIVE_FAILED);
1024c09f92d2SPeter Avalos default:
1025c09f92d2SPeter Avalos break;
1026c09f92d2SPeter Avalos }
102759bf7050SPeter Avalos if (cab->read_data_invoked == 0) {
102859bf7050SPeter Avalos if (cab->bytes_skipped) {
102959bf7050SPeter Avalos if (cab->entry_cfdata == NULL) {
103059bf7050SPeter Avalos r = cab_next_cfdata(a);
103159bf7050SPeter Avalos if (r < 0)
103259bf7050SPeter Avalos return (r);
103359bf7050SPeter Avalos }
103459bf7050SPeter Avalos if (cab_consume_cfdata(a, cab->bytes_skipped) < 0)
103559bf7050SPeter Avalos return (ARCHIVE_FATAL);
103659bf7050SPeter Avalos cab->bytes_skipped = 0;
103759bf7050SPeter Avalos }
103859bf7050SPeter Avalos cab->read_data_invoked = 1;
103959bf7050SPeter Avalos }
1040c09f92d2SPeter Avalos if (cab->entry_unconsumed) {
1041c09f92d2SPeter Avalos /* Consume as much as the compressor actually used. */
104259bf7050SPeter Avalos r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);
1043c09f92d2SPeter Avalos cab->entry_unconsumed = 0;
1044c09f92d2SPeter Avalos if (r < 0)
1045c09f92d2SPeter Avalos return (r);
1046c09f92d2SPeter Avalos }
1047c09f92d2SPeter Avalos if (cab->end_of_archive || cab->end_of_entry) {
1048c09f92d2SPeter Avalos if (!cab->end_of_entry_cleanup) {
1049c09f92d2SPeter Avalos /* End-of-entry cleanup done. */
1050c09f92d2SPeter Avalos cab->end_of_entry_cleanup = 1;
1051c09f92d2SPeter Avalos }
1052c09f92d2SPeter Avalos *offset = cab->entry_offset;
1053c09f92d2SPeter Avalos *size = 0;
1054c09f92d2SPeter Avalos *buff = NULL;
1055c09f92d2SPeter Avalos return (ARCHIVE_EOF);
1056c09f92d2SPeter Avalos }
1057c09f92d2SPeter Avalos
1058c09f92d2SPeter Avalos return (cab_read_data(a, buff, size, offset));
1059c09f92d2SPeter Avalos }
1060c09f92d2SPeter Avalos
1061c09f92d2SPeter Avalos static uint32_t
cab_checksum_cfdata_4(const void * p,size_t bytes,uint32_t seed)1062c09f92d2SPeter Avalos cab_checksum_cfdata_4(const void *p, size_t bytes, uint32_t seed)
1063c09f92d2SPeter Avalos {
1064c09f92d2SPeter Avalos const unsigned char *b;
1065d4d8193eSPeter Avalos unsigned u32num;
1066c09f92d2SPeter Avalos uint32_t sum;
1067c09f92d2SPeter Avalos
1068d4d8193eSPeter Avalos u32num = (unsigned)bytes / 4;
1069c09f92d2SPeter Avalos sum = seed;
1070c09f92d2SPeter Avalos b = p;
1071d4d8193eSPeter Avalos for (;u32num > 0; --u32num) {
1072c09f92d2SPeter Avalos sum ^= archive_le32dec(b);
1073c09f92d2SPeter Avalos b += 4;
1074c09f92d2SPeter Avalos }
1075c09f92d2SPeter Avalos return (sum);
1076c09f92d2SPeter Avalos }
1077c09f92d2SPeter Avalos
1078c09f92d2SPeter Avalos static uint32_t
cab_checksum_cfdata(const void * p,size_t bytes,uint32_t seed)1079c09f92d2SPeter Avalos cab_checksum_cfdata(const void *p, size_t bytes, uint32_t seed)
1080c09f92d2SPeter Avalos {
1081c09f92d2SPeter Avalos const unsigned char *b;
1082c09f92d2SPeter Avalos uint32_t sum;
1083c09f92d2SPeter Avalos uint32_t t;
1084c09f92d2SPeter Avalos
1085c09f92d2SPeter Avalos sum = cab_checksum_cfdata_4(p, bytes, seed);
1086c09f92d2SPeter Avalos b = p;
1087c09f92d2SPeter Avalos b += bytes & ~3;
1088c09f92d2SPeter Avalos t = 0;
1089c09f92d2SPeter Avalos switch (bytes & 3) {
1090c09f92d2SPeter Avalos case 3:
1091c09f92d2SPeter Avalos t |= ((uint32_t)(*b++)) << 16;
1092c09f92d2SPeter Avalos /* FALL THROUGH */
1093c09f92d2SPeter Avalos case 2:
1094c09f92d2SPeter Avalos t |= ((uint32_t)(*b++)) << 8;
1095c09f92d2SPeter Avalos /* FALL THROUGH */
1096c09f92d2SPeter Avalos case 1:
1097c09f92d2SPeter Avalos t |= *b;
1098c09f92d2SPeter Avalos /* FALL THROUGH */
1099c09f92d2SPeter Avalos default:
1100c09f92d2SPeter Avalos break;
1101c09f92d2SPeter Avalos }
1102c09f92d2SPeter Avalos sum ^= t;
1103c09f92d2SPeter Avalos
1104c09f92d2SPeter Avalos return (sum);
1105c09f92d2SPeter Avalos }
1106c09f92d2SPeter Avalos
1107c09f92d2SPeter Avalos static void
cab_checksum_update(struct archive_read * a,size_t bytes)1108c09f92d2SPeter Avalos cab_checksum_update(struct archive_read *a, size_t bytes)
1109c09f92d2SPeter Avalos {
1110c09f92d2SPeter Avalos struct cab *cab = (struct cab *)(a->format->data);
1111c09f92d2SPeter Avalos struct cfdata *cfdata = cab->entry_cfdata;
1112c09f92d2SPeter Avalos const unsigned char *p;
1113c09f92d2SPeter Avalos size_t sumbytes;
1114c09f92d2SPeter Avalos
1115c09f92d2SPeter Avalos if (cfdata->sum == 0 || cfdata->sum_ptr == NULL)
1116c09f92d2SPeter Avalos return;
1117c09f92d2SPeter Avalos /*
1118c09f92d2SPeter Avalos * Calculate the sum of this CFDATA.
1119c09f92d2SPeter Avalos * Make sure CFDATA must be calculated in four bytes.
1120c09f92d2SPeter Avalos */
1121c09f92d2SPeter Avalos p = cfdata->sum_ptr;
1122c09f92d2SPeter Avalos sumbytes = bytes;
1123c09f92d2SPeter Avalos if (cfdata->sum_extra_avail) {
1124c09f92d2SPeter Avalos while (cfdata->sum_extra_avail < 4 && sumbytes > 0) {
1125c09f92d2SPeter Avalos cfdata->sum_extra[
1126c09f92d2SPeter Avalos cfdata->sum_extra_avail++] = *p++;
1127c09f92d2SPeter Avalos sumbytes--;
1128c09f92d2SPeter Avalos }
1129c09f92d2SPeter Avalos if (cfdata->sum_extra_avail == 4) {
1130c09f92d2SPeter Avalos cfdata->sum_calculated = cab_checksum_cfdata_4(
1131c09f92d2SPeter Avalos cfdata->sum_extra, 4, cfdata->sum_calculated);
1132c09f92d2SPeter Avalos cfdata->sum_extra_avail = 0;
1133c09f92d2SPeter Avalos }
1134c09f92d2SPeter Avalos }
1135c09f92d2SPeter Avalos if (sumbytes) {
1136c09f92d2SPeter Avalos int odd = sumbytes & 3;
1137c09f92d2SPeter Avalos if (sumbytes - odd > 0)
1138c09f92d2SPeter Avalos cfdata->sum_calculated = cab_checksum_cfdata_4(
1139c09f92d2SPeter Avalos p, sumbytes - odd, cfdata->sum_calculated);
1140c09f92d2SPeter Avalos if (odd)
1141c09f92d2SPeter Avalos memcpy(cfdata->sum_extra, p + sumbytes - odd, odd);
1142c09f92d2SPeter Avalos cfdata->sum_extra_avail = odd;
1143c09f92d2SPeter Avalos }
1144c09f92d2SPeter Avalos cfdata->sum_ptr = NULL;
1145c09f92d2SPeter Avalos }
1146c09f92d2SPeter Avalos
1147c09f92d2SPeter Avalos static int
cab_checksum_finish(struct archive_read * a)1148c09f92d2SPeter Avalos cab_checksum_finish(struct archive_read *a)
1149c09f92d2SPeter Avalos {
1150c09f92d2SPeter Avalos struct cab *cab = (struct cab *)(a->format->data);
1151c09f92d2SPeter Avalos struct cfdata *cfdata = cab->entry_cfdata;
1152c09f92d2SPeter Avalos int l;
1153c09f92d2SPeter Avalos
1154c09f92d2SPeter Avalos /* Do not need to compute a sum. */
1155c09f92d2SPeter Avalos if (cfdata->sum == 0)
1156c09f92d2SPeter Avalos return (ARCHIVE_OK);
1157c09f92d2SPeter Avalos
1158c09f92d2SPeter Avalos /*
1159c09f92d2SPeter Avalos * Calculate the sum of remaining CFDATA.
1160c09f92d2SPeter Avalos */
1161c09f92d2SPeter Avalos if (cfdata->sum_extra_avail) {
1162c09f92d2SPeter Avalos cfdata->sum_calculated =
1163c09f92d2SPeter Avalos cab_checksum_cfdata(cfdata->sum_extra,
1164c09f92d2SPeter Avalos cfdata->sum_extra_avail, cfdata->sum_calculated);
1165c09f92d2SPeter Avalos cfdata->sum_extra_avail = 0;
1166c09f92d2SPeter Avalos }
1167c09f92d2SPeter Avalos
1168c09f92d2SPeter Avalos l = 4;
1169c09f92d2SPeter Avalos if (cab->cfheader.flags & RESERVE_PRESENT)
1170c09f92d2SPeter Avalos l += cab->cfheader.cfdata;
1171c09f92d2SPeter Avalos cfdata->sum_calculated = cab_checksum_cfdata(
1172c09f92d2SPeter Avalos cfdata->memimage + CFDATA_cbData, l, cfdata->sum_calculated);
1173c09f92d2SPeter Avalos if (cfdata->sum_calculated != cfdata->sum) {
1174c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
1175*50f8aa9cSAntonio Huete Jimenez "Checksum error CFDATA[%d] %" PRIx32 ":%" PRIx32 " in %d bytes",
1176c09f92d2SPeter Avalos cab->entry_cffolder->cfdata_index -1,
1177c09f92d2SPeter Avalos cfdata->sum, cfdata->sum_calculated,
1178c09f92d2SPeter Avalos cfdata->compressed_size);
1179c09f92d2SPeter Avalos return (ARCHIVE_FAILED);
1180c09f92d2SPeter Avalos }
1181c09f92d2SPeter Avalos return (ARCHIVE_OK);
1182c09f92d2SPeter Avalos }
1183c09f92d2SPeter Avalos
1184c09f92d2SPeter Avalos /*
1185c09f92d2SPeter Avalos * Read CFDATA if needed.
1186c09f92d2SPeter Avalos */
1187c09f92d2SPeter Avalos static int
cab_next_cfdata(struct archive_read * a)1188c09f92d2SPeter Avalos cab_next_cfdata(struct archive_read *a)
1189c09f92d2SPeter Avalos {
1190c09f92d2SPeter Avalos struct cab *cab = (struct cab *)(a->format->data);
1191c09f92d2SPeter Avalos struct cfdata *cfdata = cab->entry_cfdata;
1192c09f92d2SPeter Avalos
1193c09f92d2SPeter Avalos /* There are remaining bytes in current CFDATA, use it first. */
1194c09f92d2SPeter Avalos if (cfdata != NULL && cfdata->uncompressed_bytes_remaining > 0)
1195c09f92d2SPeter Avalos return (ARCHIVE_OK);
1196c09f92d2SPeter Avalos
1197c09f92d2SPeter Avalos if (cfdata == NULL) {
1198c09f92d2SPeter Avalos int64_t skip;
1199c09f92d2SPeter Avalos
1200c09f92d2SPeter Avalos cab->entry_cffolder->cfdata_index = 0;
1201c09f92d2SPeter Avalos
1202c09f92d2SPeter Avalos /* Seek read pointer to the offset of CFDATA if needed. */
1203c09f92d2SPeter Avalos skip = cab->entry_cffolder->cfdata_offset_in_cab
1204c09f92d2SPeter Avalos - cab->cab_offset;
1205c09f92d2SPeter Avalos if (skip < 0) {
1206c09f92d2SPeter Avalos int folder_index;
1207c09f92d2SPeter Avalos switch (cab->entry_cffile->folder) {
1208c09f92d2SPeter Avalos case iFoldCONTINUED_FROM_PREV:
1209c09f92d2SPeter Avalos case iFoldCONTINUED_PREV_AND_NEXT:
1210c09f92d2SPeter Avalos folder_index = 0;
1211c09f92d2SPeter Avalos break;
1212c09f92d2SPeter Avalos case iFoldCONTINUED_TO_NEXT:
1213c09f92d2SPeter Avalos folder_index = cab->cfheader.folder_count-1;
1214c09f92d2SPeter Avalos break;
1215c09f92d2SPeter Avalos default:
1216c09f92d2SPeter Avalos folder_index = cab->entry_cffile->folder;
1217c09f92d2SPeter Avalos break;
1218c09f92d2SPeter Avalos }
1219c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1220c09f92d2SPeter Avalos "Invalid offset of CFDATA in folder(%d) %jd < %jd",
1221c09f92d2SPeter Avalos folder_index,
1222c09f92d2SPeter Avalos (intmax_t)cab->entry_cffolder->cfdata_offset_in_cab,
1223c09f92d2SPeter Avalos (intmax_t)cab->cab_offset);
1224c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1225c09f92d2SPeter Avalos }
1226c09f92d2SPeter Avalos if (skip > 0) {
1227c09f92d2SPeter Avalos if (__archive_read_consume(a, skip) < 0)
1228c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1229c09f92d2SPeter Avalos cab->cab_offset =
1230c09f92d2SPeter Avalos cab->entry_cffolder->cfdata_offset_in_cab;
1231c09f92d2SPeter Avalos }
1232c09f92d2SPeter Avalos }
1233c09f92d2SPeter Avalos
1234c09f92d2SPeter Avalos /*
1235c09f92d2SPeter Avalos * Read a CFDATA.
1236c09f92d2SPeter Avalos */
1237c09f92d2SPeter Avalos if (cab->entry_cffolder->cfdata_index <
1238c09f92d2SPeter Avalos cab->entry_cffolder->cfdata_count) {
1239c09f92d2SPeter Avalos const unsigned char *p;
1240c09f92d2SPeter Avalos int l;
1241c09f92d2SPeter Avalos
1242c09f92d2SPeter Avalos cfdata = &(cab->entry_cffolder->cfdata);
1243c09f92d2SPeter Avalos cab->entry_cffolder->cfdata_index++;
1244c09f92d2SPeter Avalos cab->entry_cfdata = cfdata;
1245c09f92d2SPeter Avalos cfdata->sum_calculated = 0;
1246c09f92d2SPeter Avalos cfdata->sum_extra_avail = 0;
1247c09f92d2SPeter Avalos cfdata->sum_ptr = NULL;
1248c09f92d2SPeter Avalos l = 8;
1249c09f92d2SPeter Avalos if (cab->cfheader.flags & RESERVE_PRESENT)
1250c09f92d2SPeter Avalos l += cab->cfheader.cfdata;
1251c09f92d2SPeter Avalos if ((p = __archive_read_ahead(a, l, NULL)) == NULL)
1252c09f92d2SPeter Avalos return (truncated_error(a));
1253c09f92d2SPeter Avalos cfdata->sum = archive_le32dec(p + CFDATA_csum);
1254c09f92d2SPeter Avalos cfdata->compressed_size = archive_le16dec(p + CFDATA_cbData);
1255c09f92d2SPeter Avalos cfdata->compressed_bytes_remaining = cfdata->compressed_size;
1256c09f92d2SPeter Avalos cfdata->uncompressed_size =
1257c09f92d2SPeter Avalos archive_le16dec(p + CFDATA_cbUncomp);
1258c09f92d2SPeter Avalos cfdata->uncompressed_bytes_remaining =
1259c09f92d2SPeter Avalos cfdata->uncompressed_size;
1260c09f92d2SPeter Avalos cfdata->uncompressed_avail = 0;
1261c09f92d2SPeter Avalos cfdata->read_offset = 0;
1262c09f92d2SPeter Avalos cfdata->unconsumed = 0;
1263c09f92d2SPeter Avalos
1264c09f92d2SPeter Avalos /*
1265c09f92d2SPeter Avalos * Sanity check if data size is acceptable.
1266c09f92d2SPeter Avalos */
1267c09f92d2SPeter Avalos if (cfdata->compressed_size == 0 ||
1268c09f92d2SPeter Avalos cfdata->compressed_size > (0x8000+6144))
1269c09f92d2SPeter Avalos goto invalid;
1270c09f92d2SPeter Avalos if (cfdata->uncompressed_size > 0x8000)
1271c09f92d2SPeter Avalos goto invalid;
1272c09f92d2SPeter Avalos if (cfdata->uncompressed_size == 0) {
1273c09f92d2SPeter Avalos switch (cab->entry_cffile->folder) {
1274c09f92d2SPeter Avalos case iFoldCONTINUED_PREV_AND_NEXT:
1275c09f92d2SPeter Avalos case iFoldCONTINUED_TO_NEXT:
1276c09f92d2SPeter Avalos break;
1277c09f92d2SPeter Avalos case iFoldCONTINUED_FROM_PREV:
1278c09f92d2SPeter Avalos default:
1279c09f92d2SPeter Avalos goto invalid;
1280c09f92d2SPeter Avalos }
1281c09f92d2SPeter Avalos }
1282c09f92d2SPeter Avalos /* If CFDATA is not last in a folder, an uncompressed
1283c09f92d2SPeter Avalos * size must be 0x8000(32KBi) */
1284c09f92d2SPeter Avalos if ((cab->entry_cffolder->cfdata_index <
1285c09f92d2SPeter Avalos cab->entry_cffolder->cfdata_count) &&
1286c09f92d2SPeter Avalos cfdata->uncompressed_size != 0x8000)
1287c09f92d2SPeter Avalos goto invalid;
1288c09f92d2SPeter Avalos
1289c09f92d2SPeter Avalos /* A compressed data size and an uncompressed data size must
1290c09f92d2SPeter Avalos * be the same in no compression mode. */
1291c09f92d2SPeter Avalos if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&
1292c09f92d2SPeter Avalos cfdata->compressed_size != cfdata->uncompressed_size)
1293c09f92d2SPeter Avalos goto invalid;
1294c09f92d2SPeter Avalos
1295c09f92d2SPeter Avalos /*
1296c09f92d2SPeter Avalos * Save CFDATA image for sum check.
1297c09f92d2SPeter Avalos */
1298c09f92d2SPeter Avalos if (cfdata->memimage_size < (size_t)l) {
1299c09f92d2SPeter Avalos free(cfdata->memimage);
1300c09f92d2SPeter Avalos cfdata->memimage = malloc(l);
1301c09f92d2SPeter Avalos if (cfdata->memimage == NULL) {
1302c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
1303c09f92d2SPeter Avalos "Can't allocate memory for CAB data");
1304c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1305c09f92d2SPeter Avalos }
1306c09f92d2SPeter Avalos cfdata->memimage_size = l;
1307c09f92d2SPeter Avalos }
1308c09f92d2SPeter Avalos memcpy(cfdata->memimage, p, l);
1309c09f92d2SPeter Avalos
1310c09f92d2SPeter Avalos /* Consume bytes as much as we used. */
1311c09f92d2SPeter Avalos __archive_read_consume(a, l);
1312c09f92d2SPeter Avalos cab->cab_offset += l;
1313c09f92d2SPeter Avalos } else if (cab->entry_cffolder->cfdata_count > 0) {
1314c09f92d2SPeter Avalos /* Run out of all CFDATA in a folder. */
1315c09f92d2SPeter Avalos cfdata->compressed_size = 0;
1316c09f92d2SPeter Avalos cfdata->uncompressed_size = 0;
1317c09f92d2SPeter Avalos cfdata->compressed_bytes_remaining = 0;
1318c09f92d2SPeter Avalos cfdata->uncompressed_bytes_remaining = 0;
1319c09f92d2SPeter Avalos } else {
1320c09f92d2SPeter Avalos /* Current folder does not have any CFDATA. */
1321c09f92d2SPeter Avalos cfdata = &(cab->entry_cffolder->cfdata);
1322c09f92d2SPeter Avalos cab->entry_cfdata = cfdata;
1323c09f92d2SPeter Avalos memset(cfdata, 0, sizeof(*cfdata));
1324c09f92d2SPeter Avalos }
1325c09f92d2SPeter Avalos return (ARCHIVE_OK);
1326c09f92d2SPeter Avalos invalid:
1327c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
1328c09f92d2SPeter Avalos "Invalid CFDATA");
1329c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1330c09f92d2SPeter Avalos }
1331c09f92d2SPeter Avalos
1332c09f92d2SPeter Avalos /*
1333c09f92d2SPeter Avalos * Read ahead CFDATA.
1334c09f92d2SPeter Avalos */
1335c09f92d2SPeter Avalos static const void *
cab_read_ahead_cfdata(struct archive_read * a,ssize_t * avail)1336c09f92d2SPeter Avalos cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail)
1337c09f92d2SPeter Avalos {
1338c09f92d2SPeter Avalos struct cab *cab = (struct cab *)(a->format->data);
1339c09f92d2SPeter Avalos int err;
1340c09f92d2SPeter Avalos
1341c09f92d2SPeter Avalos err = cab_next_cfdata(a);
1342c09f92d2SPeter Avalos if (err < ARCHIVE_OK) {
1343c09f92d2SPeter Avalos *avail = err;
1344c09f92d2SPeter Avalos return (NULL);
1345c09f92d2SPeter Avalos }
1346c09f92d2SPeter Avalos
1347c09f92d2SPeter Avalos switch (cab->entry_cffolder->comptype) {
1348c09f92d2SPeter Avalos case COMPTYPE_NONE:
1349c09f92d2SPeter Avalos return (cab_read_ahead_cfdata_none(a, avail));
1350c09f92d2SPeter Avalos case COMPTYPE_MSZIP:
1351c09f92d2SPeter Avalos return (cab_read_ahead_cfdata_deflate(a, avail));
1352c09f92d2SPeter Avalos case COMPTYPE_LZX:
1353c09f92d2SPeter Avalos return (cab_read_ahead_cfdata_lzx(a, avail));
1354c09f92d2SPeter Avalos default: /* Unsupported compression. */
1355c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
1356c09f92d2SPeter Avalos "Unsupported CAB compression : %s",
1357c09f92d2SPeter Avalos cab->entry_cffolder->compname);
1358c09f92d2SPeter Avalos *avail = ARCHIVE_FAILED;
1359c09f92d2SPeter Avalos return (NULL);
1360c09f92d2SPeter Avalos }
1361c09f92d2SPeter Avalos }
1362c09f92d2SPeter Avalos
1363c09f92d2SPeter Avalos /*
1364c09f92d2SPeter Avalos * Read ahead CFDATA as uncompressed data.
1365c09f92d2SPeter Avalos */
1366c09f92d2SPeter Avalos static const void *
cab_read_ahead_cfdata_none(struct archive_read * a,ssize_t * avail)1367c09f92d2SPeter Avalos cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail)
1368c09f92d2SPeter Avalos {
1369c09f92d2SPeter Avalos struct cab *cab = (struct cab *)(a->format->data);
1370c09f92d2SPeter Avalos struct cfdata *cfdata;
1371c09f92d2SPeter Avalos const void *d;
1372c09f92d2SPeter Avalos
1373c09f92d2SPeter Avalos cfdata = cab->entry_cfdata;
1374c09f92d2SPeter Avalos
1375c09f92d2SPeter Avalos /*
1376c09f92d2SPeter Avalos * Note: '1' here is a performance optimization.
1377c09f92d2SPeter Avalos * Recall that the decompression layer returns a count of
1378c09f92d2SPeter Avalos * available bytes; asking for more than that forces the
1379c09f92d2SPeter Avalos * decompressor to combine reads by copying data.
1380c09f92d2SPeter Avalos */
1381c09f92d2SPeter Avalos d = __archive_read_ahead(a, 1, avail);
1382c09f92d2SPeter Avalos if (*avail <= 0) {
1383c09f92d2SPeter Avalos *avail = truncated_error(a);
1384c09f92d2SPeter Avalos return (NULL);
1385c09f92d2SPeter Avalos }
1386c09f92d2SPeter Avalos if (*avail > cfdata->uncompressed_bytes_remaining)
1387c09f92d2SPeter Avalos *avail = cfdata->uncompressed_bytes_remaining;
1388c09f92d2SPeter Avalos cfdata->uncompressed_avail = cfdata->uncompressed_size;
1389c09f92d2SPeter Avalos cfdata->unconsumed = *avail;
1390c09f92d2SPeter Avalos cfdata->sum_ptr = d;
1391c09f92d2SPeter Avalos return (d);
1392c09f92d2SPeter Avalos }
1393c09f92d2SPeter Avalos
1394c09f92d2SPeter Avalos /*
1395c09f92d2SPeter Avalos * Read ahead CFDATA as deflate data.
1396c09f92d2SPeter Avalos */
1397c09f92d2SPeter Avalos #ifdef HAVE_ZLIB_H
1398c09f92d2SPeter Avalos static const void *
cab_read_ahead_cfdata_deflate(struct archive_read * a,ssize_t * avail)1399c09f92d2SPeter Avalos cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
1400c09f92d2SPeter Avalos {
1401c09f92d2SPeter Avalos struct cab *cab = (struct cab *)(a->format->data);
1402c09f92d2SPeter Avalos struct cfdata *cfdata;
1403c09f92d2SPeter Avalos const void *d;
1404c09f92d2SPeter Avalos int r, mszip;
1405c09f92d2SPeter Avalos uint16_t uavail;
1406c09f92d2SPeter Avalos char eod = 0;
1407c09f92d2SPeter Avalos
1408c09f92d2SPeter Avalos cfdata = cab->entry_cfdata;
1409c09f92d2SPeter Avalos /* If the buffer hasn't been allocated, allocate it now. */
1410c09f92d2SPeter Avalos if (cab->uncompressed_buffer == NULL) {
1411c09f92d2SPeter Avalos cab->uncompressed_buffer_size = 0x8000;
1412c09f92d2SPeter Avalos cab->uncompressed_buffer
1413c09f92d2SPeter Avalos = (unsigned char *)malloc(cab->uncompressed_buffer_size);
1414c09f92d2SPeter Avalos if (cab->uncompressed_buffer == NULL) {
1415c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
1416c09f92d2SPeter Avalos "No memory for CAB reader");
1417c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1418c09f92d2SPeter Avalos return (NULL);
1419c09f92d2SPeter Avalos }
1420c09f92d2SPeter Avalos }
1421c09f92d2SPeter Avalos
1422c09f92d2SPeter Avalos uavail = cfdata->uncompressed_avail;
1423c09f92d2SPeter Avalos if (uavail == cfdata->uncompressed_size) {
1424c09f92d2SPeter Avalos d = cab->uncompressed_buffer + cfdata->read_offset;
1425c09f92d2SPeter Avalos *avail = uavail - cfdata->read_offset;
1426c09f92d2SPeter Avalos return (d);
1427c09f92d2SPeter Avalos }
1428c09f92d2SPeter Avalos
1429c09f92d2SPeter Avalos if (!cab->entry_cffolder->decompress_init) {
1430c09f92d2SPeter Avalos cab->stream.next_in = NULL;
1431c09f92d2SPeter Avalos cab->stream.avail_in = 0;
1432c09f92d2SPeter Avalos cab->stream.total_in = 0;
1433c09f92d2SPeter Avalos cab->stream.next_out = NULL;
1434c09f92d2SPeter Avalos cab->stream.avail_out = 0;
1435c09f92d2SPeter Avalos cab->stream.total_out = 0;
1436c09f92d2SPeter Avalos if (cab->stream_valid)
1437c09f92d2SPeter Avalos r = inflateReset(&cab->stream);
1438c09f92d2SPeter Avalos else
1439c09f92d2SPeter Avalos r = inflateInit2(&cab->stream,
1440c09f92d2SPeter Avalos -15 /* Don't check for zlib header */);
1441c09f92d2SPeter Avalos if (r != Z_OK) {
1442c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1443c09f92d2SPeter Avalos "Can't initialize deflate decompression.");
1444c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1445c09f92d2SPeter Avalos return (NULL);
1446c09f92d2SPeter Avalos }
1447c09f92d2SPeter Avalos /* Stream structure has been set up. */
1448c09f92d2SPeter Avalos cab->stream_valid = 1;
1449c09f92d2SPeter Avalos /* We've initialized decompression for this stream. */
1450c09f92d2SPeter Avalos cab->entry_cffolder->decompress_init = 1;
1451c09f92d2SPeter Avalos }
1452c09f92d2SPeter Avalos
1453c09f92d2SPeter Avalos if (cfdata->compressed_bytes_remaining == cfdata->compressed_size)
1454c09f92d2SPeter Avalos mszip = 2;
1455c09f92d2SPeter Avalos else
1456c09f92d2SPeter Avalos mszip = 0;
1457c09f92d2SPeter Avalos eod = 0;
1458c09f92d2SPeter Avalos cab->stream.total_out = uavail;
1459c09f92d2SPeter Avalos /*
1460c09f92d2SPeter Avalos * We always uncompress all data in current CFDATA.
1461c09f92d2SPeter Avalos */
1462c09f92d2SPeter Avalos while (!eod && cab->stream.total_out < cfdata->uncompressed_size) {
1463c09f92d2SPeter Avalos ssize_t bytes_avail;
1464c09f92d2SPeter Avalos
1465c09f92d2SPeter Avalos cab->stream.next_out =
1466c09f92d2SPeter Avalos cab->uncompressed_buffer + cab->stream.total_out;
1467c09f92d2SPeter Avalos cab->stream.avail_out =
1468c09f92d2SPeter Avalos cfdata->uncompressed_size - cab->stream.total_out;
1469c09f92d2SPeter Avalos
1470c09f92d2SPeter Avalos d = __archive_read_ahead(a, 1, &bytes_avail);
1471c09f92d2SPeter Avalos if (bytes_avail <= 0) {
1472c09f92d2SPeter Avalos *avail = truncated_error(a);
1473c09f92d2SPeter Avalos return (NULL);
1474c09f92d2SPeter Avalos }
1475c09f92d2SPeter Avalos if (bytes_avail > cfdata->compressed_bytes_remaining)
1476c09f92d2SPeter Avalos bytes_avail = cfdata->compressed_bytes_remaining;
1477c09f92d2SPeter Avalos /*
1478c09f92d2SPeter Avalos * A bug in zlib.h: stream.next_in should be marked 'const'
1479c09f92d2SPeter Avalos * but isn't (the library never alters data through the
1480c09f92d2SPeter Avalos * next_in pointer, only reads it). The result: this ugly
1481c09f92d2SPeter Avalos * cast to remove 'const'.
1482c09f92d2SPeter Avalos */
1483c09f92d2SPeter Avalos cab->stream.next_in = (Bytef *)(uintptr_t)d;
1484d4d8193eSPeter Avalos cab->stream.avail_in = (uInt)bytes_avail;
1485c09f92d2SPeter Avalos cab->stream.total_in = 0;
1486c09f92d2SPeter Avalos
1487c09f92d2SPeter Avalos /* Cut out a tow-byte MSZIP signature(0x43, 0x4b). */
1488c09f92d2SPeter Avalos if (mszip > 0) {
1489e95abc47Szrj if (bytes_avail <= 0)
1490e95abc47Szrj goto nomszip;
1491c09f92d2SPeter Avalos if (bytes_avail <= mszip) {
1492c09f92d2SPeter Avalos if (mszip == 2) {
1493c09f92d2SPeter Avalos if (cab->stream.next_in[0] != 0x43)
1494c09f92d2SPeter Avalos goto nomszip;
1495c09f92d2SPeter Avalos if (bytes_avail > 1 &&
1496c09f92d2SPeter Avalos cab->stream.next_in[1] != 0x4b)
1497c09f92d2SPeter Avalos goto nomszip;
1498c09f92d2SPeter Avalos } else if (cab->stream.next_in[0] != 0x4b)
1499c09f92d2SPeter Avalos goto nomszip;
1500c09f92d2SPeter Avalos cfdata->unconsumed = bytes_avail;
1501c09f92d2SPeter Avalos cfdata->sum_ptr = d;
1502c09f92d2SPeter Avalos if (cab_minimum_consume_cfdata(
1503c09f92d2SPeter Avalos a, cfdata->unconsumed) < 0) {
1504c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1505c09f92d2SPeter Avalos return (NULL);
1506c09f92d2SPeter Avalos }
1507d4d8193eSPeter Avalos mszip -= (int)bytes_avail;
1508c09f92d2SPeter Avalos continue;
1509c09f92d2SPeter Avalos }
1510c09f92d2SPeter Avalos if (mszip == 1 && cab->stream.next_in[0] != 0x4b)
1511c09f92d2SPeter Avalos goto nomszip;
1512085658deSDaniel Fojt else if (mszip == 2 && (cab->stream.next_in[0] != 0x43 ||
1513085658deSDaniel Fojt cab->stream.next_in[1] != 0x4b))
1514c09f92d2SPeter Avalos goto nomszip;
1515c09f92d2SPeter Avalos cab->stream.next_in += mszip;
1516c09f92d2SPeter Avalos cab->stream.avail_in -= mszip;
1517c09f92d2SPeter Avalos cab->stream.total_in += mszip;
1518c09f92d2SPeter Avalos mszip = 0;
1519c09f92d2SPeter Avalos }
1520c09f92d2SPeter Avalos
1521c09f92d2SPeter Avalos r = inflate(&cab->stream, 0);
1522c09f92d2SPeter Avalos switch (r) {
1523c09f92d2SPeter Avalos case Z_OK:
1524c09f92d2SPeter Avalos break;
1525c09f92d2SPeter Avalos case Z_STREAM_END:
1526c09f92d2SPeter Avalos eod = 1;
1527c09f92d2SPeter Avalos break;
1528c09f92d2SPeter Avalos default:
1529c09f92d2SPeter Avalos goto zlibfailed;
1530c09f92d2SPeter Avalos }
1531c09f92d2SPeter Avalos cfdata->unconsumed = cab->stream.total_in;
1532c09f92d2SPeter Avalos cfdata->sum_ptr = d;
1533c09f92d2SPeter Avalos if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
1534c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1535c09f92d2SPeter Avalos return (NULL);
1536c09f92d2SPeter Avalos }
1537c09f92d2SPeter Avalos }
153859bf7050SPeter Avalos uavail = (uint16_t)cab->stream.total_out;
1539c09f92d2SPeter Avalos
1540c09f92d2SPeter Avalos if (uavail < cfdata->uncompressed_size) {
1541c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1542c09f92d2SPeter Avalos "Invalid uncompressed size (%d < %d)",
1543c09f92d2SPeter Avalos uavail, cfdata->uncompressed_size);
1544c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1545c09f92d2SPeter Avalos return (NULL);
1546c09f92d2SPeter Avalos }
1547c09f92d2SPeter Avalos
1548c09f92d2SPeter Avalos /*
1549c09f92d2SPeter Avalos * Note: I suspect there is a bug in makecab.exe because, in rare
1550c09f92d2SPeter Avalos * case, compressed bytes are still remaining regardless we have
1551e95abc47Szrj * gotten all uncompressed bytes, which size is recorded in CFDATA,
1552c09f92d2SPeter Avalos * as much as we need, and we have to use the garbage so as to
1553c09f92d2SPeter Avalos * correctly compute the sum of CFDATA accordingly.
1554c09f92d2SPeter Avalos */
1555c09f92d2SPeter Avalos if (cfdata->compressed_bytes_remaining > 0) {
1556c09f92d2SPeter Avalos ssize_t bytes_avail;
1557c09f92d2SPeter Avalos
1558c09f92d2SPeter Avalos d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
1559c09f92d2SPeter Avalos &bytes_avail);
1560c09f92d2SPeter Avalos if (bytes_avail <= 0) {
1561c09f92d2SPeter Avalos *avail = truncated_error(a);
1562c09f92d2SPeter Avalos return (NULL);
1563c09f92d2SPeter Avalos }
1564c09f92d2SPeter Avalos cfdata->unconsumed = cfdata->compressed_bytes_remaining;
1565c09f92d2SPeter Avalos cfdata->sum_ptr = d;
1566c09f92d2SPeter Avalos if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
1567c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1568c09f92d2SPeter Avalos return (NULL);
1569c09f92d2SPeter Avalos }
1570c09f92d2SPeter Avalos }
1571c09f92d2SPeter Avalos
1572c09f92d2SPeter Avalos /*
1573c09f92d2SPeter Avalos * Set dictionary data for decompressing of next CFDATA, which
1574c09f92d2SPeter Avalos * in the same folder. This is why we always do decompress CFDATA
1575c09f92d2SPeter Avalos * even if beginning CFDATA or some of CFDATA are not used in
1576c09f92d2SPeter Avalos * skipping file data.
1577c09f92d2SPeter Avalos */
1578c09f92d2SPeter Avalos if (cab->entry_cffolder->cfdata_index <
1579c09f92d2SPeter Avalos cab->entry_cffolder->cfdata_count) {
1580c09f92d2SPeter Avalos r = inflateReset(&cab->stream);
1581c09f92d2SPeter Avalos if (r != Z_OK)
1582c09f92d2SPeter Avalos goto zlibfailed;
1583c09f92d2SPeter Avalos r = inflateSetDictionary(&cab->stream,
1584c09f92d2SPeter Avalos cab->uncompressed_buffer, cfdata->uncompressed_size);
1585c09f92d2SPeter Avalos if (r != Z_OK)
1586c09f92d2SPeter Avalos goto zlibfailed;
1587c09f92d2SPeter Avalos }
1588c09f92d2SPeter Avalos
1589c09f92d2SPeter Avalos d = cab->uncompressed_buffer + cfdata->read_offset;
1590c09f92d2SPeter Avalos *avail = uavail - cfdata->read_offset;
1591c09f92d2SPeter Avalos cfdata->uncompressed_avail = uavail;
1592c09f92d2SPeter Avalos
1593c09f92d2SPeter Avalos return (d);
1594c09f92d2SPeter Avalos
1595c09f92d2SPeter Avalos zlibfailed:
1596c09f92d2SPeter Avalos switch (r) {
1597c09f92d2SPeter Avalos case Z_MEM_ERROR:
1598c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
1599c09f92d2SPeter Avalos "Out of memory for deflate decompression");
1600c09f92d2SPeter Avalos break;
1601c09f92d2SPeter Avalos default:
1602c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1603c09f92d2SPeter Avalos "Deflate decompression failed (%d)", r);
1604c09f92d2SPeter Avalos break;
1605c09f92d2SPeter Avalos }
1606c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1607c09f92d2SPeter Avalos return (NULL);
1608c09f92d2SPeter Avalos nomszip:
1609c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1610c09f92d2SPeter Avalos "CFDATA incorrect(no MSZIP signature)");
1611c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1612c09f92d2SPeter Avalos return (NULL);
1613c09f92d2SPeter Avalos }
1614c09f92d2SPeter Avalos
1615c09f92d2SPeter Avalos #else /* HAVE_ZLIB_H */
1616c09f92d2SPeter Avalos
1617c09f92d2SPeter Avalos static const void *
cab_read_ahead_cfdata_deflate(struct archive_read * a,ssize_t * avail)1618c09f92d2SPeter Avalos cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
1619c09f92d2SPeter Avalos {
1620c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1621c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1622c09f92d2SPeter Avalos "libarchive compiled without deflate support (no libz)");
1623c09f92d2SPeter Avalos return (NULL);
1624c09f92d2SPeter Avalos }
1625c09f92d2SPeter Avalos
1626c09f92d2SPeter Avalos #endif /* HAVE_ZLIB_H */
1627c09f92d2SPeter Avalos
1628c09f92d2SPeter Avalos static const void *
cab_read_ahead_cfdata_lzx(struct archive_read * a,ssize_t * avail)1629c09f92d2SPeter Avalos cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
1630c09f92d2SPeter Avalos {
1631c09f92d2SPeter Avalos struct cab *cab = (struct cab *)(a->format->data);
1632c09f92d2SPeter Avalos struct cfdata *cfdata;
1633c09f92d2SPeter Avalos const void *d;
1634c09f92d2SPeter Avalos int r;
1635c09f92d2SPeter Avalos uint16_t uavail;
1636c09f92d2SPeter Avalos
1637c09f92d2SPeter Avalos cfdata = cab->entry_cfdata;
1638c09f92d2SPeter Avalos /* If the buffer hasn't been allocated, allocate it now. */
1639c09f92d2SPeter Avalos if (cab->uncompressed_buffer == NULL) {
1640c09f92d2SPeter Avalos cab->uncompressed_buffer_size = 0x8000;
1641c09f92d2SPeter Avalos cab->uncompressed_buffer
1642c09f92d2SPeter Avalos = (unsigned char *)malloc(cab->uncompressed_buffer_size);
1643c09f92d2SPeter Avalos if (cab->uncompressed_buffer == NULL) {
1644c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
1645c09f92d2SPeter Avalos "No memory for CAB reader");
1646c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1647c09f92d2SPeter Avalos return (NULL);
1648c09f92d2SPeter Avalos }
1649c09f92d2SPeter Avalos }
1650c09f92d2SPeter Avalos
1651c09f92d2SPeter Avalos uavail = cfdata->uncompressed_avail;
1652c09f92d2SPeter Avalos if (uavail == cfdata->uncompressed_size) {
1653c09f92d2SPeter Avalos d = cab->uncompressed_buffer + cfdata->read_offset;
1654c09f92d2SPeter Avalos *avail = uavail - cfdata->read_offset;
1655c09f92d2SPeter Avalos return (d);
1656c09f92d2SPeter Avalos }
1657c09f92d2SPeter Avalos
1658c09f92d2SPeter Avalos if (!cab->entry_cffolder->decompress_init) {
1659c09f92d2SPeter Avalos r = lzx_decode_init(&cab->xstrm,
1660c09f92d2SPeter Avalos cab->entry_cffolder->compdata);
1661c09f92d2SPeter Avalos if (r != ARCHIVE_OK) {
1662c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1663c09f92d2SPeter Avalos "Can't initialize LZX decompression.");
1664c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1665c09f92d2SPeter Avalos return (NULL);
1666c09f92d2SPeter Avalos }
1667c09f92d2SPeter Avalos /* We've initialized decompression for this stream. */
1668c09f92d2SPeter Avalos cab->entry_cffolder->decompress_init = 1;
1669c09f92d2SPeter Avalos }
1670c09f92d2SPeter Avalos
1671c09f92d2SPeter Avalos /* Clean up remaining bits of previous CFDATA. */
1672c09f92d2SPeter Avalos lzx_cleanup_bitstream(&cab->xstrm);
1673c09f92d2SPeter Avalos cab->xstrm.total_out = uavail;
1674c09f92d2SPeter Avalos while (cab->xstrm.total_out < cfdata->uncompressed_size) {
1675c09f92d2SPeter Avalos ssize_t bytes_avail;
1676c09f92d2SPeter Avalos
1677c09f92d2SPeter Avalos cab->xstrm.next_out =
1678c09f92d2SPeter Avalos cab->uncompressed_buffer + cab->xstrm.total_out;
1679c09f92d2SPeter Avalos cab->xstrm.avail_out =
1680c09f92d2SPeter Avalos cfdata->uncompressed_size - cab->xstrm.total_out;
1681c09f92d2SPeter Avalos
1682c09f92d2SPeter Avalos d = __archive_read_ahead(a, 1, &bytes_avail);
1683c09f92d2SPeter Avalos if (bytes_avail <= 0) {
1684c09f92d2SPeter Avalos archive_set_error(&a->archive,
1685c09f92d2SPeter Avalos ARCHIVE_ERRNO_FILE_FORMAT,
1686c09f92d2SPeter Avalos "Truncated CAB file data");
1687c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1688c09f92d2SPeter Avalos return (NULL);
1689c09f92d2SPeter Avalos }
1690c09f92d2SPeter Avalos if (bytes_avail > cfdata->compressed_bytes_remaining)
1691c09f92d2SPeter Avalos bytes_avail = cfdata->compressed_bytes_remaining;
1692c09f92d2SPeter Avalos
1693c09f92d2SPeter Avalos cab->xstrm.next_in = d;
1694c09f92d2SPeter Avalos cab->xstrm.avail_in = bytes_avail;
1695c09f92d2SPeter Avalos cab->xstrm.total_in = 0;
1696c09f92d2SPeter Avalos r = lzx_decode(&cab->xstrm,
1697c09f92d2SPeter Avalos cfdata->compressed_bytes_remaining == bytes_avail);
1698c09f92d2SPeter Avalos switch (r) {
1699c09f92d2SPeter Avalos case ARCHIVE_OK:
1700c09f92d2SPeter Avalos case ARCHIVE_EOF:
1701c09f92d2SPeter Avalos break;
1702c09f92d2SPeter Avalos default:
1703c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1704c09f92d2SPeter Avalos "LZX decompression failed (%d)", r);
1705c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1706c09f92d2SPeter Avalos return (NULL);
1707c09f92d2SPeter Avalos }
1708c09f92d2SPeter Avalos cfdata->unconsumed = cab->xstrm.total_in;
1709c09f92d2SPeter Avalos cfdata->sum_ptr = d;
1710c09f92d2SPeter Avalos if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
1711c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1712c09f92d2SPeter Avalos return (NULL);
1713c09f92d2SPeter Avalos }
1714c09f92d2SPeter Avalos }
1715c09f92d2SPeter Avalos
171659bf7050SPeter Avalos uavail = (uint16_t)cab->xstrm.total_out;
1717c09f92d2SPeter Avalos /*
1718c09f92d2SPeter Avalos * Make sure a read pointer advances to next CFDATA.
1719c09f92d2SPeter Avalos */
1720c09f92d2SPeter Avalos if (cfdata->compressed_bytes_remaining > 0) {
1721c09f92d2SPeter Avalos ssize_t bytes_avail;
1722c09f92d2SPeter Avalos
1723c09f92d2SPeter Avalos d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
1724c09f92d2SPeter Avalos &bytes_avail);
1725c09f92d2SPeter Avalos if (bytes_avail <= 0) {
1726c09f92d2SPeter Avalos *avail = truncated_error(a);
1727c09f92d2SPeter Avalos return (NULL);
1728c09f92d2SPeter Avalos }
1729c09f92d2SPeter Avalos cfdata->unconsumed = cfdata->compressed_bytes_remaining;
1730c09f92d2SPeter Avalos cfdata->sum_ptr = d;
1731c09f92d2SPeter Avalos if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
1732c09f92d2SPeter Avalos *avail = ARCHIVE_FATAL;
1733c09f92d2SPeter Avalos return (NULL);
1734c09f92d2SPeter Avalos }
1735c09f92d2SPeter Avalos }
1736c09f92d2SPeter Avalos
1737c09f92d2SPeter Avalos /*
1738e95abc47Szrj * Translation reversal of x86 processor CALL byte sequence(E8).
1739c09f92d2SPeter Avalos */
1740c09f92d2SPeter Avalos lzx_translation(&cab->xstrm, cab->uncompressed_buffer,
1741c09f92d2SPeter Avalos cfdata->uncompressed_size,
1742c09f92d2SPeter Avalos (cab->entry_cffolder->cfdata_index-1) * 0x8000);
1743c09f92d2SPeter Avalos
1744c09f92d2SPeter Avalos d = cab->uncompressed_buffer + cfdata->read_offset;
1745c09f92d2SPeter Avalos *avail = uavail - cfdata->read_offset;
1746c09f92d2SPeter Avalos cfdata->uncompressed_avail = uavail;
1747c09f92d2SPeter Avalos
1748c09f92d2SPeter Avalos return (d);
1749c09f92d2SPeter Avalos }
1750c09f92d2SPeter Avalos
1751c09f92d2SPeter Avalos /*
1752c09f92d2SPeter Avalos * Consume CFDATA.
1753c09f92d2SPeter Avalos * We always decompress CFDATA to consume CFDATA as much as we need
1754c09f92d2SPeter Avalos * in uncompressed bytes because all CFDATA in a folder are related
1755c09f92d2SPeter Avalos * so we do not skip any CFDATA without decompressing.
1756c09f92d2SPeter Avalos * Note: If the folder of a CFFILE is iFoldCONTINUED_PREV_AND_NEXT or
1757c09f92d2SPeter Avalos * iFoldCONTINUED_FROM_PREV, we won't decompress because a CFDATA for
1758c09f92d2SPeter Avalos * the CFFILE is remaining bytes of previous Multivolume CAB file.
1759c09f92d2SPeter Avalos */
1760c09f92d2SPeter Avalos static int64_t
cab_consume_cfdata(struct archive_read * a,int64_t consumed_bytes)1761c09f92d2SPeter Avalos cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
1762c09f92d2SPeter Avalos {
1763c09f92d2SPeter Avalos struct cab *cab = (struct cab *)(a->format->data);
1764c09f92d2SPeter Avalos struct cfdata *cfdata;
1765c09f92d2SPeter Avalos int64_t cbytes, rbytes;
1766c09f92d2SPeter Avalos int err;
1767c09f92d2SPeter Avalos
1768c09f92d2SPeter Avalos rbytes = cab_minimum_consume_cfdata(a, consumed_bytes);
1769c09f92d2SPeter Avalos if (rbytes < 0)
1770c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1771c09f92d2SPeter Avalos
1772c09f92d2SPeter Avalos cfdata = cab->entry_cfdata;
1773c09f92d2SPeter Avalos while (rbytes > 0) {
1774c09f92d2SPeter Avalos ssize_t avail;
1775c09f92d2SPeter Avalos
1776c09f92d2SPeter Avalos if (cfdata->compressed_size == 0) {
1777c09f92d2SPeter Avalos archive_set_error(&a->archive,
1778c09f92d2SPeter Avalos ARCHIVE_ERRNO_FILE_FORMAT,
1779c09f92d2SPeter Avalos "Invalid CFDATA");
1780c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1781c09f92d2SPeter Avalos }
1782c09f92d2SPeter Avalos cbytes = cfdata->uncompressed_bytes_remaining;
1783c09f92d2SPeter Avalos if (cbytes > rbytes)
1784c09f92d2SPeter Avalos cbytes = rbytes;
1785c09f92d2SPeter Avalos rbytes -= cbytes;
1786c09f92d2SPeter Avalos
1787c09f92d2SPeter Avalos if (cfdata->uncompressed_avail == 0 &&
178859bf7050SPeter Avalos (cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT ||
1789c09f92d2SPeter Avalos cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) {
1790c09f92d2SPeter Avalos /* We have not read any data yet. */
1791c09f92d2SPeter Avalos if (cbytes == cfdata->uncompressed_bytes_remaining) {
1792c09f92d2SPeter Avalos /* Skip whole current CFDATA. */
1793c09f92d2SPeter Avalos __archive_read_consume(a,
1794c09f92d2SPeter Avalos cfdata->compressed_size);
1795c09f92d2SPeter Avalos cab->cab_offset += cfdata->compressed_size;
1796c09f92d2SPeter Avalos cfdata->compressed_bytes_remaining = 0;
1797c09f92d2SPeter Avalos cfdata->uncompressed_bytes_remaining = 0;
1798c09f92d2SPeter Avalos err = cab_next_cfdata(a);
1799c09f92d2SPeter Avalos if (err < 0)
1800c09f92d2SPeter Avalos return (err);
1801c09f92d2SPeter Avalos cfdata = cab->entry_cfdata;
1802c09f92d2SPeter Avalos if (cfdata->uncompressed_size == 0) {
1803c09f92d2SPeter Avalos switch (cab->entry_cffile->folder) {
1804c09f92d2SPeter Avalos case iFoldCONTINUED_PREV_AND_NEXT:
1805c09f92d2SPeter Avalos case iFoldCONTINUED_TO_NEXT:
1806c09f92d2SPeter Avalos case iFoldCONTINUED_FROM_PREV:
1807c09f92d2SPeter Avalos rbytes = 0;
1808c09f92d2SPeter Avalos break;
1809c09f92d2SPeter Avalos default:
1810c09f92d2SPeter Avalos break;
1811c09f92d2SPeter Avalos }
1812c09f92d2SPeter Avalos }
1813c09f92d2SPeter Avalos continue;
1814c09f92d2SPeter Avalos }
181559bf7050SPeter Avalos cfdata->read_offset += (uint16_t)cbytes;
181659bf7050SPeter Avalos cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
1817c09f92d2SPeter Avalos break;
1818c09f92d2SPeter Avalos } else if (cbytes == 0) {
1819c09f92d2SPeter Avalos err = cab_next_cfdata(a);
1820c09f92d2SPeter Avalos if (err < 0)
1821c09f92d2SPeter Avalos return (err);
1822c09f92d2SPeter Avalos cfdata = cab->entry_cfdata;
1823c09f92d2SPeter Avalos if (cfdata->uncompressed_size == 0) {
1824c09f92d2SPeter Avalos switch (cab->entry_cffile->folder) {
1825c09f92d2SPeter Avalos case iFoldCONTINUED_PREV_AND_NEXT:
1826c09f92d2SPeter Avalos case iFoldCONTINUED_TO_NEXT:
1827c09f92d2SPeter Avalos case iFoldCONTINUED_FROM_PREV:
1828c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1829c09f92d2SPeter Avalos default:
1830c09f92d2SPeter Avalos break;
1831c09f92d2SPeter Avalos }
1832c09f92d2SPeter Avalos }
1833c09f92d2SPeter Avalos continue;
1834c09f92d2SPeter Avalos }
1835c09f92d2SPeter Avalos while (cbytes > 0) {
1836c09f92d2SPeter Avalos (void)cab_read_ahead_cfdata(a, &avail);
1837c09f92d2SPeter Avalos if (avail <= 0)
1838c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1839c09f92d2SPeter Avalos if (avail > cbytes)
184059bf7050SPeter Avalos avail = (ssize_t)cbytes;
1841c09f92d2SPeter Avalos if (cab_minimum_consume_cfdata(a, avail) < 0)
1842c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1843c09f92d2SPeter Avalos cbytes -= avail;
1844c09f92d2SPeter Avalos }
1845c09f92d2SPeter Avalos }
1846c09f92d2SPeter Avalos return (consumed_bytes);
1847c09f92d2SPeter Avalos }
1848c09f92d2SPeter Avalos
1849c09f92d2SPeter Avalos /*
1850c09f92d2SPeter Avalos * Consume CFDATA as much as we have already gotten and
1851c09f92d2SPeter Avalos * compute the sum of CFDATA.
1852c09f92d2SPeter Avalos */
1853c09f92d2SPeter Avalos static int64_t
cab_minimum_consume_cfdata(struct archive_read * a,int64_t consumed_bytes)1854c09f92d2SPeter Avalos cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
1855c09f92d2SPeter Avalos {
1856c09f92d2SPeter Avalos struct cab *cab = (struct cab *)(a->format->data);
1857c09f92d2SPeter Avalos struct cfdata *cfdata;
1858c09f92d2SPeter Avalos int64_t cbytes, rbytes;
1859c09f92d2SPeter Avalos int err;
1860c09f92d2SPeter Avalos
1861c09f92d2SPeter Avalos cfdata = cab->entry_cfdata;
1862c09f92d2SPeter Avalos rbytes = consumed_bytes;
1863c09f92d2SPeter Avalos if (cab->entry_cffolder->comptype == COMPTYPE_NONE) {
1864c09f92d2SPeter Avalos if (consumed_bytes < cfdata->unconsumed)
1865c09f92d2SPeter Avalos cbytes = consumed_bytes;
1866c09f92d2SPeter Avalos else
1867c09f92d2SPeter Avalos cbytes = cfdata->unconsumed;
1868c09f92d2SPeter Avalos rbytes -= cbytes;
186959bf7050SPeter Avalos cfdata->read_offset += (uint16_t)cbytes;
187059bf7050SPeter Avalos cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
1871c09f92d2SPeter Avalos cfdata->unconsumed -= cbytes;
1872c09f92d2SPeter Avalos } else {
1873c09f92d2SPeter Avalos cbytes = cfdata->uncompressed_avail - cfdata->read_offset;
1874c09f92d2SPeter Avalos if (cbytes > 0) {
1875c09f92d2SPeter Avalos if (consumed_bytes < cbytes)
1876c09f92d2SPeter Avalos cbytes = consumed_bytes;
1877c09f92d2SPeter Avalos rbytes -= cbytes;
187859bf7050SPeter Avalos cfdata->read_offset += (uint16_t)cbytes;
187959bf7050SPeter Avalos cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
1880c09f92d2SPeter Avalos }
1881c09f92d2SPeter Avalos
1882c09f92d2SPeter Avalos if (cfdata->unconsumed) {
1883c09f92d2SPeter Avalos cbytes = cfdata->unconsumed;
1884c09f92d2SPeter Avalos cfdata->unconsumed = 0;
1885c09f92d2SPeter Avalos } else
1886c09f92d2SPeter Avalos cbytes = 0;
1887c09f92d2SPeter Avalos }
1888c09f92d2SPeter Avalos if (cbytes) {
1889c09f92d2SPeter Avalos /* Compute the sum. */
189059bf7050SPeter Avalos cab_checksum_update(a, (size_t)cbytes);
1891c09f92d2SPeter Avalos
1892c09f92d2SPeter Avalos /* Consume as much as the compressor actually used. */
1893c09f92d2SPeter Avalos __archive_read_consume(a, cbytes);
1894c09f92d2SPeter Avalos cab->cab_offset += cbytes;
189559bf7050SPeter Avalos cfdata->compressed_bytes_remaining -= (uint16_t)cbytes;
1896c09f92d2SPeter Avalos if (cfdata->compressed_bytes_remaining == 0) {
1897c09f92d2SPeter Avalos err = cab_checksum_finish(a);
1898c09f92d2SPeter Avalos if (err < 0)
1899c09f92d2SPeter Avalos return (err);
1900c09f92d2SPeter Avalos }
1901c09f92d2SPeter Avalos }
1902c09f92d2SPeter Avalos return (rbytes);
1903c09f92d2SPeter Avalos }
1904c09f92d2SPeter Avalos
1905c09f92d2SPeter Avalos /*
1906c09f92d2SPeter Avalos * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
1907c09f92d2SPeter Avalos * cab->end_of_entry if it consumes all of the data.
1908c09f92d2SPeter Avalos */
1909c09f92d2SPeter Avalos static int
cab_read_data(struct archive_read * a,const void ** buff,size_t * size,int64_t * offset)1910c09f92d2SPeter Avalos cab_read_data(struct archive_read *a, const void **buff,
1911c09f92d2SPeter Avalos size_t *size, int64_t *offset)
1912c09f92d2SPeter Avalos {
1913c09f92d2SPeter Avalos struct cab *cab = (struct cab *)(a->format->data);
1914c09f92d2SPeter Avalos ssize_t bytes_avail;
1915c09f92d2SPeter Avalos
1916c09f92d2SPeter Avalos if (cab->entry_bytes_remaining == 0) {
1917c09f92d2SPeter Avalos *buff = NULL;
1918c09f92d2SPeter Avalos *size = 0;
1919c09f92d2SPeter Avalos *offset = cab->entry_offset;
1920c09f92d2SPeter Avalos cab->end_of_entry = 1;
1921c09f92d2SPeter Avalos return (ARCHIVE_OK);
1922c09f92d2SPeter Avalos }
1923c09f92d2SPeter Avalos
1924c09f92d2SPeter Avalos *buff = cab_read_ahead_cfdata(a, &bytes_avail);
1925c09f92d2SPeter Avalos if (bytes_avail <= 0) {
1926c09f92d2SPeter Avalos *buff = NULL;
1927c09f92d2SPeter Avalos *size = 0;
1928c09f92d2SPeter Avalos *offset = 0;
1929c09f92d2SPeter Avalos if (bytes_avail == 0 &&
1930c09f92d2SPeter Avalos cab->entry_cfdata->uncompressed_size == 0) {
1931c09f92d2SPeter Avalos /* All of CFDATA in a folder has been handled. */
1932c09f92d2SPeter Avalos archive_set_error(&a->archive,
1933c09f92d2SPeter Avalos ARCHIVE_ERRNO_FILE_FORMAT, "Invalid CFDATA");
1934c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1935c09f92d2SPeter Avalos } else
1936d4d8193eSPeter Avalos return ((int)bytes_avail);
1937c09f92d2SPeter Avalos }
1938c09f92d2SPeter Avalos if (bytes_avail > cab->entry_bytes_remaining)
193959bf7050SPeter Avalos bytes_avail = (ssize_t)cab->entry_bytes_remaining;
1940c09f92d2SPeter Avalos
1941c09f92d2SPeter Avalos *size = bytes_avail;
1942c09f92d2SPeter Avalos *offset = cab->entry_offset;
1943c09f92d2SPeter Avalos cab->entry_offset += bytes_avail;
1944c09f92d2SPeter Avalos cab->entry_bytes_remaining -= bytes_avail;
1945c09f92d2SPeter Avalos if (cab->entry_bytes_remaining == 0)
1946c09f92d2SPeter Avalos cab->end_of_entry = 1;
1947c09f92d2SPeter Avalos cab->entry_unconsumed = bytes_avail;
194859bf7050SPeter Avalos if (cab->entry_cffolder->comptype == COMPTYPE_NONE) {
194959bf7050SPeter Avalos /* Don't consume more than current entry used. */
195059bf7050SPeter Avalos if (cab->entry_cfdata->unconsumed > cab->entry_unconsumed)
195159bf7050SPeter Avalos cab->entry_cfdata->unconsumed = cab->entry_unconsumed;
195259bf7050SPeter Avalos }
1953c09f92d2SPeter Avalos return (ARCHIVE_OK);
1954c09f92d2SPeter Avalos }
1955c09f92d2SPeter Avalos
1956c09f92d2SPeter Avalos static int
archive_read_format_cab_read_data_skip(struct archive_read * a)1957c09f92d2SPeter Avalos archive_read_format_cab_read_data_skip(struct archive_read *a)
1958c09f92d2SPeter Avalos {
1959c09f92d2SPeter Avalos struct cab *cab;
1960c09f92d2SPeter Avalos int64_t bytes_skipped;
1961c09f92d2SPeter Avalos int r;
1962c09f92d2SPeter Avalos
1963c09f92d2SPeter Avalos cab = (struct cab *)(a->format->data);
1964c09f92d2SPeter Avalos
1965c09f92d2SPeter Avalos if (cab->end_of_archive)
1966c09f92d2SPeter Avalos return (ARCHIVE_EOF);
1967c09f92d2SPeter Avalos
196859bf7050SPeter Avalos if (!cab->read_data_invoked) {
196959bf7050SPeter Avalos cab->bytes_skipped += cab->entry_bytes_remaining;
197059bf7050SPeter Avalos cab->entry_bytes_remaining = 0;
197159bf7050SPeter Avalos /* This entry is finished and done. */
197259bf7050SPeter Avalos cab->end_of_entry_cleanup = cab->end_of_entry = 1;
197359bf7050SPeter Avalos return (ARCHIVE_OK);
197459bf7050SPeter Avalos }
197559bf7050SPeter Avalos
1976c09f92d2SPeter Avalos if (cab->entry_unconsumed) {
1977c09f92d2SPeter Avalos /* Consume as much as the compressor actually used. */
197859bf7050SPeter Avalos r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);
1979c09f92d2SPeter Avalos cab->entry_unconsumed = 0;
1980c09f92d2SPeter Avalos if (r < 0)
1981c09f92d2SPeter Avalos return (r);
1982c09f92d2SPeter Avalos } else if (cab->entry_cfdata == NULL) {
1983c09f92d2SPeter Avalos r = cab_next_cfdata(a);
1984c09f92d2SPeter Avalos if (r < 0)
1985c09f92d2SPeter Avalos return (r);
1986c09f92d2SPeter Avalos }
1987c09f92d2SPeter Avalos
1988c09f92d2SPeter Avalos /* if we've already read to end of data, we're done. */
1989c09f92d2SPeter Avalos if (cab->end_of_entry_cleanup)
1990c09f92d2SPeter Avalos return (ARCHIVE_OK);
1991c09f92d2SPeter Avalos
1992c09f92d2SPeter Avalos /*
1993c09f92d2SPeter Avalos * If the length is at the beginning, we can skip the
1994c09f92d2SPeter Avalos * compressed data much more quickly.
1995c09f92d2SPeter Avalos */
1996c09f92d2SPeter Avalos bytes_skipped = cab_consume_cfdata(a, cab->entry_bytes_remaining);
1997c09f92d2SPeter Avalos if (bytes_skipped < 0)
1998c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1999c09f92d2SPeter Avalos
200059bf7050SPeter Avalos /* If the compression type is none(uncompressed), we've already
200159bf7050SPeter Avalos * consumed data as much as the current entry size. */
2002d4d8193eSPeter Avalos if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&
2003d4d8193eSPeter Avalos cab->entry_cfdata != NULL)
200459bf7050SPeter Avalos cab->entry_cfdata->unconsumed = 0;
200559bf7050SPeter Avalos
2006c09f92d2SPeter Avalos /* This entry is finished and done. */
2007c09f92d2SPeter Avalos cab->end_of_entry_cleanup = cab->end_of_entry = 1;
2008c09f92d2SPeter Avalos return (ARCHIVE_OK);
2009c09f92d2SPeter Avalos }
2010c09f92d2SPeter Avalos
2011c09f92d2SPeter Avalos static int
archive_read_format_cab_cleanup(struct archive_read * a)2012c09f92d2SPeter Avalos archive_read_format_cab_cleanup(struct archive_read *a)
2013c09f92d2SPeter Avalos {
2014c09f92d2SPeter Avalos struct cab *cab = (struct cab *)(a->format->data);
2015c09f92d2SPeter Avalos struct cfheader *hd = &cab->cfheader;
2016c09f92d2SPeter Avalos int i;
2017c09f92d2SPeter Avalos
2018c09f92d2SPeter Avalos if (hd->folder_array != NULL) {
2019c09f92d2SPeter Avalos for (i = 0; i < hd->folder_count; i++)
2020c09f92d2SPeter Avalos free(hd->folder_array[i].cfdata.memimage);
2021c09f92d2SPeter Avalos free(hd->folder_array);
2022c09f92d2SPeter Avalos }
2023c09f92d2SPeter Avalos if (hd->file_array != NULL) {
2024c09f92d2SPeter Avalos for (i = 0; i < cab->cfheader.file_count; i++)
2025c09f92d2SPeter Avalos archive_string_free(&(hd->file_array[i].pathname));
2026c09f92d2SPeter Avalos free(hd->file_array);
2027c09f92d2SPeter Avalos }
2028c09f92d2SPeter Avalos #ifdef HAVE_ZLIB_H
2029c09f92d2SPeter Avalos if (cab->stream_valid)
2030c09f92d2SPeter Avalos inflateEnd(&cab->stream);
2031c09f92d2SPeter Avalos #endif
2032c09f92d2SPeter Avalos lzx_decode_free(&cab->xstrm);
2033c09f92d2SPeter Avalos archive_wstring_free(&cab->ws);
2034c09f92d2SPeter Avalos free(cab->uncompressed_buffer);
2035c09f92d2SPeter Avalos free(cab);
2036c09f92d2SPeter Avalos (a->format->data) = NULL;
2037c09f92d2SPeter Avalos return (ARCHIVE_OK);
2038c09f92d2SPeter Avalos }
2039c09f92d2SPeter Avalos
2040c09f92d2SPeter Avalos /* Convert an MSDOS-style date/time into Unix-style time. */
2041c09f92d2SPeter Avalos static time_t
cab_dos_time(const unsigned char * p)2042c09f92d2SPeter Avalos cab_dos_time(const unsigned char *p)
2043c09f92d2SPeter Avalos {
2044c09f92d2SPeter Avalos int msTime, msDate;
2045c09f92d2SPeter Avalos struct tm ts;
2046c09f92d2SPeter Avalos
2047c09f92d2SPeter Avalos msDate = archive_le16dec(p);
2048c09f92d2SPeter Avalos msTime = archive_le16dec(p+2);
2049c09f92d2SPeter Avalos
2050c09f92d2SPeter Avalos memset(&ts, 0, sizeof(ts));
2051c09f92d2SPeter Avalos ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
2052c09f92d2SPeter Avalos ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
2053c09f92d2SPeter Avalos ts.tm_mday = msDate & 0x1f; /* Day of month. */
2054c09f92d2SPeter Avalos ts.tm_hour = (msTime >> 11) & 0x1f;
2055c09f92d2SPeter Avalos ts.tm_min = (msTime >> 5) & 0x3f;
2056c09f92d2SPeter Avalos ts.tm_sec = (msTime << 1) & 0x3e;
2057c09f92d2SPeter Avalos ts.tm_isdst = -1;
2058c09f92d2SPeter Avalos return (mktime(&ts));
2059c09f92d2SPeter Avalos }
2060c09f92d2SPeter Avalos
2061c09f92d2SPeter Avalos /*****************************************************************
2062c09f92d2SPeter Avalos *
2063c09f92d2SPeter Avalos * LZX decompression code.
2064c09f92d2SPeter Avalos *
2065c09f92d2SPeter Avalos *****************************************************************/
2066c09f92d2SPeter Avalos
2067c09f92d2SPeter Avalos /*
2068c09f92d2SPeter Avalos * Initialize LZX decoder.
2069c09f92d2SPeter Avalos *
2070c09f92d2SPeter Avalos * Returns ARCHIVE_OK if initialization was successful.
2071c09f92d2SPeter Avalos * Returns ARCHIVE_FAILED if w_bits has unsupported value.
2072c09f92d2SPeter Avalos * Returns ARCHIVE_FATAL if initialization failed; memory allocation
2073c09f92d2SPeter Avalos * error occurred.
2074c09f92d2SPeter Avalos */
2075c09f92d2SPeter Avalos static int
lzx_decode_init(struct lzx_stream * strm,int w_bits)2076c09f92d2SPeter Avalos lzx_decode_init(struct lzx_stream *strm, int w_bits)
2077c09f92d2SPeter Avalos {
2078c09f92d2SPeter Avalos struct lzx_dec *ds;
2079c09f92d2SPeter Avalos int slot, w_size, w_slot;
2080c09f92d2SPeter Avalos int base, footer;
208159bf7050SPeter Avalos int base_inc[18];
2082c09f92d2SPeter Avalos
2083c09f92d2SPeter Avalos if (strm->ds == NULL) {
2084c09f92d2SPeter Avalos strm->ds = calloc(1, sizeof(*strm->ds));
2085c09f92d2SPeter Avalos if (strm->ds == NULL)
2086c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2087c09f92d2SPeter Avalos }
2088c09f92d2SPeter Avalos ds = strm->ds;
2089c09f92d2SPeter Avalos ds->error = ARCHIVE_FAILED;
2090c09f92d2SPeter Avalos
2091c09f92d2SPeter Avalos /* Allow bits from 15(32KBi) up to 21(2MBi) */
2092c09f92d2SPeter Avalos if (w_bits < SLOT_BASE || w_bits > SLOT_MAX)
2093c09f92d2SPeter Avalos return (ARCHIVE_FAILED);
2094c09f92d2SPeter Avalos
2095c09f92d2SPeter Avalos ds->error = ARCHIVE_FATAL;
2096c09f92d2SPeter Avalos
2097c09f92d2SPeter Avalos /*
2098c09f92d2SPeter Avalos * Alloc window
2099c09f92d2SPeter Avalos */
2100c09f92d2SPeter Avalos w_size = ds->w_size;
2101c09f92d2SPeter Avalos w_slot = slots[w_bits - SLOT_BASE];
2102c09f92d2SPeter Avalos ds->w_size = 1U << w_bits;
2103c09f92d2SPeter Avalos ds->w_mask = ds->w_size -1;
2104c09f92d2SPeter Avalos if (ds->w_buff == NULL || w_size != ds->w_size) {
2105c09f92d2SPeter Avalos free(ds->w_buff);
2106c09f92d2SPeter Avalos ds->w_buff = malloc(ds->w_size);
2107c09f92d2SPeter Avalos if (ds->w_buff == NULL)
2108c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2109c09f92d2SPeter Avalos free(ds->pos_tbl);
2110c09f92d2SPeter Avalos ds->pos_tbl = malloc(sizeof(ds->pos_tbl[0]) * w_slot);
2111c09f92d2SPeter Avalos if (ds->pos_tbl == NULL)
2112c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2113c09f92d2SPeter Avalos }
2114c09f92d2SPeter Avalos
211559bf7050SPeter Avalos for (footer = 0; footer < 18; footer++)
211659bf7050SPeter Avalos base_inc[footer] = 1 << footer;
2117c09f92d2SPeter Avalos base = footer = 0;
2118c09f92d2SPeter Avalos for (slot = 0; slot < w_slot; slot++) {
2119c09f92d2SPeter Avalos int n;
2120c09f92d2SPeter Avalos if (footer == 0)
2121c09f92d2SPeter Avalos base = slot;
2122c09f92d2SPeter Avalos else
212359bf7050SPeter Avalos base += base_inc[footer];
2124c09f92d2SPeter Avalos if (footer < 17) {
2125c09f92d2SPeter Avalos footer = -2;
2126c09f92d2SPeter Avalos for (n = base; n; n >>= 1)
2127c09f92d2SPeter Avalos footer++;
2128c09f92d2SPeter Avalos if (footer <= 0)
2129c09f92d2SPeter Avalos footer = 0;
2130c09f92d2SPeter Avalos }
2131c09f92d2SPeter Avalos ds->pos_tbl[slot].base = base;
2132c09f92d2SPeter Avalos ds->pos_tbl[slot].footer_bits = footer;
2133c09f92d2SPeter Avalos }
2134c09f92d2SPeter Avalos
2135c09f92d2SPeter Avalos ds->w_pos = 0;
2136c09f92d2SPeter Avalos ds->state = 0;
2137c09f92d2SPeter Avalos ds->br.cache_buffer = 0;
2138c09f92d2SPeter Avalos ds->br.cache_avail = 0;
2139c09f92d2SPeter Avalos ds->r0 = ds->r1 = ds->r2 = 1;
2140c09f92d2SPeter Avalos
2141c09f92d2SPeter Avalos /* Initialize aligned offset tree. */
2142c09f92d2SPeter Avalos if (lzx_huffman_init(&(ds->at), 8, 8) != ARCHIVE_OK)
2143c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2144c09f92d2SPeter Avalos
2145c09f92d2SPeter Avalos /* Initialize pre-tree. */
2146c09f92d2SPeter Avalos if (lzx_huffman_init(&(ds->pt), 20, 10) != ARCHIVE_OK)
2147c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2148c09f92d2SPeter Avalos
2149c09f92d2SPeter Avalos /* Initialize Main tree. */
2150c09f92d2SPeter Avalos if (lzx_huffman_init(&(ds->mt), 256+(w_slot<<3), 16)
2151c09f92d2SPeter Avalos != ARCHIVE_OK)
2152c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2153c09f92d2SPeter Avalos
2154c09f92d2SPeter Avalos /* Initialize Length tree. */
2155c09f92d2SPeter Avalos if (lzx_huffman_init(&(ds->lt), 249, 16) != ARCHIVE_OK)
2156c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2157c09f92d2SPeter Avalos
2158c09f92d2SPeter Avalos ds->error = 0;
2159c09f92d2SPeter Avalos
2160c09f92d2SPeter Avalos return (ARCHIVE_OK);
2161c09f92d2SPeter Avalos }
2162c09f92d2SPeter Avalos
2163c09f92d2SPeter Avalos /*
2164c09f92d2SPeter Avalos * Release LZX decoder.
2165c09f92d2SPeter Avalos */
2166c09f92d2SPeter Avalos static void
lzx_decode_free(struct lzx_stream * strm)2167c09f92d2SPeter Avalos lzx_decode_free(struct lzx_stream *strm)
2168c09f92d2SPeter Avalos {
2169c09f92d2SPeter Avalos
2170c09f92d2SPeter Avalos if (strm->ds == NULL)
2171c09f92d2SPeter Avalos return;
2172c09f92d2SPeter Avalos free(strm->ds->w_buff);
2173c09f92d2SPeter Avalos free(strm->ds->pos_tbl);
2174c09f92d2SPeter Avalos lzx_huffman_free(&(strm->ds->at));
2175c09f92d2SPeter Avalos lzx_huffman_free(&(strm->ds->pt));
2176c09f92d2SPeter Avalos lzx_huffman_free(&(strm->ds->mt));
2177c09f92d2SPeter Avalos lzx_huffman_free(&(strm->ds->lt));
2178c09f92d2SPeter Avalos free(strm->ds);
2179c09f92d2SPeter Avalos strm->ds = NULL;
2180c09f92d2SPeter Avalos }
2181c09f92d2SPeter Avalos
2182c09f92d2SPeter Avalos /*
2183c09f92d2SPeter Avalos * E8 Call Translation reversal.
2184c09f92d2SPeter Avalos */
2185c09f92d2SPeter Avalos static void
lzx_translation(struct lzx_stream * strm,void * p,size_t size,uint32_t offset)2186c09f92d2SPeter Avalos lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)
2187c09f92d2SPeter Avalos {
2188c09f92d2SPeter Avalos struct lzx_dec *ds = strm->ds;
2189c09f92d2SPeter Avalos unsigned char *b, *end;
2190c09f92d2SPeter Avalos
2191c09f92d2SPeter Avalos if (!ds->translation || size <= 10)
2192c09f92d2SPeter Avalos return;
2193c09f92d2SPeter Avalos b = p;
2194c09f92d2SPeter Avalos end = b + size - 10;
2195c09f92d2SPeter Avalos while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {
2196c09f92d2SPeter Avalos size_t i = b - (unsigned char *)p;
219759bf7050SPeter Avalos int32_t cp, displacement, value;
2198c09f92d2SPeter Avalos
2199d4d8193eSPeter Avalos cp = (int32_t)(offset + (uint32_t)i);
2200c09f92d2SPeter Avalos value = archive_le32dec(&b[1]);
220159bf7050SPeter Avalos if (value >= -cp && value < (int32_t)ds->translation_size) {
2202c09f92d2SPeter Avalos if (value >= 0)
2203c09f92d2SPeter Avalos displacement = value - cp;
2204c09f92d2SPeter Avalos else
2205c09f92d2SPeter Avalos displacement = value + ds->translation_size;
2206c09f92d2SPeter Avalos archive_le32enc(&b[1], (uint32_t)displacement);
2207c09f92d2SPeter Avalos }
2208c09f92d2SPeter Avalos b += 5;
2209c09f92d2SPeter Avalos }
2210c09f92d2SPeter Avalos }
2211c09f92d2SPeter Avalos
2212c09f92d2SPeter Avalos /*
2213c09f92d2SPeter Avalos * Bit stream reader.
2214c09f92d2SPeter Avalos */
2215c09f92d2SPeter Avalos /* Check that the cache buffer has enough bits. */
2216c09f92d2SPeter Avalos #define lzx_br_has(br, n) ((br)->cache_avail >= n)
2217c09f92d2SPeter Avalos /* Get compressed data by bit. */
2218c09f92d2SPeter Avalos #define lzx_br_bits(br, n) \
2219c09f92d2SPeter Avalos (((uint32_t)((br)->cache_buffer >> \
2220c09f92d2SPeter Avalos ((br)->cache_avail - (n)))) & cache_masks[n])
2221c09f92d2SPeter Avalos #define lzx_br_bits_forced(br, n) \
2222c09f92d2SPeter Avalos (((uint32_t)((br)->cache_buffer << \
2223c09f92d2SPeter Avalos ((n) - (br)->cache_avail))) & cache_masks[n])
2224c09f92d2SPeter Avalos /* Read ahead to make sure the cache buffer has enough compressed data we
2225c09f92d2SPeter Avalos * will use.
2226c09f92d2SPeter Avalos * True : completed, there is enough data in the cache buffer.
2227c09f92d2SPeter Avalos * False : we met that strm->next_in is empty, we have to get following
2228c09f92d2SPeter Avalos * bytes. */
2229c09f92d2SPeter Avalos #define lzx_br_read_ahead_0(strm, br, n) \
2230c09f92d2SPeter Avalos (lzx_br_has((br), (n)) || lzx_br_fillup(strm, br))
2231c09f92d2SPeter Avalos /* True : the cache buffer has some bits as much as we need.
2232c09f92d2SPeter Avalos * False : there are no enough bits in the cache buffer to be used,
2233c09f92d2SPeter Avalos * we have to get following bytes if we could. */
2234c09f92d2SPeter Avalos #define lzx_br_read_ahead(strm, br, n) \
2235c09f92d2SPeter Avalos (lzx_br_read_ahead_0((strm), (br), (n)) || lzx_br_has((br), (n)))
2236c09f92d2SPeter Avalos
2237c09f92d2SPeter Avalos /* Notify how many bits we consumed. */
2238c09f92d2SPeter Avalos #define lzx_br_consume(br, n) ((br)->cache_avail -= (n))
223959bf7050SPeter Avalos #define lzx_br_consume_unaligned_bits(br) ((br)->cache_avail &= ~0x0f)
224059bf7050SPeter Avalos
224159bf7050SPeter Avalos #define lzx_br_is_unaligned(br) ((br)->cache_avail & 0x0f)
2242c09f92d2SPeter Avalos
2243c09f92d2SPeter Avalos static const uint32_t cache_masks[] = {
2244c09f92d2SPeter Avalos 0x00000000, 0x00000001, 0x00000003, 0x00000007,
2245c09f92d2SPeter Avalos 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
2246c09f92d2SPeter Avalos 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,
2247c09f92d2SPeter Avalos 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,
2248c09f92d2SPeter Avalos 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,
2249c09f92d2SPeter Avalos 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
2250c09f92d2SPeter Avalos 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
2251c09f92d2SPeter Avalos 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,
2252c09f92d2SPeter Avalos 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
2253c09f92d2SPeter Avalos };
2254c09f92d2SPeter Avalos
2255c09f92d2SPeter Avalos /*
2256c09f92d2SPeter Avalos * Shift away used bits in the cache data and fill it up with following bits.
2257c09f92d2SPeter Avalos * Call this when cache buffer does not have enough bits you need.
2258c09f92d2SPeter Avalos *
2259c09f92d2SPeter Avalos * Returns 1 if the cache buffer is full.
2260c09f92d2SPeter Avalos * Returns 0 if the cache buffer is not full; input buffer is empty.
2261c09f92d2SPeter Avalos */
2262c09f92d2SPeter Avalos static int
lzx_br_fillup(struct lzx_stream * strm,struct lzx_br * br)2263c09f92d2SPeter Avalos lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
2264c09f92d2SPeter Avalos {
2265c09f92d2SPeter Avalos /*
2266e95abc47Szrj * x86 processor family can read misaligned data without an access error.
2267c09f92d2SPeter Avalos */
2268c09f92d2SPeter Avalos int n = CACHE_BITS - br->cache_avail;
2269c09f92d2SPeter Avalos
2270c09f92d2SPeter Avalos for (;;) {
2271c09f92d2SPeter Avalos switch (n >> 4) {
2272c09f92d2SPeter Avalos case 4:
2273c09f92d2SPeter Avalos if (strm->avail_in >= 8) {
2274c09f92d2SPeter Avalos br->cache_buffer =
2275c09f92d2SPeter Avalos ((uint64_t)strm->next_in[1]) << 56 |
2276c09f92d2SPeter Avalos ((uint64_t)strm->next_in[0]) << 48 |
2277c09f92d2SPeter Avalos ((uint64_t)strm->next_in[3]) << 40 |
2278c09f92d2SPeter Avalos ((uint64_t)strm->next_in[2]) << 32 |
2279c09f92d2SPeter Avalos ((uint32_t)strm->next_in[5]) << 24 |
2280c09f92d2SPeter Avalos ((uint32_t)strm->next_in[4]) << 16 |
2281c09f92d2SPeter Avalos ((uint32_t)strm->next_in[7]) << 8 |
2282c09f92d2SPeter Avalos (uint32_t)strm->next_in[6];
2283c09f92d2SPeter Avalos strm->next_in += 8;
2284c09f92d2SPeter Avalos strm->avail_in -= 8;
2285c09f92d2SPeter Avalos br->cache_avail += 8 * 8;
2286c09f92d2SPeter Avalos return (1);
2287c09f92d2SPeter Avalos }
2288c09f92d2SPeter Avalos break;
2289c09f92d2SPeter Avalos case 3:
2290c09f92d2SPeter Avalos if (strm->avail_in >= 6) {
2291c09f92d2SPeter Avalos br->cache_buffer =
2292c09f92d2SPeter Avalos (br->cache_buffer << 48) |
2293c09f92d2SPeter Avalos ((uint64_t)strm->next_in[1]) << 40 |
2294c09f92d2SPeter Avalos ((uint64_t)strm->next_in[0]) << 32 |
2295c09f92d2SPeter Avalos ((uint32_t)strm->next_in[3]) << 24 |
2296c09f92d2SPeter Avalos ((uint32_t)strm->next_in[2]) << 16 |
2297c09f92d2SPeter Avalos ((uint32_t)strm->next_in[5]) << 8 |
2298c09f92d2SPeter Avalos (uint32_t)strm->next_in[4];
2299c09f92d2SPeter Avalos strm->next_in += 6;
2300c09f92d2SPeter Avalos strm->avail_in -= 6;
2301c09f92d2SPeter Avalos br->cache_avail += 6 * 8;
2302c09f92d2SPeter Avalos return (1);
2303c09f92d2SPeter Avalos }
2304c09f92d2SPeter Avalos break;
2305c09f92d2SPeter Avalos case 0:
2306c09f92d2SPeter Avalos /* We have enough compressed data in
2307c09f92d2SPeter Avalos * the cache buffer.*/
2308c09f92d2SPeter Avalos return (1);
2309c09f92d2SPeter Avalos default:
2310c09f92d2SPeter Avalos break;
2311c09f92d2SPeter Avalos }
2312c09f92d2SPeter Avalos if (strm->avail_in < 2) {
2313c09f92d2SPeter Avalos /* There is not enough compressed data to
2314c09f92d2SPeter Avalos * fill up the cache buffer. */
2315c09f92d2SPeter Avalos if (strm->avail_in == 1) {
2316c09f92d2SPeter Avalos br->odd = *strm->next_in++;
2317c09f92d2SPeter Avalos strm->avail_in--;
2318c09f92d2SPeter Avalos br->have_odd = 1;
2319c09f92d2SPeter Avalos }
2320c09f92d2SPeter Avalos return (0);
2321c09f92d2SPeter Avalos }
2322c09f92d2SPeter Avalos br->cache_buffer =
2323c09f92d2SPeter Avalos (br->cache_buffer << 16) |
2324c09f92d2SPeter Avalos archive_le16dec(strm->next_in);
2325c09f92d2SPeter Avalos strm->next_in += 2;
2326c09f92d2SPeter Avalos strm->avail_in -= 2;
2327c09f92d2SPeter Avalos br->cache_avail += 16;
2328c09f92d2SPeter Avalos n -= 16;
2329c09f92d2SPeter Avalos }
2330c09f92d2SPeter Avalos }
2331c09f92d2SPeter Avalos
2332c09f92d2SPeter Avalos static void
lzx_br_fixup(struct lzx_stream * strm,struct lzx_br * br)2333c09f92d2SPeter Avalos lzx_br_fixup(struct lzx_stream *strm, struct lzx_br *br)
2334c09f92d2SPeter Avalos {
2335c09f92d2SPeter Avalos int n = CACHE_BITS - br->cache_avail;
2336c09f92d2SPeter Avalos
2337c09f92d2SPeter Avalos if (br->have_odd && n >= 16 && strm->avail_in > 0) {
2338c09f92d2SPeter Avalos br->cache_buffer =
2339c09f92d2SPeter Avalos (br->cache_buffer << 16) |
2340c09f92d2SPeter Avalos ((uint16_t)(*strm->next_in)) << 8 | br->odd;
2341c09f92d2SPeter Avalos strm->next_in++;
2342c09f92d2SPeter Avalos strm->avail_in--;
2343c09f92d2SPeter Avalos br->cache_avail += 16;
2344c09f92d2SPeter Avalos br->have_odd = 0;
2345c09f92d2SPeter Avalos }
2346c09f92d2SPeter Avalos }
2347c09f92d2SPeter Avalos
2348c09f92d2SPeter Avalos static void
lzx_cleanup_bitstream(struct lzx_stream * strm)2349c09f92d2SPeter Avalos lzx_cleanup_bitstream(struct lzx_stream *strm)
2350c09f92d2SPeter Avalos {
2351c09f92d2SPeter Avalos strm->ds->br.cache_avail = 0;
2352c09f92d2SPeter Avalos strm->ds->br.have_odd = 0;
2353c09f92d2SPeter Avalos }
2354c09f92d2SPeter Avalos
2355c09f92d2SPeter Avalos /*
2356c09f92d2SPeter Avalos * Decode LZX.
2357c09f92d2SPeter Avalos *
2358c09f92d2SPeter Avalos * 1. Returns ARCHIVE_OK if output buffer or input buffer are empty.
2359c09f92d2SPeter Avalos * Please set available buffer and call this function again.
2360c09f92d2SPeter Avalos * 2. Returns ARCHIVE_EOF if decompression has been completed.
2361c09f92d2SPeter Avalos * 3. Returns ARCHIVE_FAILED if an error occurred; compressed data
2362c09f92d2SPeter Avalos * is broken or you do not set 'last' flag properly.
2363c09f92d2SPeter Avalos */
2364c09f92d2SPeter Avalos #define ST_RD_TRANSLATION 0
2365c09f92d2SPeter Avalos #define ST_RD_TRANSLATION_SIZE 1
2366c09f92d2SPeter Avalos #define ST_RD_BLOCK_TYPE 2
2367c09f92d2SPeter Avalos #define ST_RD_BLOCK_SIZE 3
236859bf7050SPeter Avalos #define ST_RD_ALIGNMENT 4
236959bf7050SPeter Avalos #define ST_RD_R0 5
237059bf7050SPeter Avalos #define ST_RD_R1 6
237159bf7050SPeter Avalos #define ST_RD_R2 7
237259bf7050SPeter Avalos #define ST_COPY_UNCOMP1 8
237359bf7050SPeter Avalos #define ST_COPY_UNCOMP2 9
237459bf7050SPeter Avalos #define ST_RD_ALIGNED_OFFSET 10
237559bf7050SPeter Avalos #define ST_RD_VERBATIM 11
237659bf7050SPeter Avalos #define ST_RD_PRE_MAIN_TREE_256 12
237759bf7050SPeter Avalos #define ST_MAIN_TREE_256 13
237859bf7050SPeter Avalos #define ST_RD_PRE_MAIN_TREE_REM 14
237959bf7050SPeter Avalos #define ST_MAIN_TREE_REM 15
238059bf7050SPeter Avalos #define ST_RD_PRE_LENGTH_TREE 16
238159bf7050SPeter Avalos #define ST_LENGTH_TREE 17
238259bf7050SPeter Avalos #define ST_MAIN 18
238359bf7050SPeter Avalos #define ST_LENGTH 19
238459bf7050SPeter Avalos #define ST_OFFSET 20
238559bf7050SPeter Avalos #define ST_REAL_POS 21
238659bf7050SPeter Avalos #define ST_COPY 22
2387c09f92d2SPeter Avalos
2388c09f92d2SPeter Avalos static int
lzx_decode(struct lzx_stream * strm,int last)2389c09f92d2SPeter Avalos lzx_decode(struct lzx_stream *strm, int last)
2390c09f92d2SPeter Avalos {
2391c09f92d2SPeter Avalos struct lzx_dec *ds = strm->ds;
2392c09f92d2SPeter Avalos int64_t avail_in;
2393c09f92d2SPeter Avalos int r;
2394c09f92d2SPeter Avalos
2395c09f92d2SPeter Avalos if (ds->error)
2396c09f92d2SPeter Avalos return (ds->error);
2397c09f92d2SPeter Avalos
2398c09f92d2SPeter Avalos avail_in = strm->avail_in;
2399c09f92d2SPeter Avalos lzx_br_fixup(strm, &(ds->br));
2400c09f92d2SPeter Avalos do {
2401c09f92d2SPeter Avalos if (ds->state < ST_MAIN)
2402c09f92d2SPeter Avalos r = lzx_read_blocks(strm, last);
2403c09f92d2SPeter Avalos else {
2404c09f92d2SPeter Avalos int64_t bytes_written = strm->avail_out;
2405c09f92d2SPeter Avalos r = lzx_decode_blocks(strm, last);
2406c09f92d2SPeter Avalos bytes_written -= strm->avail_out;
2407c09f92d2SPeter Avalos strm->next_out += bytes_written;
2408c09f92d2SPeter Avalos strm->total_out += bytes_written;
2409c09f92d2SPeter Avalos }
2410c09f92d2SPeter Avalos } while (r == 100);
2411c09f92d2SPeter Avalos strm->total_in += avail_in - strm->avail_in;
2412c09f92d2SPeter Avalos return (r);
2413c09f92d2SPeter Avalos }
2414c09f92d2SPeter Avalos
2415c09f92d2SPeter Avalos static int
lzx_read_blocks(struct lzx_stream * strm,int last)2416c09f92d2SPeter Avalos lzx_read_blocks(struct lzx_stream *strm, int last)
2417c09f92d2SPeter Avalos {
2418c09f92d2SPeter Avalos struct lzx_dec *ds = strm->ds;
2419c09f92d2SPeter Avalos struct lzx_br *br = &(ds->br);
2420c09f92d2SPeter Avalos int i, r;
2421c09f92d2SPeter Avalos
2422c09f92d2SPeter Avalos for (;;) {
2423c09f92d2SPeter Avalos switch (ds->state) {
2424c09f92d2SPeter Avalos case ST_RD_TRANSLATION:
2425c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, br, 1)) {
2426c09f92d2SPeter Avalos ds->state = ST_RD_TRANSLATION;
2427c09f92d2SPeter Avalos if (last)
2428c09f92d2SPeter Avalos goto failed;
2429c09f92d2SPeter Avalos return (ARCHIVE_OK);
2430c09f92d2SPeter Avalos }
2431c09f92d2SPeter Avalos ds->translation = lzx_br_bits(br, 1);
2432c09f92d2SPeter Avalos lzx_br_consume(br, 1);
2433c09f92d2SPeter Avalos /* FALL THROUGH */
2434c09f92d2SPeter Avalos case ST_RD_TRANSLATION_SIZE:
2435c09f92d2SPeter Avalos if (ds->translation) {
2436c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, br, 32)) {
2437c09f92d2SPeter Avalos ds->state = ST_RD_TRANSLATION_SIZE;
2438c09f92d2SPeter Avalos if (last)
2439c09f92d2SPeter Avalos goto failed;
2440c09f92d2SPeter Avalos return (ARCHIVE_OK);
2441c09f92d2SPeter Avalos }
2442c09f92d2SPeter Avalos ds->translation_size = lzx_br_bits(br, 16);
2443c09f92d2SPeter Avalos lzx_br_consume(br, 16);
2444c09f92d2SPeter Avalos ds->translation_size <<= 16;
2445c09f92d2SPeter Avalos ds->translation_size |= lzx_br_bits(br, 16);
2446c09f92d2SPeter Avalos lzx_br_consume(br, 16);
2447c09f92d2SPeter Avalos }
2448c09f92d2SPeter Avalos /* FALL THROUGH */
2449c09f92d2SPeter Avalos case ST_RD_BLOCK_TYPE:
2450c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, br, 3)) {
2451c09f92d2SPeter Avalos ds->state = ST_RD_BLOCK_TYPE;
2452c09f92d2SPeter Avalos if (last)
2453c09f92d2SPeter Avalos goto failed;
2454c09f92d2SPeter Avalos return (ARCHIVE_OK);
2455c09f92d2SPeter Avalos }
2456c09f92d2SPeter Avalos ds->block_type = lzx_br_bits(br, 3);
2457c09f92d2SPeter Avalos lzx_br_consume(br, 3);
2458c09f92d2SPeter Avalos /* Check a block type. */
2459c09f92d2SPeter Avalos switch (ds->block_type) {
2460c09f92d2SPeter Avalos case VERBATIM_BLOCK:
2461c09f92d2SPeter Avalos case ALIGNED_OFFSET_BLOCK:
2462c09f92d2SPeter Avalos case UNCOMPRESSED_BLOCK:
2463c09f92d2SPeter Avalos break;
2464c09f92d2SPeter Avalos default:
2465c09f92d2SPeter Avalos goto failed;/* Invalid */
2466c09f92d2SPeter Avalos }
2467c09f92d2SPeter Avalos /* FALL THROUGH */
2468c09f92d2SPeter Avalos case ST_RD_BLOCK_SIZE:
2469c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, br, 24)) {
2470c09f92d2SPeter Avalos ds->state = ST_RD_BLOCK_SIZE;
2471c09f92d2SPeter Avalos if (last)
2472c09f92d2SPeter Avalos goto failed;
2473c09f92d2SPeter Avalos return (ARCHIVE_OK);
2474c09f92d2SPeter Avalos }
2475c09f92d2SPeter Avalos ds->block_size = lzx_br_bits(br, 8);
2476c09f92d2SPeter Avalos lzx_br_consume(br, 8);
2477c09f92d2SPeter Avalos ds->block_size <<= 16;
2478c09f92d2SPeter Avalos ds->block_size |= lzx_br_bits(br, 16);
2479c09f92d2SPeter Avalos lzx_br_consume(br, 16);
2480c09f92d2SPeter Avalos if (ds->block_size == 0)
2481c09f92d2SPeter Avalos goto failed;
2482c09f92d2SPeter Avalos ds->block_bytes_avail = ds->block_size;
2483c09f92d2SPeter Avalos if (ds->block_type != UNCOMPRESSED_BLOCK) {
2484c09f92d2SPeter Avalos if (ds->block_type == VERBATIM_BLOCK)
2485c09f92d2SPeter Avalos ds->state = ST_RD_VERBATIM;
2486c09f92d2SPeter Avalos else
2487c09f92d2SPeter Avalos ds->state = ST_RD_ALIGNED_OFFSET;
2488c09f92d2SPeter Avalos break;
2489c09f92d2SPeter Avalos }
249059bf7050SPeter Avalos /* FALL THROUGH */
249159bf7050SPeter Avalos case ST_RD_ALIGNMENT:
2492c09f92d2SPeter Avalos /*
2493c09f92d2SPeter Avalos * Handle an Uncompressed Block.
2494c09f92d2SPeter Avalos */
2495c09f92d2SPeter Avalos /* Skip padding to align following field on
2496c09f92d2SPeter Avalos * 16-bit boundary. */
249759bf7050SPeter Avalos if (lzx_br_is_unaligned(br))
249859bf7050SPeter Avalos lzx_br_consume_unaligned_bits(br);
249959bf7050SPeter Avalos else {
250059bf7050SPeter Avalos if (lzx_br_read_ahead(strm, br, 16))
250159bf7050SPeter Avalos lzx_br_consume(br, 16);
250259bf7050SPeter Avalos else {
250359bf7050SPeter Avalos ds->state = ST_RD_ALIGNMENT;
250459bf7050SPeter Avalos if (last)
250559bf7050SPeter Avalos goto failed;
250659bf7050SPeter Avalos return (ARCHIVE_OK);
250759bf7050SPeter Avalos }
250859bf7050SPeter Avalos }
2509c09f92d2SPeter Avalos /* Preparation to read repeated offsets R0,R1 and R2. */
2510c09f92d2SPeter Avalos ds->rbytes_avail = 0;
2511c09f92d2SPeter Avalos ds->state = ST_RD_R0;
2512c09f92d2SPeter Avalos /* FALL THROUGH */
2513c09f92d2SPeter Avalos case ST_RD_R0:
2514c09f92d2SPeter Avalos case ST_RD_R1:
2515c09f92d2SPeter Avalos case ST_RD_R2:
2516c09f92d2SPeter Avalos do {
2517c09f92d2SPeter Avalos uint16_t u16;
2518c09f92d2SPeter Avalos /* Drain bits in the cache buffer of
2519c09f92d2SPeter Avalos * bit-stream. */
2520c09f92d2SPeter Avalos if (lzx_br_has(br, 32)) {
2521c09f92d2SPeter Avalos u16 = lzx_br_bits(br, 16);
2522c09f92d2SPeter Avalos lzx_br_consume(br, 16);
2523c09f92d2SPeter Avalos archive_le16enc(ds->rbytes, u16);
2524c09f92d2SPeter Avalos u16 = lzx_br_bits(br, 16);
2525c09f92d2SPeter Avalos lzx_br_consume(br, 16);
2526c09f92d2SPeter Avalos archive_le16enc(ds->rbytes+2, u16);
2527c09f92d2SPeter Avalos ds->rbytes_avail = 4;
2528c09f92d2SPeter Avalos } else if (lzx_br_has(br, 16)) {
2529c09f92d2SPeter Avalos u16 = lzx_br_bits(br, 16);
2530c09f92d2SPeter Avalos lzx_br_consume(br, 16);
2531c09f92d2SPeter Avalos archive_le16enc(ds->rbytes, u16);
2532c09f92d2SPeter Avalos ds->rbytes_avail = 2;
253359bf7050SPeter Avalos }
2534c09f92d2SPeter Avalos if (ds->rbytes_avail < 4 && ds->br.have_odd) {
2535c09f92d2SPeter Avalos ds->rbytes[ds->rbytes_avail++] =
2536c09f92d2SPeter Avalos ds->br.odd;
2537c09f92d2SPeter Avalos ds->br.have_odd = 0;
2538c09f92d2SPeter Avalos }
2539c09f92d2SPeter Avalos while (ds->rbytes_avail < 4) {
2540c09f92d2SPeter Avalos if (strm->avail_in <= 0) {
2541c09f92d2SPeter Avalos if (last)
2542c09f92d2SPeter Avalos goto failed;
2543c09f92d2SPeter Avalos return (ARCHIVE_OK);
2544c09f92d2SPeter Avalos }
2545c09f92d2SPeter Avalos ds->rbytes[ds->rbytes_avail++] =
2546c09f92d2SPeter Avalos *strm->next_in++;
2547c09f92d2SPeter Avalos strm->avail_in--;
2548c09f92d2SPeter Avalos }
254959bf7050SPeter Avalos ds->rbytes_avail = 0;
2550c09f92d2SPeter Avalos if (ds->state == ST_RD_R0) {
2551c09f92d2SPeter Avalos ds->r0 = archive_le32dec(ds->rbytes);
2552c09f92d2SPeter Avalos if (ds->r0 < 0)
2553c09f92d2SPeter Avalos goto failed;
2554c09f92d2SPeter Avalos ds->state = ST_RD_R1;
2555c09f92d2SPeter Avalos } else if (ds->state == ST_RD_R1) {
2556c09f92d2SPeter Avalos ds->r1 = archive_le32dec(ds->rbytes);
2557c09f92d2SPeter Avalos if (ds->r1 < 0)
2558c09f92d2SPeter Avalos goto failed;
2559c09f92d2SPeter Avalos ds->state = ST_RD_R2;
2560c09f92d2SPeter Avalos } else if (ds->state == ST_RD_R2) {
2561c09f92d2SPeter Avalos ds->r2 = archive_le32dec(ds->rbytes);
2562c09f92d2SPeter Avalos if (ds->r2 < 0)
2563c09f92d2SPeter Avalos goto failed;
2564c09f92d2SPeter Avalos /* We've gotten all repeated offsets. */
2565c09f92d2SPeter Avalos ds->state = ST_COPY_UNCOMP1;
2566c09f92d2SPeter Avalos }
2567c09f92d2SPeter Avalos } while (ds->state != ST_COPY_UNCOMP1);
2568c09f92d2SPeter Avalos /* FALL THROUGH */
2569c09f92d2SPeter Avalos case ST_COPY_UNCOMP1:
2570c09f92d2SPeter Avalos /*
2571c09f92d2SPeter Avalos * Copy bytes form next_in to next_out directly.
2572c09f92d2SPeter Avalos */
2573c09f92d2SPeter Avalos while (ds->block_bytes_avail) {
257459bf7050SPeter Avalos int l;
2575c09f92d2SPeter Avalos
2576c09f92d2SPeter Avalos if (strm->avail_out <= 0)
2577c09f92d2SPeter Avalos /* Output buffer is empty. */
2578c09f92d2SPeter Avalos return (ARCHIVE_OK);
2579c09f92d2SPeter Avalos if (strm->avail_in <= 0) {
2580c09f92d2SPeter Avalos /* Input buffer is empty. */
2581c09f92d2SPeter Avalos if (last)
2582c09f92d2SPeter Avalos goto failed;
2583c09f92d2SPeter Avalos return (ARCHIVE_OK);
2584c09f92d2SPeter Avalos }
2585d4d8193eSPeter Avalos l = (int)ds->block_bytes_avail;
2586c09f92d2SPeter Avalos if (l > ds->w_size - ds->w_pos)
2587c09f92d2SPeter Avalos l = ds->w_size - ds->w_pos;
2588c09f92d2SPeter Avalos if (l > strm->avail_out)
2589c09f92d2SPeter Avalos l = (int)strm->avail_out;
2590c09f92d2SPeter Avalos if (l > strm->avail_in)
2591c09f92d2SPeter Avalos l = (int)strm->avail_in;
259259bf7050SPeter Avalos memcpy(strm->next_out, strm->next_in, l);
259359bf7050SPeter Avalos memcpy(&(ds->w_buff[ds->w_pos]),
259459bf7050SPeter Avalos strm->next_in, l);
259559bf7050SPeter Avalos strm->next_in += l;
259659bf7050SPeter Avalos strm->avail_in -= l;
259759bf7050SPeter Avalos strm->next_out += l;
259859bf7050SPeter Avalos strm->avail_out -= l;
259959bf7050SPeter Avalos strm->total_out += l;
260059bf7050SPeter Avalos ds->w_pos = (ds->w_pos + l) & ds->w_mask;
260159bf7050SPeter Avalos ds->block_bytes_avail -= l;
2602c09f92d2SPeter Avalos }
2603c09f92d2SPeter Avalos /* FALL THROUGH */
2604c09f92d2SPeter Avalos case ST_COPY_UNCOMP2:
2605c09f92d2SPeter Avalos /* Re-align; skip padding byte. */
2606c09f92d2SPeter Avalos if (ds->block_size & 1) {
2607c09f92d2SPeter Avalos if (strm->avail_in <= 0) {
2608c09f92d2SPeter Avalos /* Input buffer is empty. */
2609c09f92d2SPeter Avalos ds->state = ST_COPY_UNCOMP2;
2610c09f92d2SPeter Avalos if (last)
2611c09f92d2SPeter Avalos goto failed;
2612c09f92d2SPeter Avalos return (ARCHIVE_OK);
2613c09f92d2SPeter Avalos }
2614c09f92d2SPeter Avalos strm->next_in++;
2615c09f92d2SPeter Avalos strm->avail_in --;
2616c09f92d2SPeter Avalos }
2617c09f92d2SPeter Avalos /* This block ended. */
2618c09f92d2SPeter Avalos ds->state = ST_RD_BLOCK_TYPE;
2619c09f92d2SPeter Avalos return (ARCHIVE_EOF);
2620c09f92d2SPeter Avalos /********************/
2621c09f92d2SPeter Avalos case ST_RD_ALIGNED_OFFSET:
2622c09f92d2SPeter Avalos /*
2623c09f92d2SPeter Avalos * Read Aligned offset tree.
2624c09f92d2SPeter Avalos */
2625c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, br, 3 * ds->at.len_size)) {
2626c09f92d2SPeter Avalos ds->state = ST_RD_ALIGNED_OFFSET;
2627c09f92d2SPeter Avalos if (last)
2628c09f92d2SPeter Avalos goto failed;
2629c09f92d2SPeter Avalos return (ARCHIVE_OK);
2630c09f92d2SPeter Avalos }
2631c09f92d2SPeter Avalos memset(ds->at.freq, 0, sizeof(ds->at.freq));
2632c09f92d2SPeter Avalos for (i = 0; i < ds->at.len_size; i++) {
2633c09f92d2SPeter Avalos ds->at.bitlen[i] = lzx_br_bits(br, 3);
2634c09f92d2SPeter Avalos ds->at.freq[ds->at.bitlen[i]]++;
2635c09f92d2SPeter Avalos lzx_br_consume(br, 3);
2636c09f92d2SPeter Avalos }
2637c09f92d2SPeter Avalos if (!lzx_make_huffman_table(&ds->at))
2638c09f92d2SPeter Avalos goto failed;
2639c09f92d2SPeter Avalos /* FALL THROUGH */
2640c09f92d2SPeter Avalos case ST_RD_VERBATIM:
2641c09f92d2SPeter Avalos ds->loop = 0;
2642c09f92d2SPeter Avalos /* FALL THROUGH */
2643c09f92d2SPeter Avalos case ST_RD_PRE_MAIN_TREE_256:
2644c09f92d2SPeter Avalos /*
2645c09f92d2SPeter Avalos * Read Pre-tree for first 256 elements of main tree.
2646c09f92d2SPeter Avalos */
2647c09f92d2SPeter Avalos if (!lzx_read_pre_tree(strm)) {
2648c09f92d2SPeter Avalos ds->state = ST_RD_PRE_MAIN_TREE_256;
2649c09f92d2SPeter Avalos if (last)
2650c09f92d2SPeter Avalos goto failed;
2651c09f92d2SPeter Avalos return (ARCHIVE_OK);
2652c09f92d2SPeter Avalos }
2653c09f92d2SPeter Avalos if (!lzx_make_huffman_table(&ds->pt))
2654c09f92d2SPeter Avalos goto failed;
2655c09f92d2SPeter Avalos ds->loop = 0;
2656c09f92d2SPeter Avalos /* FALL THROUGH */
2657c09f92d2SPeter Avalos case ST_MAIN_TREE_256:
2658c09f92d2SPeter Avalos /*
2659c09f92d2SPeter Avalos * Get path lengths of first 256 elements of main tree.
2660c09f92d2SPeter Avalos */
2661c09f92d2SPeter Avalos r = lzx_read_bitlen(strm, &ds->mt, 256);
2662c09f92d2SPeter Avalos if (r < 0)
2663c09f92d2SPeter Avalos goto failed;
2664c09f92d2SPeter Avalos else if (!r) {
2665c09f92d2SPeter Avalos ds->state = ST_MAIN_TREE_256;
2666c09f92d2SPeter Avalos if (last)
2667c09f92d2SPeter Avalos goto failed;
2668c09f92d2SPeter Avalos return (ARCHIVE_OK);
2669c09f92d2SPeter Avalos }
2670c09f92d2SPeter Avalos ds->loop = 0;
2671c09f92d2SPeter Avalos /* FALL THROUGH */
2672c09f92d2SPeter Avalos case ST_RD_PRE_MAIN_TREE_REM:
2673c09f92d2SPeter Avalos /*
2674c09f92d2SPeter Avalos * Read Pre-tree for remaining elements of main tree.
2675c09f92d2SPeter Avalos */
2676c09f92d2SPeter Avalos if (!lzx_read_pre_tree(strm)) {
2677c09f92d2SPeter Avalos ds->state = ST_RD_PRE_MAIN_TREE_REM;
2678c09f92d2SPeter Avalos if (last)
2679c09f92d2SPeter Avalos goto failed;
2680c09f92d2SPeter Avalos return (ARCHIVE_OK);
2681c09f92d2SPeter Avalos }
2682c09f92d2SPeter Avalos if (!lzx_make_huffman_table(&ds->pt))
2683c09f92d2SPeter Avalos goto failed;
2684c09f92d2SPeter Avalos ds->loop = 256;
2685c09f92d2SPeter Avalos /* FALL THROUGH */
2686c09f92d2SPeter Avalos case ST_MAIN_TREE_REM:
2687c09f92d2SPeter Avalos /*
2688c09f92d2SPeter Avalos * Get path lengths of remaining elements of main tree.
2689c09f92d2SPeter Avalos */
2690c09f92d2SPeter Avalos r = lzx_read_bitlen(strm, &ds->mt, -1);
2691c09f92d2SPeter Avalos if (r < 0)
2692c09f92d2SPeter Avalos goto failed;
2693c09f92d2SPeter Avalos else if (!r) {
2694c09f92d2SPeter Avalos ds->state = ST_MAIN_TREE_REM;
2695c09f92d2SPeter Avalos if (last)
2696c09f92d2SPeter Avalos goto failed;
2697c09f92d2SPeter Avalos return (ARCHIVE_OK);
2698c09f92d2SPeter Avalos }
2699c09f92d2SPeter Avalos if (!lzx_make_huffman_table(&ds->mt))
2700c09f92d2SPeter Avalos goto failed;
2701c09f92d2SPeter Avalos ds->loop = 0;
2702c09f92d2SPeter Avalos /* FALL THROUGH */
2703c09f92d2SPeter Avalos case ST_RD_PRE_LENGTH_TREE:
2704c09f92d2SPeter Avalos /*
2705c09f92d2SPeter Avalos * Read Pre-tree for remaining elements of main tree.
2706c09f92d2SPeter Avalos */
2707c09f92d2SPeter Avalos if (!lzx_read_pre_tree(strm)) {
2708c09f92d2SPeter Avalos ds->state = ST_RD_PRE_LENGTH_TREE;
2709c09f92d2SPeter Avalos if (last)
2710c09f92d2SPeter Avalos goto failed;
2711c09f92d2SPeter Avalos return (ARCHIVE_OK);
2712c09f92d2SPeter Avalos }
2713c09f92d2SPeter Avalos if (!lzx_make_huffman_table(&ds->pt))
2714c09f92d2SPeter Avalos goto failed;
2715c09f92d2SPeter Avalos ds->loop = 0;
2716c09f92d2SPeter Avalos /* FALL THROUGH */
2717c09f92d2SPeter Avalos case ST_LENGTH_TREE:
2718c09f92d2SPeter Avalos /*
2719c09f92d2SPeter Avalos * Get path lengths of remaining elements of main tree.
2720c09f92d2SPeter Avalos */
2721c09f92d2SPeter Avalos r = lzx_read_bitlen(strm, &ds->lt, -1);
2722c09f92d2SPeter Avalos if (r < 0)
2723c09f92d2SPeter Avalos goto failed;
2724c09f92d2SPeter Avalos else if (!r) {
2725c09f92d2SPeter Avalos ds->state = ST_LENGTH_TREE;
2726c09f92d2SPeter Avalos if (last)
2727c09f92d2SPeter Avalos goto failed;
2728c09f92d2SPeter Avalos return (ARCHIVE_OK);
2729c09f92d2SPeter Avalos }
2730c09f92d2SPeter Avalos if (!lzx_make_huffman_table(&ds->lt))
2731c09f92d2SPeter Avalos goto failed;
2732c09f92d2SPeter Avalos ds->state = ST_MAIN;
2733c09f92d2SPeter Avalos return (100);
2734c09f92d2SPeter Avalos }
2735c09f92d2SPeter Avalos }
2736c09f92d2SPeter Avalos failed:
2737c09f92d2SPeter Avalos return (ds->error = ARCHIVE_FAILED);
2738c09f92d2SPeter Avalos }
2739c09f92d2SPeter Avalos
2740c09f92d2SPeter Avalos static int
lzx_decode_blocks(struct lzx_stream * strm,int last)2741c09f92d2SPeter Avalos lzx_decode_blocks(struct lzx_stream *strm, int last)
2742c09f92d2SPeter Avalos {
2743c09f92d2SPeter Avalos struct lzx_dec *ds = strm->ds;
2744c09f92d2SPeter Avalos struct lzx_br bre = ds->br;
2745c09f92d2SPeter Avalos struct huffman *at = &(ds->at), *lt = &(ds->lt), *mt = &(ds->mt);
2746c09f92d2SPeter Avalos const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl;
2747d4d8193eSPeter Avalos unsigned char *noutp = strm->next_out;
2748d4d8193eSPeter Avalos unsigned char *endp = noutp + strm->avail_out;
2749c09f92d2SPeter Avalos unsigned char *w_buff = ds->w_buff;
2750c09f92d2SPeter Avalos unsigned char *at_bitlen = at->bitlen;
2751c09f92d2SPeter Avalos unsigned char *lt_bitlen = lt->bitlen;
2752c09f92d2SPeter Avalos unsigned char *mt_bitlen = mt->bitlen;
2753c09f92d2SPeter Avalos size_t block_bytes_avail = ds->block_bytes_avail;
2754c09f92d2SPeter Avalos int at_max_bits = at->max_bits;
2755c09f92d2SPeter Avalos int lt_max_bits = lt->max_bits;
2756c09f92d2SPeter Avalos int mt_max_bits = mt->max_bits;
2757c09f92d2SPeter Avalos int c, copy_len = ds->copy_len, copy_pos = ds->copy_pos;
2758c09f92d2SPeter Avalos int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
2759c09f92d2SPeter Avalos int length_header = ds->length_header;
2760c09f92d2SPeter Avalos int offset_bits = ds->offset_bits;
2761c09f92d2SPeter Avalos int position_slot = ds->position_slot;
2762c09f92d2SPeter Avalos int r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;
2763c09f92d2SPeter Avalos int state = ds->state;
2764c09f92d2SPeter Avalos char block_type = ds->block_type;
2765c09f92d2SPeter Avalos
2766c09f92d2SPeter Avalos for (;;) {
2767c09f92d2SPeter Avalos switch (state) {
2768c09f92d2SPeter Avalos case ST_MAIN:
2769c09f92d2SPeter Avalos for (;;) {
2770c09f92d2SPeter Avalos if (block_bytes_avail == 0) {
2771c09f92d2SPeter Avalos /* This block ended. */
2772c09f92d2SPeter Avalos ds->state = ST_RD_BLOCK_TYPE;
2773c09f92d2SPeter Avalos ds->br = bre;
2774c09f92d2SPeter Avalos ds->block_bytes_avail =
2775c09f92d2SPeter Avalos block_bytes_avail;
2776c09f92d2SPeter Avalos ds->copy_len = copy_len;
2777c09f92d2SPeter Avalos ds->copy_pos = copy_pos;
2778c09f92d2SPeter Avalos ds->length_header = length_header;
2779c09f92d2SPeter Avalos ds->position_slot = position_slot;
2780c09f92d2SPeter Avalos ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
2781c09f92d2SPeter Avalos ds->w_pos = w_pos;
2782d4d8193eSPeter Avalos strm->avail_out = endp - noutp;
2783c09f92d2SPeter Avalos return (ARCHIVE_EOF);
2784c09f92d2SPeter Avalos }
2785d4d8193eSPeter Avalos if (noutp >= endp)
2786c09f92d2SPeter Avalos /* Output buffer is empty. */
2787c09f92d2SPeter Avalos goto next_data;
2788c09f92d2SPeter Avalos
2789c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, &bre,
2790c09f92d2SPeter Avalos mt_max_bits)) {
2791c09f92d2SPeter Avalos if (!last)
2792c09f92d2SPeter Avalos goto next_data;
2793c09f92d2SPeter Avalos /* Remaining bits are less than
2794c09f92d2SPeter Avalos * maximum bits(mt.max_bits) but maybe
2795c09f92d2SPeter Avalos * it still remains as much as we need,
2796c09f92d2SPeter Avalos * so we should try to use it with
2797c09f92d2SPeter Avalos * dummy bits. */
2798c09f92d2SPeter Avalos c = lzx_decode_huffman(mt,
2799c09f92d2SPeter Avalos lzx_br_bits_forced(
2800c09f92d2SPeter Avalos &bre, mt_max_bits));
2801c09f92d2SPeter Avalos lzx_br_consume(&bre, mt_bitlen[c]);
2802c09f92d2SPeter Avalos if (!lzx_br_has(&bre, 0))
2803c09f92d2SPeter Avalos goto failed;/* Over read. */
2804c09f92d2SPeter Avalos } else {
2805c09f92d2SPeter Avalos c = lzx_decode_huffman(mt,
2806c09f92d2SPeter Avalos lzx_br_bits(&bre, mt_max_bits));
2807c09f92d2SPeter Avalos lzx_br_consume(&bre, mt_bitlen[c]);
2808c09f92d2SPeter Avalos }
2809c09f92d2SPeter Avalos if (c > UCHAR_MAX)
2810c09f92d2SPeter Avalos break;
2811c09f92d2SPeter Avalos /*
2812c09f92d2SPeter Avalos * 'c' is exactly literal code.
2813c09f92d2SPeter Avalos */
2814c09f92d2SPeter Avalos /* Save a decoded code to reference it
2815c09f92d2SPeter Avalos * afterward. */
2816c09f92d2SPeter Avalos w_buff[w_pos] = c;
2817c09f92d2SPeter Avalos w_pos = (w_pos + 1) & w_mask;
2818c09f92d2SPeter Avalos /* Store the decoded code to output buffer. */
2819d4d8193eSPeter Avalos *noutp++ = c;
2820c09f92d2SPeter Avalos block_bytes_avail--;
2821c09f92d2SPeter Avalos }
2822c09f92d2SPeter Avalos /*
2823c09f92d2SPeter Avalos * Get a match code, its length and offset.
2824c09f92d2SPeter Avalos */
2825c09f92d2SPeter Avalos c -= UCHAR_MAX + 1;
2826c09f92d2SPeter Avalos length_header = c & 7;
2827c09f92d2SPeter Avalos position_slot = c >> 3;
2828c09f92d2SPeter Avalos /* FALL THROUGH */
2829c09f92d2SPeter Avalos case ST_LENGTH:
2830c09f92d2SPeter Avalos /*
2831c09f92d2SPeter Avalos * Get a length.
2832c09f92d2SPeter Avalos */
2833c09f92d2SPeter Avalos if (length_header == 7) {
2834c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, &bre,
2835c09f92d2SPeter Avalos lt_max_bits)) {
2836c09f92d2SPeter Avalos if (!last) {
2837c09f92d2SPeter Avalos state = ST_LENGTH;
2838c09f92d2SPeter Avalos goto next_data;
2839c09f92d2SPeter Avalos }
2840c09f92d2SPeter Avalos c = lzx_decode_huffman(lt,
2841c09f92d2SPeter Avalos lzx_br_bits_forced(
2842c09f92d2SPeter Avalos &bre, lt_max_bits));
2843c09f92d2SPeter Avalos lzx_br_consume(&bre, lt_bitlen[c]);
2844c09f92d2SPeter Avalos if (!lzx_br_has(&bre, 0))
2845c09f92d2SPeter Avalos goto failed;/* Over read. */
2846c09f92d2SPeter Avalos } else {
2847c09f92d2SPeter Avalos c = lzx_decode_huffman(lt,
2848c09f92d2SPeter Avalos lzx_br_bits(&bre, lt_max_bits));
2849c09f92d2SPeter Avalos lzx_br_consume(&bre, lt_bitlen[c]);
2850c09f92d2SPeter Avalos }
2851c09f92d2SPeter Avalos copy_len = c + 7 + 2;
2852c09f92d2SPeter Avalos } else
2853c09f92d2SPeter Avalos copy_len = length_header + 2;
2854c09f92d2SPeter Avalos if ((size_t)copy_len > block_bytes_avail)
2855c09f92d2SPeter Avalos goto failed;
2856c09f92d2SPeter Avalos /*
2857c09f92d2SPeter Avalos * Get an offset.
2858c09f92d2SPeter Avalos */
2859c09f92d2SPeter Avalos switch (position_slot) {
2860c09f92d2SPeter Avalos case 0: /* Use repeated offset 0. */
2861c09f92d2SPeter Avalos copy_pos = r0;
2862c09f92d2SPeter Avalos state = ST_REAL_POS;
2863c09f92d2SPeter Avalos continue;
2864c09f92d2SPeter Avalos case 1: /* Use repeated offset 1. */
2865c09f92d2SPeter Avalos copy_pos = r1;
2866c09f92d2SPeter Avalos /* Swap repeated offset. */
2867c09f92d2SPeter Avalos r1 = r0;
2868c09f92d2SPeter Avalos r0 = copy_pos;
2869c09f92d2SPeter Avalos state = ST_REAL_POS;
2870c09f92d2SPeter Avalos continue;
2871c09f92d2SPeter Avalos case 2: /* Use repeated offset 2. */
2872c09f92d2SPeter Avalos copy_pos = r2;
2873c09f92d2SPeter Avalos /* Swap repeated offset. */
2874c09f92d2SPeter Avalos r2 = r0;
2875c09f92d2SPeter Avalos r0 = copy_pos;
2876c09f92d2SPeter Avalos state = ST_REAL_POS;
2877c09f92d2SPeter Avalos continue;
2878c09f92d2SPeter Avalos default:
2879c09f92d2SPeter Avalos offset_bits =
2880c09f92d2SPeter Avalos pos_tbl[position_slot].footer_bits;
2881c09f92d2SPeter Avalos break;
2882c09f92d2SPeter Avalos }
2883c09f92d2SPeter Avalos /* FALL THROUGH */
2884c09f92d2SPeter Avalos case ST_OFFSET:
2885c09f92d2SPeter Avalos /*
2886c09f92d2SPeter Avalos * Get the offset, which is a distance from
2887c09f92d2SPeter Avalos * current window position.
2888c09f92d2SPeter Avalos */
2889c09f92d2SPeter Avalos if (block_type == ALIGNED_OFFSET_BLOCK &&
2890c09f92d2SPeter Avalos offset_bits >= 3) {
2891c09f92d2SPeter Avalos int offbits = offset_bits - 3;
2892c09f92d2SPeter Avalos
2893c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, &bre, offbits)) {
2894c09f92d2SPeter Avalos state = ST_OFFSET;
2895c09f92d2SPeter Avalos if (last)
2896c09f92d2SPeter Avalos goto failed;
2897c09f92d2SPeter Avalos goto next_data;
2898c09f92d2SPeter Avalos }
2899c09f92d2SPeter Avalos copy_pos = lzx_br_bits(&bre, offbits) << 3;
2900c09f92d2SPeter Avalos
2901c09f92d2SPeter Avalos /* Get an aligned number. */
2902c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, &bre,
2903c09f92d2SPeter Avalos offbits + at_max_bits)) {
2904c09f92d2SPeter Avalos if (!last) {
2905c09f92d2SPeter Avalos state = ST_OFFSET;
2906c09f92d2SPeter Avalos goto next_data;
2907c09f92d2SPeter Avalos }
2908c09f92d2SPeter Avalos lzx_br_consume(&bre, offbits);
2909c09f92d2SPeter Avalos c = lzx_decode_huffman(at,
2910c09f92d2SPeter Avalos lzx_br_bits_forced(&bre,
2911c09f92d2SPeter Avalos at_max_bits));
2912c09f92d2SPeter Avalos lzx_br_consume(&bre, at_bitlen[c]);
2913c09f92d2SPeter Avalos if (!lzx_br_has(&bre, 0))
2914c09f92d2SPeter Avalos goto failed;/* Over read. */
2915c09f92d2SPeter Avalos } else {
2916c09f92d2SPeter Avalos lzx_br_consume(&bre, offbits);
2917c09f92d2SPeter Avalos c = lzx_decode_huffman(at,
2918c09f92d2SPeter Avalos lzx_br_bits(&bre, at_max_bits));
2919c09f92d2SPeter Avalos lzx_br_consume(&bre, at_bitlen[c]);
2920c09f92d2SPeter Avalos }
2921c09f92d2SPeter Avalos /* Add an aligned number. */
2922c09f92d2SPeter Avalos copy_pos += c;
2923c09f92d2SPeter Avalos } else {
2924c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, &bre,
2925c09f92d2SPeter Avalos offset_bits)) {
2926c09f92d2SPeter Avalos state = ST_OFFSET;
2927c09f92d2SPeter Avalos if (last)
2928c09f92d2SPeter Avalos goto failed;
2929c09f92d2SPeter Avalos goto next_data;
2930c09f92d2SPeter Avalos }
2931c09f92d2SPeter Avalos copy_pos = lzx_br_bits(&bre, offset_bits);
2932c09f92d2SPeter Avalos lzx_br_consume(&bre, offset_bits);
2933c09f92d2SPeter Avalos }
2934c09f92d2SPeter Avalos copy_pos += pos_tbl[position_slot].base -2;
2935c09f92d2SPeter Avalos
2936c09f92d2SPeter Avalos /* Update repeated offset LRU queue. */
2937c09f92d2SPeter Avalos r2 = r1;
2938c09f92d2SPeter Avalos r1 = r0;
2939c09f92d2SPeter Avalos r0 = copy_pos;
2940c09f92d2SPeter Avalos /* FALL THROUGH */
2941c09f92d2SPeter Avalos case ST_REAL_POS:
2942c09f92d2SPeter Avalos /*
2943c09f92d2SPeter Avalos * Compute a real position in window.
2944c09f92d2SPeter Avalos */
2945c09f92d2SPeter Avalos copy_pos = (w_pos - copy_pos) & w_mask;
2946c09f92d2SPeter Avalos /* FALL THROUGH */
2947c09f92d2SPeter Avalos case ST_COPY:
2948c09f92d2SPeter Avalos /*
2949c09f92d2SPeter Avalos * Copy several bytes as extracted data from the window
2950c09f92d2SPeter Avalos * into the output buffer.
2951c09f92d2SPeter Avalos */
2952c09f92d2SPeter Avalos for (;;) {
2953c09f92d2SPeter Avalos const unsigned char *s;
2954c09f92d2SPeter Avalos int l;
2955c09f92d2SPeter Avalos
2956c09f92d2SPeter Avalos l = copy_len;
2957c09f92d2SPeter Avalos if (copy_pos > w_pos) {
2958c09f92d2SPeter Avalos if (l > w_size - copy_pos)
2959c09f92d2SPeter Avalos l = w_size - copy_pos;
2960c09f92d2SPeter Avalos } else {
2961c09f92d2SPeter Avalos if (l > w_size - w_pos)
2962c09f92d2SPeter Avalos l = w_size - w_pos;
2963c09f92d2SPeter Avalos }
2964d4d8193eSPeter Avalos if (noutp + l >= endp)
2965d4d8193eSPeter Avalos l = (int)(endp - noutp);
2966c09f92d2SPeter Avalos s = w_buff + copy_pos;
2967c09f92d2SPeter Avalos if (l >= 8 && ((copy_pos + l < w_pos)
2968c09f92d2SPeter Avalos || (w_pos + l < copy_pos))) {
2969c09f92d2SPeter Avalos memcpy(w_buff + w_pos, s, l);
2970d4d8193eSPeter Avalos memcpy(noutp, s, l);
2971c09f92d2SPeter Avalos } else {
2972c09f92d2SPeter Avalos unsigned char *d;
2973c09f92d2SPeter Avalos int li;
2974c09f92d2SPeter Avalos
2975c09f92d2SPeter Avalos d = w_buff + w_pos;
2976c09f92d2SPeter Avalos for (li = 0; li < l; li++)
2977d4d8193eSPeter Avalos noutp[li] = d[li] = s[li];
2978c09f92d2SPeter Avalos }
2979d4d8193eSPeter Avalos noutp += l;
2980c09f92d2SPeter Avalos copy_pos = (copy_pos + l) & w_mask;
2981c09f92d2SPeter Avalos w_pos = (w_pos + l) & w_mask;
2982c09f92d2SPeter Avalos block_bytes_avail -= l;
2983c09f92d2SPeter Avalos if (copy_len <= l)
2984c09f92d2SPeter Avalos /* A copy of current pattern ended. */
2985c09f92d2SPeter Avalos break;
2986c09f92d2SPeter Avalos copy_len -= l;
2987d4d8193eSPeter Avalos if (noutp >= endp) {
2988c09f92d2SPeter Avalos /* Output buffer is empty. */
2989c09f92d2SPeter Avalos state = ST_COPY;
2990c09f92d2SPeter Avalos goto next_data;
2991c09f92d2SPeter Avalos }
2992c09f92d2SPeter Avalos }
2993c09f92d2SPeter Avalos state = ST_MAIN;
2994c09f92d2SPeter Avalos break;
2995c09f92d2SPeter Avalos }
2996c09f92d2SPeter Avalos }
2997c09f92d2SPeter Avalos failed:
2998c09f92d2SPeter Avalos return (ds->error = ARCHIVE_FAILED);
2999c09f92d2SPeter Avalos next_data:
3000c09f92d2SPeter Avalos ds->br = bre;
3001c09f92d2SPeter Avalos ds->block_bytes_avail = block_bytes_avail;
3002c09f92d2SPeter Avalos ds->copy_len = copy_len;
3003c09f92d2SPeter Avalos ds->copy_pos = copy_pos;
3004c09f92d2SPeter Avalos ds->length_header = length_header;
3005c09f92d2SPeter Avalos ds->offset_bits = offset_bits;
3006c09f92d2SPeter Avalos ds->position_slot = position_slot;
3007c09f92d2SPeter Avalos ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
3008c09f92d2SPeter Avalos ds->state = state;
3009c09f92d2SPeter Avalos ds->w_pos = w_pos;
3010d4d8193eSPeter Avalos strm->avail_out = endp - noutp;
3011c09f92d2SPeter Avalos return (ARCHIVE_OK);
3012c09f92d2SPeter Avalos }
3013c09f92d2SPeter Avalos
3014c09f92d2SPeter Avalos static int
lzx_read_pre_tree(struct lzx_stream * strm)3015c09f92d2SPeter Avalos lzx_read_pre_tree(struct lzx_stream *strm)
3016c09f92d2SPeter Avalos {
3017c09f92d2SPeter Avalos struct lzx_dec *ds = strm->ds;
3018c09f92d2SPeter Avalos struct lzx_br *br = &(ds->br);
3019c09f92d2SPeter Avalos int i;
3020c09f92d2SPeter Avalos
3021c09f92d2SPeter Avalos if (ds->loop == 0)
3022c09f92d2SPeter Avalos memset(ds->pt.freq, 0, sizeof(ds->pt.freq));
3023c09f92d2SPeter Avalos for (i = ds->loop; i < ds->pt.len_size; i++) {
3024c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, br, 4)) {
3025c09f92d2SPeter Avalos ds->loop = i;
3026c09f92d2SPeter Avalos return (0);
3027c09f92d2SPeter Avalos }
3028c09f92d2SPeter Avalos ds->pt.bitlen[i] = lzx_br_bits(br, 4);
3029c09f92d2SPeter Avalos ds->pt.freq[ds->pt.bitlen[i]]++;
3030c09f92d2SPeter Avalos lzx_br_consume(br, 4);
3031c09f92d2SPeter Avalos }
3032c09f92d2SPeter Avalos ds->loop = i;
3033c09f92d2SPeter Avalos return (1);
3034c09f92d2SPeter Avalos }
3035c09f92d2SPeter Avalos
3036c09f92d2SPeter Avalos /*
3037c09f92d2SPeter Avalos * Read a bunch of bit-lengths from pre-tree.
3038c09f92d2SPeter Avalos */
3039c09f92d2SPeter Avalos static int
lzx_read_bitlen(struct lzx_stream * strm,struct huffman * d,int end)3040c09f92d2SPeter Avalos lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, int end)
3041c09f92d2SPeter Avalos {
3042c09f92d2SPeter Avalos struct lzx_dec *ds = strm->ds;
3043c09f92d2SPeter Avalos struct lzx_br *br = &(ds->br);
3044c09f92d2SPeter Avalos int c, i, j, ret, same;
3045c09f92d2SPeter Avalos unsigned rbits;
3046c09f92d2SPeter Avalos
3047c09f92d2SPeter Avalos i = ds->loop;
3048c09f92d2SPeter Avalos if (i == 0)
3049c09f92d2SPeter Avalos memset(d->freq, 0, sizeof(d->freq));
3050c09f92d2SPeter Avalos ret = 0;
3051c09f92d2SPeter Avalos if (end < 0)
3052c09f92d2SPeter Avalos end = d->len_size;
3053c09f92d2SPeter Avalos while (i < end) {
3054c09f92d2SPeter Avalos ds->loop = i;
3055c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, br, ds->pt.max_bits))
3056c09f92d2SPeter Avalos goto getdata;
3057c09f92d2SPeter Avalos rbits = lzx_br_bits(br, ds->pt.max_bits);
3058c09f92d2SPeter Avalos c = lzx_decode_huffman(&(ds->pt), rbits);
3059c09f92d2SPeter Avalos switch (c) {
3060c09f92d2SPeter Avalos case 17:/* several zero lengths, from 4 to 19. */
3061c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+4))
3062c09f92d2SPeter Avalos goto getdata;
3063c09f92d2SPeter Avalos lzx_br_consume(br, ds->pt.bitlen[c]);
3064c09f92d2SPeter Avalos same = lzx_br_bits(br, 4) + 4;
3065c09f92d2SPeter Avalos if (i + same > end)
3066c09f92d2SPeter Avalos return (-1);/* Invalid */
3067c09f92d2SPeter Avalos lzx_br_consume(br, 4);
3068c09f92d2SPeter Avalos for (j = 0; j < same; j++)
3069c09f92d2SPeter Avalos d->bitlen[i++] = 0;
3070c09f92d2SPeter Avalos break;
3071c09f92d2SPeter Avalos case 18:/* many zero lengths, from 20 to 51. */
3072c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+5))
3073c09f92d2SPeter Avalos goto getdata;
3074c09f92d2SPeter Avalos lzx_br_consume(br, ds->pt.bitlen[c]);
3075c09f92d2SPeter Avalos same = lzx_br_bits(br, 5) + 20;
3076c09f92d2SPeter Avalos if (i + same > end)
3077c09f92d2SPeter Avalos return (-1);/* Invalid */
3078c09f92d2SPeter Avalos lzx_br_consume(br, 5);
3079c09f92d2SPeter Avalos memset(d->bitlen + i, 0, same);
3080c09f92d2SPeter Avalos i += same;
3081c09f92d2SPeter Avalos break;
3082c09f92d2SPeter Avalos case 19:/* a few same lengths. */
3083c09f92d2SPeter Avalos if (!lzx_br_read_ahead(strm, br,
3084c09f92d2SPeter Avalos ds->pt.bitlen[c]+1+ds->pt.max_bits))
3085c09f92d2SPeter Avalos goto getdata;
3086c09f92d2SPeter Avalos lzx_br_consume(br, ds->pt.bitlen[c]);
3087c09f92d2SPeter Avalos same = lzx_br_bits(br, 1) + 4;
3088c09f92d2SPeter Avalos if (i + same > end)
3089c09f92d2SPeter Avalos return (-1);
3090c09f92d2SPeter Avalos lzx_br_consume(br, 1);
3091c09f92d2SPeter Avalos rbits = lzx_br_bits(br, ds->pt.max_bits);
3092c09f92d2SPeter Avalos c = lzx_decode_huffman(&(ds->pt), rbits);
3093c09f92d2SPeter Avalos lzx_br_consume(br, ds->pt.bitlen[c]);
3094c09f92d2SPeter Avalos c = (d->bitlen[i] - c + 17) % 17;
3095c09f92d2SPeter Avalos if (c < 0)
3096c09f92d2SPeter Avalos return (-1);/* Invalid */
3097c09f92d2SPeter Avalos for (j = 0; j < same; j++)
3098c09f92d2SPeter Avalos d->bitlen[i++] = c;
3099c09f92d2SPeter Avalos d->freq[c] += same;
3100c09f92d2SPeter Avalos break;
3101c09f92d2SPeter Avalos default:
3102c09f92d2SPeter Avalos lzx_br_consume(br, ds->pt.bitlen[c]);
3103c09f92d2SPeter Avalos c = (d->bitlen[i] - c + 17) % 17;
3104c09f92d2SPeter Avalos if (c < 0)
3105c09f92d2SPeter Avalos return (-1);/* Invalid */
3106c09f92d2SPeter Avalos d->freq[c]++;
3107c09f92d2SPeter Avalos d->bitlen[i++] = c;
3108c09f92d2SPeter Avalos break;
3109c09f92d2SPeter Avalos }
3110c09f92d2SPeter Avalos }
3111c09f92d2SPeter Avalos ret = 1;
3112c09f92d2SPeter Avalos getdata:
3113c09f92d2SPeter Avalos ds->loop = i;
3114c09f92d2SPeter Avalos return (ret);
3115c09f92d2SPeter Avalos }
3116c09f92d2SPeter Avalos
3117c09f92d2SPeter Avalos static int
lzx_huffman_init(struct huffman * hf,size_t len_size,int tbl_bits)3118c09f92d2SPeter Avalos lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
3119c09f92d2SPeter Avalos {
3120c09f92d2SPeter Avalos
3121c09f92d2SPeter Avalos if (hf->bitlen == NULL || hf->len_size != (int)len_size) {
3122c09f92d2SPeter Avalos free(hf->bitlen);
3123c09f92d2SPeter Avalos hf->bitlen = calloc(len_size, sizeof(hf->bitlen[0]));
3124c09f92d2SPeter Avalos if (hf->bitlen == NULL)
3125c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
3126d4d8193eSPeter Avalos hf->len_size = (int)len_size;
3127c09f92d2SPeter Avalos } else
3128c09f92d2SPeter Avalos memset(hf->bitlen, 0, len_size * sizeof(hf->bitlen[0]));
3129c09f92d2SPeter Avalos if (hf->tbl == NULL) {
3130e95abc47Szrj hf->tbl = malloc(((size_t)1 << tbl_bits) * sizeof(hf->tbl[0]));
3131c09f92d2SPeter Avalos if (hf->tbl == NULL)
3132c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
3133c09f92d2SPeter Avalos hf->tbl_bits = tbl_bits;
3134c09f92d2SPeter Avalos }
3135c09f92d2SPeter Avalos return (ARCHIVE_OK);
3136c09f92d2SPeter Avalos }
3137c09f92d2SPeter Avalos
3138c09f92d2SPeter Avalos static void
lzx_huffman_free(struct huffman * hf)3139c09f92d2SPeter Avalos lzx_huffman_free(struct huffman *hf)
3140c09f92d2SPeter Avalos {
3141c09f92d2SPeter Avalos free(hf->bitlen);
3142c09f92d2SPeter Avalos free(hf->tbl);
3143c09f92d2SPeter Avalos }
3144c09f92d2SPeter Avalos
3145c09f92d2SPeter Avalos /*
3146c09f92d2SPeter Avalos * Make a huffman coding table.
3147c09f92d2SPeter Avalos */
3148c09f92d2SPeter Avalos static int
lzx_make_huffman_table(struct huffman * hf)3149c09f92d2SPeter Avalos lzx_make_huffman_table(struct huffman *hf)
3150c09f92d2SPeter Avalos {
3151c09f92d2SPeter Avalos uint16_t *tbl;
3152c09f92d2SPeter Avalos const unsigned char *bitlen;
3153c09f92d2SPeter Avalos int bitptn[17], weight[17];
3154c09f92d2SPeter Avalos int i, maxbits = 0, ptn, tbl_size, w;
3155e95abc47Szrj int len_avail;
3156c09f92d2SPeter Avalos
3157c09f92d2SPeter Avalos /*
3158c09f92d2SPeter Avalos * Initialize bit patterns.
3159c09f92d2SPeter Avalos */
3160c09f92d2SPeter Avalos ptn = 0;
3161c09f92d2SPeter Avalos for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {
3162c09f92d2SPeter Avalos bitptn[i] = ptn;
3163c09f92d2SPeter Avalos weight[i] = w;
3164c09f92d2SPeter Avalos if (hf->freq[i]) {
3165c09f92d2SPeter Avalos ptn += hf->freq[i] * w;
3166c09f92d2SPeter Avalos maxbits = i;
3167c09f92d2SPeter Avalos }
3168c09f92d2SPeter Avalos }
3169c09f92d2SPeter Avalos if ((ptn & 0xffff) != 0 || maxbits > hf->tbl_bits)
3170c09f92d2SPeter Avalos return (0);/* Invalid */
3171c09f92d2SPeter Avalos
3172c09f92d2SPeter Avalos hf->max_bits = maxbits;
3173c09f92d2SPeter Avalos
3174c09f92d2SPeter Avalos /*
3175c09f92d2SPeter Avalos * Cut out extra bits which we won't house in the table.
3176c09f92d2SPeter Avalos * This preparation reduces the same calculation in the for-loop
3177c09f92d2SPeter Avalos * making the table.
3178c09f92d2SPeter Avalos */
3179c09f92d2SPeter Avalos if (maxbits < 16) {
3180c09f92d2SPeter Avalos int ebits = 16 - maxbits;
3181c09f92d2SPeter Avalos for (i = 1; i <= maxbits; i++) {
3182c09f92d2SPeter Avalos bitptn[i] >>= ebits;
3183c09f92d2SPeter Avalos weight[i] >>= ebits;
3184c09f92d2SPeter Avalos }
3185c09f92d2SPeter Avalos }
3186c09f92d2SPeter Avalos
3187c09f92d2SPeter Avalos /*
3188c09f92d2SPeter Avalos * Make the table.
3189c09f92d2SPeter Avalos */
3190e95abc47Szrj tbl_size = 1 << hf->tbl_bits;
3191c09f92d2SPeter Avalos tbl = hf->tbl;
3192c09f92d2SPeter Avalos bitlen = hf->bitlen;
3193c09f92d2SPeter Avalos len_avail = hf->len_size;
3194c09f92d2SPeter Avalos hf->tree_used = 0;
3195c09f92d2SPeter Avalos for (i = 0; i < len_avail; i++) {
3196c09f92d2SPeter Avalos uint16_t *p;
3197c09f92d2SPeter Avalos int len, cnt;
3198c09f92d2SPeter Avalos
3199c09f92d2SPeter Avalos if (bitlen[i] == 0)
3200c09f92d2SPeter Avalos continue;
3201c09f92d2SPeter Avalos /* Get a bit pattern */
3202c09f92d2SPeter Avalos len = bitlen[i];
3203e95abc47Szrj if (len > tbl_size)
3204e95abc47Szrj return (0);
3205c09f92d2SPeter Avalos ptn = bitptn[len];
3206c09f92d2SPeter Avalos cnt = weight[len];
3207c09f92d2SPeter Avalos /* Calculate next bit pattern */
3208c09f92d2SPeter Avalos if ((bitptn[len] = ptn + cnt) > tbl_size)
3209c09f92d2SPeter Avalos return (0);/* Invalid */
3210c09f92d2SPeter Avalos /* Update the table */
3211c09f92d2SPeter Avalos p = &(tbl[ptn]);
3212c09f92d2SPeter Avalos while (--cnt >= 0)
3213c09f92d2SPeter Avalos p[cnt] = (uint16_t)i;
3214c09f92d2SPeter Avalos }
3215c09f92d2SPeter Avalos return (1);
3216c09f92d2SPeter Avalos }
3217c09f92d2SPeter Avalos
3218c09f92d2SPeter Avalos static inline int
lzx_decode_huffman(struct huffman * hf,unsigned rbits)3219c09f92d2SPeter Avalos lzx_decode_huffman(struct huffman *hf, unsigned rbits)
3220c09f92d2SPeter Avalos {
3221c09f92d2SPeter Avalos int c;
3222e95abc47Szrj c = hf->tbl[rbits];
3223c09f92d2SPeter Avalos if (c < hf->len_size)
3224c09f92d2SPeter Avalos return (c);
3225e95abc47Szrj return (0);
3226c09f92d2SPeter Avalos }
3227