1c2c66affSColin Finck /***************************************************************************
2c2c66affSColin Finck * lzx.c - LZX decompression routines *
3c2c66affSColin Finck * ------------------- *
4c2c66affSColin Finck * *
5c2c66affSColin Finck * maintainer: Jed Wing <jedwin@ugcs.caltech.edu> *
6c2c66affSColin Finck * source: modified lzx.c from cabextract v0.5 *
7c2c66affSColin Finck * notes: This file was taken from cabextract v0.5, which was, *
8c2c66affSColin Finck * itself, a modified version of the lzx decompression code *
9c2c66affSColin Finck * from unlzx. *
10c2c66affSColin Finck * *
11c2c66affSColin Finck * platforms: In its current incarnation, this file has been tested on *
12c2c66affSColin Finck * two different Linux platforms (one, redhat-based, with a *
13c2c66affSColin Finck * 2.1.2 glibc and gcc 2.95.x, and the other, Debian, with *
14c2c66affSColin Finck * 2.2.4 glibc and both gcc 2.95.4 and gcc 3.0.2). Both were *
15c2c66affSColin Finck * Intel x86 compatible machines. *
16c2c66affSColin Finck ***************************************************************************/
17c2c66affSColin Finck
18c2c66affSColin Finck /***************************************************************************
19c2c66affSColin Finck *
20c2c66affSColin Finck * Copyright(C) Stuart Caie
21c2c66affSColin Finck *
22c2c66affSColin Finck * This library is free software; you can redistribute it and/or
23c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public
24c2c66affSColin Finck * License as published by the Free Software Foundation; either
25c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version.
26c2c66affSColin Finck *
27c2c66affSColin Finck * This library is distributed in the hope that it will be useful,
28c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
29c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30c2c66affSColin Finck * Lesser General Public License for more details.
31c2c66affSColin Finck *
32c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public
33c2c66affSColin Finck * License along with this library; if not, write to the Free Software
34c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
35c2c66affSColin Finck *
36c2c66affSColin Finck ***************************************************************************/
37c2c66affSColin Finck
38919215fdSAmine Khaldi #include "lzx.h"
39919215fdSAmine Khaldi #include <stdarg.h>
40919215fdSAmine Khaldi #include <stdio.h>
41919215fdSAmine Khaldi #include <stdlib.h>
42919215fdSAmine Khaldi #include <string.h>
43919215fdSAmine Khaldi
44919215fdSAmine Khaldi #include "windef.h"
45919215fdSAmine Khaldi #include "winbase.h"
46c2c66affSColin Finck
47c2c66affSColin Finck /* sized types */
48c2c66affSColin Finck typedef unsigned char UBYTE; /* 8 bits exactly */
49c2c66affSColin Finck typedef unsigned short UWORD; /* 16 bits (or more) */
50c2c66affSColin Finck
51c2c66affSColin Finck /* some constants defined by the LZX specification */
52c2c66affSColin Finck #define LZX_MIN_MATCH (2)
53c2c66affSColin Finck #define LZX_MAX_MATCH (257)
54c2c66affSColin Finck #define LZX_NUM_CHARS (256)
55c2c66affSColin Finck #define LZX_BLOCKTYPE_INVALID (0) /* also blocktypes 4-7 invalid */
56c2c66affSColin Finck #define LZX_BLOCKTYPE_VERBATIM (1)
57c2c66affSColin Finck #define LZX_BLOCKTYPE_ALIGNED (2)
58c2c66affSColin Finck #define LZX_BLOCKTYPE_UNCOMPRESSED (3)
59c2c66affSColin Finck #define LZX_PRETREE_NUM_ELEMENTS (20)
60c2c66affSColin Finck #define LZX_ALIGNED_NUM_ELEMENTS (8) /* aligned offset tree #elements */
61c2c66affSColin Finck #define LZX_NUM_PRIMARY_LENGTHS (7) /* this one missing from spec! */
62c2c66affSColin Finck #define LZX_NUM_SECONDARY_LENGTHS (249) /* length tree #elements */
63c2c66affSColin Finck
64c2c66affSColin Finck /* LZX huffman defines: tweak tablebits as desired */
65c2c66affSColin Finck #define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS)
66c2c66affSColin Finck #define LZX_PRETREE_TABLEBITS (6)
67c2c66affSColin Finck #define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8)
68c2c66affSColin Finck #define LZX_MAINTREE_TABLEBITS (12)
69c2c66affSColin Finck #define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1)
70c2c66affSColin Finck #define LZX_LENGTH_TABLEBITS (12)
71c2c66affSColin Finck #define LZX_ALIGNED_MAXSYMBOLS (LZX_ALIGNED_NUM_ELEMENTS)
72c2c66affSColin Finck #define LZX_ALIGNED_TABLEBITS (7)
73c2c66affSColin Finck
74c2c66affSColin Finck #define LZX_LENTABLE_SAFETY (64) /* we allow length table decoding overruns */
75c2c66affSColin Finck
76c2c66affSColin Finck #define LZX_DECLARE_TABLE(tbl) \
77c2c66affSColin Finck UWORD tbl##_table[(1<<LZX_##tbl##_TABLEBITS) + (LZX_##tbl##_MAXSYMBOLS<<1)];\
78c2c66affSColin Finck UBYTE tbl##_len [LZX_##tbl##_MAXSYMBOLS + LZX_LENTABLE_SAFETY]
79c2c66affSColin Finck
80c2c66affSColin Finck struct LZXstate
81c2c66affSColin Finck {
82c2c66affSColin Finck UBYTE *window; /* the actual decoding window */
83c2c66affSColin Finck ULONG window_size; /* window size (32Kb through 2Mb) */
84c2c66affSColin Finck ULONG actual_size; /* window size when it was first allocated */
85c2c66affSColin Finck ULONG window_posn; /* current offset within the window */
86c2c66affSColin Finck ULONG R0, R1, R2; /* for the LRU offset system */
87c2c66affSColin Finck UWORD main_elements; /* number of main tree elements */
88c2c66affSColin Finck int header_read; /* have we started decoding at all yet? */
89c2c66affSColin Finck UWORD block_type; /* type of this block */
90c2c66affSColin Finck ULONG block_length; /* uncompressed length of this block */
91c2c66affSColin Finck ULONG block_remaining; /* uncompressed bytes still left to decode */
92c2c66affSColin Finck ULONG frames_read; /* the number of CFDATA blocks processed */
93c2c66affSColin Finck LONG intel_filesize; /* magic header value used for transform */
94c2c66affSColin Finck LONG intel_curpos; /* current offset in transform space */
95c2c66affSColin Finck int intel_started; /* have we seen any translatable data yet? */
96c2c66affSColin Finck
97c2c66affSColin Finck LZX_DECLARE_TABLE(PRETREE);
98c2c66affSColin Finck LZX_DECLARE_TABLE(MAINTREE);
99c2c66affSColin Finck LZX_DECLARE_TABLE(LENGTH);
100c2c66affSColin Finck LZX_DECLARE_TABLE(ALIGNED);
101c2c66affSColin Finck };
102c2c66affSColin Finck
103c2c66affSColin Finck /* LZX decruncher */
104c2c66affSColin Finck
105c2c66affSColin Finck /* Microsoft's LZX document and their implementation of the
106c2c66affSColin Finck * com.ms.util.cab Java package do not concur.
107c2c66affSColin Finck *
108c2c66affSColin Finck * In the LZX document, there is a table showing the correlation between
109c2c66affSColin Finck * window size and the number of position slots. It states that the 1MB
110c2c66affSColin Finck * window = 40 slots and the 2MB window = 42 slots. In the implementation,
111c2c66affSColin Finck * 1MB = 42 slots, 2MB = 50 slots. The actual calculation is 'find the
112c2c66affSColin Finck * first slot whose position base is equal to or more than the required
113c2c66affSColin Finck * window size'. This would explain why other tables in the document refer
114c2c66affSColin Finck * to 50 slots rather than 42.
115c2c66affSColin Finck *
116c2c66affSColin Finck * The constant NUM_PRIMARY_LENGTHS used in the decompression pseudocode
117c2c66affSColin Finck * is not defined in the specification.
118c2c66affSColin Finck *
119c2c66affSColin Finck * The LZX document does not state the uncompressed block has an
120c2c66affSColin Finck * uncompressed length field. Where does this length field come from, so
121c2c66affSColin Finck * we can know how large the block is? The implementation has it as the 24
122c2c66affSColin Finck * bits following after the 3 blocktype bits, before the alignment
123c2c66affSColin Finck * padding.
124c2c66affSColin Finck *
125c2c66affSColin Finck * The LZX document states that aligned offset blocks have their aligned
126c2c66affSColin Finck * offset huffman tree AFTER the main and length trees. The implementation
127c2c66affSColin Finck * suggests that the aligned offset tree is BEFORE the main and length
128c2c66affSColin Finck * trees.
129c2c66affSColin Finck *
130c2c66affSColin Finck * The LZX document decoding algorithm states that, in an aligned offset
131c2c66affSColin Finck * block, if an extra_bits value is 1, 2 or 3, then that number of bits
132c2c66affSColin Finck * should be read and the result added to the match offset. This is
133c2c66affSColin Finck * correct for 1 and 2, but not 3, where just a huffman symbol (using the
134c2c66affSColin Finck * aligned tree) should be read.
135c2c66affSColin Finck *
136c2c66affSColin Finck * Regarding the E8 preprocessing, the LZX document states 'No translation
137c2c66affSColin Finck * may be performed on the last 6 bytes of the input block'. This is
138c2c66affSColin Finck * correct. However, the pseudocode provided checks for the *E8 leader*
139c2c66affSColin Finck * up to the last 6 bytes. If the leader appears between -10 and -7 bytes
140c2c66affSColin Finck * from the end, this would cause the next four bytes to be modified, at
141c2c66affSColin Finck * least one of which would be in the last 6 bytes, which is not allowed
142c2c66affSColin Finck * according to the spec.
143c2c66affSColin Finck *
144c2c66affSColin Finck * The specification states that the huffman trees must always contain at
145c2c66affSColin Finck * least one element. However, many CAB files contain blocks where the
146c2c66affSColin Finck * length tree is completely empty (because there are no matches), and
147c2c66affSColin Finck * this is expected to succeed.
148c2c66affSColin Finck */
149c2c66affSColin Finck
150c2c66affSColin Finck
151c2c66affSColin Finck /* LZX uses what it calls 'position slots' to represent match offsets.
152c2c66affSColin Finck * What this means is that a small 'position slot' number and a small
153c2c66affSColin Finck * offset from that slot are encoded instead of one large offset for
154c2c66affSColin Finck * every match.
155c2c66affSColin Finck * - position_base is an index to the position slot bases
156c2c66affSColin Finck * - extra_bits states how many bits of offset-from-base data is needed.
157c2c66affSColin Finck */
158c2c66affSColin Finck static const UBYTE extra_bits[51] = {
159c2c66affSColin Finck 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
160c2c66affSColin Finck 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14,
161c2c66affSColin Finck 15, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
162c2c66affSColin Finck 17, 17, 17
163c2c66affSColin Finck };
164c2c66affSColin Finck
165c2c66affSColin Finck static const ULONG position_base[51] = {
166c2c66affSColin Finck 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
167c2c66affSColin Finck 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152,
168c2c66affSColin Finck 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360, 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
169c2c66affSColin Finck 1835008, 1966080, 2097152
170c2c66affSColin Finck };
171c2c66affSColin Finck
LZXinit(int wndsize)172*da0cd273SAmine Khaldi struct LZXstate *LZXinit(int wndsize)
173c2c66affSColin Finck {
174c2c66affSColin Finck struct LZXstate *pState=NULL;
175c2c66affSColin Finck int i, posn_slots;
176c2c66affSColin Finck
177c2c66affSColin Finck /* allocate state and associated window */
178c2c66affSColin Finck pState = HeapAlloc(GetProcessHeap(), 0, sizeof(struct LZXstate));
179c2c66affSColin Finck if (!(pState->window = HeapAlloc(GetProcessHeap(), 0, wndsize)))
180c2c66affSColin Finck {
181c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pState);
182c2c66affSColin Finck return NULL;
183c2c66affSColin Finck }
184c2c66affSColin Finck pState->actual_size = wndsize;
185c2c66affSColin Finck pState->window_size = wndsize;
186c2c66affSColin Finck
187c2c66affSColin Finck /* calculate required position slots */
188*da0cd273SAmine Khaldi posn_slots = i = 0;
189*da0cd273SAmine Khaldi while (i < wndsize) i += 1 << extra_bits[posn_slots++];
190c2c66affSColin Finck
191c2c66affSColin Finck /* initialize other state */
192c2c66affSColin Finck pState->R0 = pState->R1 = pState->R2 = 1;
193c2c66affSColin Finck pState->main_elements = LZX_NUM_CHARS + (posn_slots << 3);
194c2c66affSColin Finck pState->header_read = 0;
195c2c66affSColin Finck pState->frames_read = 0;
196c2c66affSColin Finck pState->block_remaining = 0;
197c2c66affSColin Finck pState->block_type = LZX_BLOCKTYPE_INVALID;
198c2c66affSColin Finck pState->intel_curpos = 0;
199c2c66affSColin Finck pState->intel_started = 0;
200c2c66affSColin Finck pState->window_posn = 0;
201c2c66affSColin Finck
202c2c66affSColin Finck /* initialise tables to 0 (because deltas will be applied to them) */
203c2c66affSColin Finck for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) pState->MAINTREE_len[i] = 0;
204c2c66affSColin Finck for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) pState->LENGTH_len[i] = 0;
205c2c66affSColin Finck
206c2c66affSColin Finck return pState;
207c2c66affSColin Finck }
208c2c66affSColin Finck
LZXteardown(struct LZXstate * pState)209c2c66affSColin Finck void LZXteardown(struct LZXstate *pState)
210c2c66affSColin Finck {
211c2c66affSColin Finck if (pState)
212c2c66affSColin Finck {
213c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pState->window);
214c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pState);
215c2c66affSColin Finck }
216c2c66affSColin Finck }
217c2c66affSColin Finck
LZXreset(struct LZXstate * pState)218c2c66affSColin Finck int LZXreset(struct LZXstate *pState)
219c2c66affSColin Finck {
220c2c66affSColin Finck int i;
221c2c66affSColin Finck
222c2c66affSColin Finck pState->R0 = pState->R1 = pState->R2 = 1;
223c2c66affSColin Finck pState->header_read = 0;
224c2c66affSColin Finck pState->frames_read = 0;
225c2c66affSColin Finck pState->block_remaining = 0;
226c2c66affSColin Finck pState->block_type = LZX_BLOCKTYPE_INVALID;
227c2c66affSColin Finck pState->intel_curpos = 0;
228c2c66affSColin Finck pState->intel_started = 0;
229c2c66affSColin Finck pState->window_posn = 0;
230c2c66affSColin Finck
231c2c66affSColin Finck for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY; i++) pState->MAINTREE_len[i] = 0;
232c2c66affSColin Finck for (i = 0; i < LZX_LENGTH_MAXSYMBOLS + LZX_LENTABLE_SAFETY; i++) pState->LENGTH_len[i] = 0;
233c2c66affSColin Finck
234c2c66affSColin Finck return DECR_OK;
235c2c66affSColin Finck }
236c2c66affSColin Finck
237c2c66affSColin Finck
238c2c66affSColin Finck /* Bitstream reading macros:
239c2c66affSColin Finck *
240c2c66affSColin Finck * INIT_BITSTREAM should be used first to set up the system
241c2c66affSColin Finck * READ_BITS(var,n) takes N bits from the buffer and puts them in var
242c2c66affSColin Finck *
243c2c66affSColin Finck * ENSURE_BITS(n) ensures there are at least N bits in the bit buffer
244c2c66affSColin Finck * PEEK_BITS(n) extracts (without removing) N bits from the bit buffer
245c2c66affSColin Finck * REMOVE_BITS(n) removes N bits from the bit buffer
246c2c66affSColin Finck *
247c2c66affSColin Finck * These bit access routines work by using the area beyond the MSB and the
248c2c66affSColin Finck * LSB as a free source of zeroes. This avoids having to mask any bits.
249c2c66affSColin Finck * So we have to know the bit width of the bitbuffer variable. This is
250c2c66affSColin Finck * sizeof(ULONG) * 8, also defined as ULONG_BITS
251c2c66affSColin Finck */
252c2c66affSColin Finck
253c2c66affSColin Finck /* number of bits in ULONG. Note: This must be at multiple of 16, and at
254c2c66affSColin Finck * least 32 for the bitbuffer code to work (ie, it must be able to ensure
255c2c66affSColin Finck * up to 17 bits - that's adding 16 bits when there's one bit left, or
256c2c66affSColin Finck * adding 32 bits when there are no bits left. The code should work fine
257c2c66affSColin Finck * for machines where ULONG >= 32 bits.
258c2c66affSColin Finck */
259c2c66affSColin Finck #define ULONG_BITS (sizeof(ULONG)<<3)
260c2c66affSColin Finck
261c2c66affSColin Finck #define INIT_BITSTREAM do { bitsleft = 0; bitbuf = 0; } while (0)
262c2c66affSColin Finck
263c2c66affSColin Finck #define ENSURE_BITS(n) \
264c2c66affSColin Finck while (bitsleft < (n)) { \
265c2c66affSColin Finck bitbuf |= ((inpos[1]<<8)|inpos[0]) << (ULONG_BITS-16 - bitsleft); \
266c2c66affSColin Finck bitsleft += 16; inpos+=2; \
267c2c66affSColin Finck }
268c2c66affSColin Finck
269c2c66affSColin Finck #define PEEK_BITS(n) (bitbuf >> (ULONG_BITS - (n)))
270c2c66affSColin Finck #define REMOVE_BITS(n) ((bitbuf <<= (n)), (bitsleft -= (n)))
271c2c66affSColin Finck
272c2c66affSColin Finck #define READ_BITS(v,n) do { \
273c2c66affSColin Finck ENSURE_BITS(n); \
274c2c66affSColin Finck (v) = PEEK_BITS(n); \
275c2c66affSColin Finck REMOVE_BITS(n); \
276c2c66affSColin Finck } while (0)
277c2c66affSColin Finck
278c2c66affSColin Finck
279c2c66affSColin Finck /* Huffman macros */
280c2c66affSColin Finck
281c2c66affSColin Finck #define TABLEBITS(tbl) (LZX_##tbl##_TABLEBITS)
282c2c66affSColin Finck #define MAXSYMBOLS(tbl) (LZX_##tbl##_MAXSYMBOLS)
283c2c66affSColin Finck #define SYMTABLE(tbl) (pState->tbl##_table)
284c2c66affSColin Finck #define LENTABLE(tbl) (pState->tbl##_len)
285c2c66affSColin Finck
286c2c66affSColin Finck /* BUILD_TABLE(tablename) builds a huffman lookup table from code lengths.
287c2c66affSColin Finck * In reality, it just calls make_decode_table() with the appropriate
288c2c66affSColin Finck * values - they're all fixed by some #defines anyway, so there's no point
289c2c66affSColin Finck * writing each call out in full by hand.
290c2c66affSColin Finck */
291c2c66affSColin Finck #define BUILD_TABLE(tbl) \
292c2c66affSColin Finck if (make_decode_table( \
293c2c66affSColin Finck MAXSYMBOLS(tbl), TABLEBITS(tbl), LENTABLE(tbl), SYMTABLE(tbl) \
294c2c66affSColin Finck )) { return DECR_ILLEGALDATA; }
295c2c66affSColin Finck
296c2c66affSColin Finck
297c2c66affSColin Finck /* READ_HUFFSYM(tablename, var) decodes one huffman symbol from the
298c2c66affSColin Finck * bitstream using the stated table and puts it in var.
299c2c66affSColin Finck */
300c2c66affSColin Finck #define READ_HUFFSYM(tbl,var) do { \
301c2c66affSColin Finck ENSURE_BITS(16); \
302c2c66affSColin Finck hufftbl = SYMTABLE(tbl); \
303c2c66affSColin Finck if ((i = hufftbl[PEEK_BITS(TABLEBITS(tbl))]) >= MAXSYMBOLS(tbl)) { \
304c2c66affSColin Finck j = 1 << (ULONG_BITS - TABLEBITS(tbl)); \
305c2c66affSColin Finck do { \
306c2c66affSColin Finck j >>= 1; i <<= 1; i |= (bitbuf & j) ? 1 : 0; \
307c2c66affSColin Finck if (!j) { return DECR_ILLEGALDATA; } \
308c2c66affSColin Finck } while ((i = hufftbl[i]) >= MAXSYMBOLS(tbl)); \
309c2c66affSColin Finck } \
310c2c66affSColin Finck j = LENTABLE(tbl)[(var) = i]; \
311c2c66affSColin Finck REMOVE_BITS(j); \
312c2c66affSColin Finck } while (0)
313c2c66affSColin Finck
314c2c66affSColin Finck
315c2c66affSColin Finck /* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols
316c2c66affSColin Finck * first to last in the given table. The code lengths are stored in their
317c2c66affSColin Finck * own special LZX way.
318c2c66affSColin Finck */
319c2c66affSColin Finck #define READ_LENGTHS(tbl,first,last) do { \
320c2c66affSColin Finck lb.bb = bitbuf; lb.bl = bitsleft; lb.ip = inpos; \
321c2c66affSColin Finck if (lzx_read_lens(pState, LENTABLE(tbl),(first),(last),&lb)) { \
322c2c66affSColin Finck return DECR_ILLEGALDATA; \
323c2c66affSColin Finck } \
324c2c66affSColin Finck bitbuf = lb.bb; bitsleft = lb.bl; inpos = lb.ip; \
325c2c66affSColin Finck } while (0)
326c2c66affSColin Finck
327c2c66affSColin Finck
328c2c66affSColin Finck /* make_decode_table(nsyms, nbits, length[], table[])
329c2c66affSColin Finck *
330c2c66affSColin Finck * This function was coded by David Tritscher. It builds a fast huffman
331c2c66affSColin Finck * decoding table out of just a canonical huffman code lengths table.
332c2c66affSColin Finck *
333c2c66affSColin Finck * nsyms = total number of symbols in this huffman tree.
334c2c66affSColin Finck * nbits = any symbols with a code length of nbits or less can be decoded
335c2c66affSColin Finck * in one lookup of the table.
336c2c66affSColin Finck * length = A table to get code lengths from [0 to syms-1]
337c2c66affSColin Finck * table = The table to fill up with decoded symbols and pointers.
338c2c66affSColin Finck *
339c2c66affSColin Finck * Returns 0 for OK or 1 for error
340c2c66affSColin Finck */
341c2c66affSColin Finck
make_decode_table(ULONG nsyms,ULONG nbits,UBYTE * length,UWORD * table)342c2c66affSColin Finck static int make_decode_table(ULONG nsyms, ULONG nbits, UBYTE *length, UWORD *table) {
343c2c66affSColin Finck register UWORD sym;
344c2c66affSColin Finck register ULONG leaf;
345c2c66affSColin Finck register UBYTE bit_num = 1;
346c2c66affSColin Finck ULONG fill;
347c2c66affSColin Finck ULONG pos = 0; /* the current position in the decode table */
348c2c66affSColin Finck ULONG table_mask = 1 << nbits;
349c2c66affSColin Finck ULONG bit_mask = table_mask >> 1; /* don't do 0 length codes */
350c2c66affSColin Finck ULONG next_symbol = bit_mask; /* base of allocation for long codes */
351c2c66affSColin Finck
352c2c66affSColin Finck /* fill entries for codes short enough for a direct mapping */
353c2c66affSColin Finck while (bit_num <= nbits) {
354c2c66affSColin Finck for (sym = 0; sym < nsyms; sym++) {
355c2c66affSColin Finck if (length[sym] == bit_num) {
356c2c66affSColin Finck leaf = pos;
357c2c66affSColin Finck
358c2c66affSColin Finck if((pos += bit_mask) > table_mask) return 1; /* table overrun */
359c2c66affSColin Finck
360c2c66affSColin Finck /* fill all possible lookups of this symbol with the symbol itself */
361c2c66affSColin Finck fill = bit_mask;
362c2c66affSColin Finck while (fill-- > 0) table[leaf++] = sym;
363c2c66affSColin Finck }
364c2c66affSColin Finck }
365c2c66affSColin Finck bit_mask >>= 1;
366c2c66affSColin Finck bit_num++;
367c2c66affSColin Finck }
368c2c66affSColin Finck
369c2c66affSColin Finck /* if there are any codes longer than nbits */
370c2c66affSColin Finck if (pos != table_mask) {
371c2c66affSColin Finck /* clear the remainder of the table */
372c2c66affSColin Finck for (sym = pos; sym < table_mask; sym++) table[sym] = 0;
373c2c66affSColin Finck
374c2c66affSColin Finck /* give ourselves room for codes to grow by up to 16 more bits */
375c2c66affSColin Finck pos <<= 16;
376c2c66affSColin Finck table_mask <<= 16;
377c2c66affSColin Finck bit_mask = 1 << 15;
378c2c66affSColin Finck
379c2c66affSColin Finck while (bit_num <= 16) {
380c2c66affSColin Finck for (sym = 0; sym < nsyms; sym++) {
381c2c66affSColin Finck if (length[sym] == bit_num) {
382c2c66affSColin Finck leaf = pos >> 16;
383c2c66affSColin Finck for (fill = 0; fill < bit_num - nbits; fill++) {
384c2c66affSColin Finck /* if this path hasn't been taken yet, 'allocate' two entries */
385c2c66affSColin Finck if (table[leaf] == 0) {
386c2c66affSColin Finck table[(next_symbol << 1)] = 0;
387c2c66affSColin Finck table[(next_symbol << 1) + 1] = 0;
388c2c66affSColin Finck table[leaf] = next_symbol++;
389c2c66affSColin Finck }
390c2c66affSColin Finck /* follow the path and select either left or right for next bit */
391c2c66affSColin Finck leaf = table[leaf] << 1;
392c2c66affSColin Finck if ((pos >> (15-fill)) & 1) leaf++;
393c2c66affSColin Finck }
394c2c66affSColin Finck table[leaf] = sym;
395c2c66affSColin Finck
396c2c66affSColin Finck if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
397c2c66affSColin Finck }
398c2c66affSColin Finck }
399c2c66affSColin Finck bit_mask >>= 1;
400c2c66affSColin Finck bit_num++;
401c2c66affSColin Finck }
402c2c66affSColin Finck }
403c2c66affSColin Finck
404c2c66affSColin Finck /* full table? */
405c2c66affSColin Finck if (pos == table_mask) return 0;
406c2c66affSColin Finck
407c2c66affSColin Finck /* either erroneous table, or all elements are 0 - let's find out. */
408c2c66affSColin Finck for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1;
409c2c66affSColin Finck return 0;
410c2c66affSColin Finck }
411c2c66affSColin Finck
412c2c66affSColin Finck struct lzx_bits {
413c2c66affSColin Finck ULONG bb;
414c2c66affSColin Finck int bl;
415c2c66affSColin Finck UBYTE *ip;
416c2c66affSColin Finck };
417c2c66affSColin Finck
lzx_read_lens(struct LZXstate * pState,UBYTE * lens,ULONG first,ULONG last,struct lzx_bits * lb)418c2c66affSColin Finck static int lzx_read_lens(struct LZXstate *pState, UBYTE *lens, ULONG first, ULONG last, struct lzx_bits *lb) {
419c2c66affSColin Finck ULONG i,j, x,y;
420c2c66affSColin Finck int z;
421c2c66affSColin Finck
422c2c66affSColin Finck register ULONG bitbuf = lb->bb;
423c2c66affSColin Finck register int bitsleft = lb->bl;
424c2c66affSColin Finck UBYTE *inpos = lb->ip;
425c2c66affSColin Finck UWORD *hufftbl;
426c2c66affSColin Finck
427c2c66affSColin Finck for (x = 0; x < 20; x++) {
428c2c66affSColin Finck READ_BITS(y, 4);
429c2c66affSColin Finck LENTABLE(PRETREE)[x] = y;
430c2c66affSColin Finck }
431c2c66affSColin Finck BUILD_TABLE(PRETREE);
432c2c66affSColin Finck
433c2c66affSColin Finck for (x = first; x < last; ) {
434c2c66affSColin Finck READ_HUFFSYM(PRETREE, z);
435c2c66affSColin Finck if (z == 17) {
436c2c66affSColin Finck READ_BITS(y, 4); y += 4;
437c2c66affSColin Finck while (y--) lens[x++] = 0;
438c2c66affSColin Finck }
439c2c66affSColin Finck else if (z == 18) {
440c2c66affSColin Finck READ_BITS(y, 5); y += 20;
441c2c66affSColin Finck while (y--) lens[x++] = 0;
442c2c66affSColin Finck }
443c2c66affSColin Finck else if (z == 19) {
444c2c66affSColin Finck READ_BITS(y, 1); y += 4;
445c2c66affSColin Finck READ_HUFFSYM(PRETREE, z);
446c2c66affSColin Finck z = lens[x] - z; if (z < 0) z += 17;
447c2c66affSColin Finck while (y--) lens[x++] = z;
448c2c66affSColin Finck }
449c2c66affSColin Finck else {
450c2c66affSColin Finck z = lens[x] - z; if (z < 0) z += 17;
451c2c66affSColin Finck lens[x++] = z;
452c2c66affSColin Finck }
453c2c66affSColin Finck }
454c2c66affSColin Finck
455c2c66affSColin Finck lb->bb = bitbuf;
456c2c66affSColin Finck lb->bl = bitsleft;
457c2c66affSColin Finck lb->ip = inpos;
458c2c66affSColin Finck return 0;
459c2c66affSColin Finck }
460c2c66affSColin Finck
LZXdecompress(struct LZXstate * pState,unsigned char * inpos,unsigned char * outpos,int inlen,int outlen)461c2c66affSColin Finck int LZXdecompress(struct LZXstate *pState, unsigned char *inpos, unsigned char *outpos, int inlen, int outlen) {
462c2c66affSColin Finck UBYTE *endinp = inpos + inlen;
463c2c66affSColin Finck UBYTE *window = pState->window;
464c2c66affSColin Finck UBYTE *runsrc, *rundest;
465c2c66affSColin Finck UWORD *hufftbl; /* used in READ_HUFFSYM macro as chosen decoding table */
466c2c66affSColin Finck
467c2c66affSColin Finck ULONG window_posn = pState->window_posn;
468c2c66affSColin Finck ULONG window_size = pState->window_size;
469c2c66affSColin Finck ULONG R0 = pState->R0;
470c2c66affSColin Finck ULONG R1 = pState->R1;
471c2c66affSColin Finck ULONG R2 = pState->R2;
472c2c66affSColin Finck
473c2c66affSColin Finck register ULONG bitbuf;
474c2c66affSColin Finck register int bitsleft;
475c2c66affSColin Finck ULONG match_offset, i,j,k; /* ijk used in READ_HUFFSYM macro */
476c2c66affSColin Finck struct lzx_bits lb; /* used in READ_LENGTHS macro */
477c2c66affSColin Finck
478c2c66affSColin Finck int togo = outlen, this_run, main_element, aligned_bits;
479c2c66affSColin Finck int match_length, length_footer, extra, verbatim_bits;
480c2c66affSColin Finck int copy_length;
481c2c66affSColin Finck
482c2c66affSColin Finck INIT_BITSTREAM;
483c2c66affSColin Finck
484c2c66affSColin Finck /* read header if necessary */
485c2c66affSColin Finck if (!pState->header_read) {
486c2c66affSColin Finck i = j = 0;
487c2c66affSColin Finck READ_BITS(k, 1); if (k) { READ_BITS(i,16); READ_BITS(j,16); }
488c2c66affSColin Finck pState->intel_filesize = (i << 16) | j; /* or 0 if not encoded */
489c2c66affSColin Finck pState->header_read = 1;
490c2c66affSColin Finck }
491c2c66affSColin Finck
492c2c66affSColin Finck /* main decoding loop */
493c2c66affSColin Finck while (togo > 0) {
494c2c66affSColin Finck /* last block finished, new block expected */
495c2c66affSColin Finck if (pState->block_remaining == 0) {
496c2c66affSColin Finck if (pState->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) {
497c2c66affSColin Finck if (pState->block_length & 1) inpos++; /* realign bitstream to word */
498c2c66affSColin Finck INIT_BITSTREAM;
499c2c66affSColin Finck }
500c2c66affSColin Finck
501c2c66affSColin Finck READ_BITS(pState->block_type, 3);
502c2c66affSColin Finck READ_BITS(i, 16);
503c2c66affSColin Finck READ_BITS(j, 8);
504c2c66affSColin Finck pState->block_remaining = pState->block_length = (i << 8) | j;
505c2c66affSColin Finck
506c2c66affSColin Finck switch (pState->block_type) {
507c2c66affSColin Finck case LZX_BLOCKTYPE_ALIGNED:
508c2c66affSColin Finck for (i = 0; i < 8; i++) { READ_BITS(j, 3); LENTABLE(ALIGNED)[i] = j; }
509c2c66affSColin Finck BUILD_TABLE(ALIGNED);
510c2c66affSColin Finck /* rest of aligned header is same as verbatim */
511c2c66affSColin Finck
512c2c66affSColin Finck case LZX_BLOCKTYPE_VERBATIM:
513c2c66affSColin Finck READ_LENGTHS(MAINTREE, 0, 256);
514c2c66affSColin Finck READ_LENGTHS(MAINTREE, 256, pState->main_elements);
515c2c66affSColin Finck BUILD_TABLE(MAINTREE);
516c2c66affSColin Finck if (LENTABLE(MAINTREE)[0xE8] != 0) pState->intel_started = 1;
517c2c66affSColin Finck
518c2c66affSColin Finck READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS);
519c2c66affSColin Finck BUILD_TABLE(LENGTH);
520c2c66affSColin Finck break;
521c2c66affSColin Finck
522c2c66affSColin Finck case LZX_BLOCKTYPE_UNCOMPRESSED:
523c2c66affSColin Finck pState->intel_started = 1; /* because we can't assume otherwise */
524c2c66affSColin Finck ENSURE_BITS(16); /* get up to 16 pad bits into the buffer */
525c2c66affSColin Finck if (bitsleft > 16) inpos -= 2; /* and align the bitstream! */
526c2c66affSColin Finck R0 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
527c2c66affSColin Finck R1 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
528c2c66affSColin Finck R2 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
529c2c66affSColin Finck break;
530c2c66affSColin Finck
531c2c66affSColin Finck default:
532c2c66affSColin Finck return DECR_ILLEGALDATA;
533c2c66affSColin Finck }
534c2c66affSColin Finck }
535c2c66affSColin Finck
536c2c66affSColin Finck /* buffer exhaustion check */
537c2c66affSColin Finck if (inpos > endinp) {
538c2c66affSColin Finck /* it's possible to have a file where the next run is less than
539c2c66affSColin Finck * 16 bits in size. In this case, the READ_HUFFSYM() macro used
540c2c66affSColin Finck * in building the tables will exhaust the buffer, so we should
541c2c66affSColin Finck * allow for this, but not allow those accidentally read bits to
542c2c66affSColin Finck * be used (so we check that there are at least 16 bits
543c2c66affSColin Finck * remaining - in this boundary case they aren't really part of
544c2c66affSColin Finck * the compressed data)
545c2c66affSColin Finck */
546c2c66affSColin Finck if (inpos > (endinp+2) || bitsleft < 16) return DECR_ILLEGALDATA;
547c2c66affSColin Finck }
548c2c66affSColin Finck
549c2c66affSColin Finck while ((this_run = pState->block_remaining) > 0 && togo > 0) {
550c2c66affSColin Finck if (this_run > togo) this_run = togo;
551c2c66affSColin Finck togo -= this_run;
552c2c66affSColin Finck pState->block_remaining -= this_run;
553c2c66affSColin Finck
554c2c66affSColin Finck /* apply 2^x-1 mask */
555c2c66affSColin Finck window_posn &= window_size - 1;
556c2c66affSColin Finck /* runs can't straddle the window wraparound */
557c2c66affSColin Finck if ((window_posn + this_run) > window_size)
558c2c66affSColin Finck return DECR_DATAFORMAT;
559c2c66affSColin Finck
560c2c66affSColin Finck switch (pState->block_type) {
561c2c66affSColin Finck
562c2c66affSColin Finck case LZX_BLOCKTYPE_VERBATIM:
563c2c66affSColin Finck while (this_run > 0) {
564c2c66affSColin Finck READ_HUFFSYM(MAINTREE, main_element);
565c2c66affSColin Finck
566c2c66affSColin Finck if (main_element < LZX_NUM_CHARS) {
567c2c66affSColin Finck /* literal: 0 to LZX_NUM_CHARS-1 */
568c2c66affSColin Finck window[window_posn++] = main_element;
569c2c66affSColin Finck this_run--;
570c2c66affSColin Finck }
571c2c66affSColin Finck else {
572c2c66affSColin Finck /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
573c2c66affSColin Finck main_element -= LZX_NUM_CHARS;
574c2c66affSColin Finck
575c2c66affSColin Finck match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
576c2c66affSColin Finck if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
577c2c66affSColin Finck READ_HUFFSYM(LENGTH, length_footer);
578c2c66affSColin Finck match_length += length_footer;
579c2c66affSColin Finck }
580c2c66affSColin Finck match_length += LZX_MIN_MATCH;
581c2c66affSColin Finck
582c2c66affSColin Finck match_offset = main_element >> 3;
583c2c66affSColin Finck
584c2c66affSColin Finck if (match_offset > 2) {
585c2c66affSColin Finck /* not repeated offset */
586c2c66affSColin Finck if (match_offset != 3) {
587c2c66affSColin Finck extra = extra_bits[match_offset];
588c2c66affSColin Finck READ_BITS(verbatim_bits, extra);
589c2c66affSColin Finck match_offset = position_base[match_offset] - 2 + verbatim_bits;
590c2c66affSColin Finck }
591c2c66affSColin Finck else {
592c2c66affSColin Finck match_offset = 1;
593c2c66affSColin Finck }
594c2c66affSColin Finck
595c2c66affSColin Finck /* update repeated offset LRU queue */
596c2c66affSColin Finck R2 = R1; R1 = R0; R0 = match_offset;
597c2c66affSColin Finck }
598c2c66affSColin Finck else if (match_offset == 0) {
599c2c66affSColin Finck match_offset = R0;
600c2c66affSColin Finck }
601c2c66affSColin Finck else if (match_offset == 1) {
602c2c66affSColin Finck match_offset = R1;
603c2c66affSColin Finck R1 = R0; R0 = match_offset;
604c2c66affSColin Finck }
605c2c66affSColin Finck else /* match_offset == 2 */ {
606c2c66affSColin Finck match_offset = R2;
607c2c66affSColin Finck R2 = R0; R0 = match_offset;
608c2c66affSColin Finck }
609c2c66affSColin Finck
610c2c66affSColin Finck rundest = window + window_posn;
611c2c66affSColin Finck this_run -= match_length;
612c2c66affSColin Finck
613c2c66affSColin Finck /* copy any wrapped around source data */
614c2c66affSColin Finck if (window_posn >= match_offset) {
615c2c66affSColin Finck /* no wrap */
616c2c66affSColin Finck runsrc = rundest - match_offset;
617c2c66affSColin Finck } else {
618c2c66affSColin Finck runsrc = rundest + (window_size - match_offset);
619c2c66affSColin Finck copy_length = match_offset - window_posn;
620c2c66affSColin Finck if (copy_length < match_length) {
621c2c66affSColin Finck match_length -= copy_length;
622c2c66affSColin Finck window_posn += copy_length;
623c2c66affSColin Finck while (copy_length-- > 0) *rundest++ = *runsrc++;
624c2c66affSColin Finck runsrc = window;
625c2c66affSColin Finck }
626c2c66affSColin Finck }
627c2c66affSColin Finck window_posn += match_length;
628c2c66affSColin Finck
629c2c66affSColin Finck /* copy match data - no worries about destination wraps */
630c2c66affSColin Finck while (match_length-- > 0) *rundest++ = *runsrc++;
631c2c66affSColin Finck
632c2c66affSColin Finck }
633c2c66affSColin Finck }
634c2c66affSColin Finck break;
635c2c66affSColin Finck
636c2c66affSColin Finck case LZX_BLOCKTYPE_ALIGNED:
637c2c66affSColin Finck while (this_run > 0) {
638c2c66affSColin Finck READ_HUFFSYM(MAINTREE, main_element);
639c2c66affSColin Finck
640c2c66affSColin Finck if (main_element < LZX_NUM_CHARS) {
641c2c66affSColin Finck /* literal: 0 to LZX_NUM_CHARS-1 */
642c2c66affSColin Finck window[window_posn++] = main_element;
643c2c66affSColin Finck this_run--;
644c2c66affSColin Finck }
645c2c66affSColin Finck else {
646c2c66affSColin Finck /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
647c2c66affSColin Finck main_element -= LZX_NUM_CHARS;
648c2c66affSColin Finck
649c2c66affSColin Finck match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
650c2c66affSColin Finck if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
651c2c66affSColin Finck READ_HUFFSYM(LENGTH, length_footer);
652c2c66affSColin Finck match_length += length_footer;
653c2c66affSColin Finck }
654c2c66affSColin Finck match_length += LZX_MIN_MATCH;
655c2c66affSColin Finck
656c2c66affSColin Finck match_offset = main_element >> 3;
657c2c66affSColin Finck
658c2c66affSColin Finck if (match_offset > 2) {
659c2c66affSColin Finck /* not repeated offset */
660c2c66affSColin Finck extra = extra_bits[match_offset];
661c2c66affSColin Finck match_offset = position_base[match_offset] - 2;
662c2c66affSColin Finck if (extra > 3) {
663c2c66affSColin Finck /* verbatim and aligned bits */
664c2c66affSColin Finck extra -= 3;
665c2c66affSColin Finck READ_BITS(verbatim_bits, extra);
666c2c66affSColin Finck match_offset += (verbatim_bits << 3);
667c2c66affSColin Finck READ_HUFFSYM(ALIGNED, aligned_bits);
668c2c66affSColin Finck match_offset += aligned_bits;
669c2c66affSColin Finck }
670c2c66affSColin Finck else if (extra == 3) {
671c2c66affSColin Finck /* aligned bits only */
672c2c66affSColin Finck READ_HUFFSYM(ALIGNED, aligned_bits);
673c2c66affSColin Finck match_offset += aligned_bits;
674c2c66affSColin Finck }
675c2c66affSColin Finck else if (extra > 0) { /* extra==1, extra==2 */
676c2c66affSColin Finck /* verbatim bits only */
677c2c66affSColin Finck READ_BITS(verbatim_bits, extra);
678c2c66affSColin Finck match_offset += verbatim_bits;
679c2c66affSColin Finck }
680c2c66affSColin Finck else /* extra == 0 */ {
681c2c66affSColin Finck /* ??? */
682c2c66affSColin Finck match_offset = 1;
683c2c66affSColin Finck }
684c2c66affSColin Finck
685c2c66affSColin Finck /* update repeated offset LRU queue */
686c2c66affSColin Finck R2 = R1; R1 = R0; R0 = match_offset;
687c2c66affSColin Finck }
688c2c66affSColin Finck else if (match_offset == 0) {
689c2c66affSColin Finck match_offset = R0;
690c2c66affSColin Finck }
691c2c66affSColin Finck else if (match_offset == 1) {
692c2c66affSColin Finck match_offset = R1;
693c2c66affSColin Finck R1 = R0; R0 = match_offset;
694c2c66affSColin Finck }
695c2c66affSColin Finck else /* match_offset == 2 */ {
696c2c66affSColin Finck match_offset = R2;
697c2c66affSColin Finck R2 = R0; R0 = match_offset;
698c2c66affSColin Finck }
699c2c66affSColin Finck
700c2c66affSColin Finck rundest = window + window_posn;
701c2c66affSColin Finck this_run -= match_length;
702c2c66affSColin Finck
703c2c66affSColin Finck /* copy any wrapped around source data */
704c2c66affSColin Finck if (window_posn >= match_offset) {
705c2c66affSColin Finck /* no wrap */
706c2c66affSColin Finck runsrc = rundest - match_offset;
707c2c66affSColin Finck } else {
708c2c66affSColin Finck runsrc = rundest + (window_size - match_offset);
709c2c66affSColin Finck copy_length = match_offset - window_posn;
710c2c66affSColin Finck if (copy_length < match_length) {
711c2c66affSColin Finck match_length -= copy_length;
712c2c66affSColin Finck window_posn += copy_length;
713c2c66affSColin Finck while (copy_length-- > 0) *rundest++ = *runsrc++;
714c2c66affSColin Finck runsrc = window;
715c2c66affSColin Finck }
716c2c66affSColin Finck }
717c2c66affSColin Finck window_posn += match_length;
718c2c66affSColin Finck
719c2c66affSColin Finck /* copy match data - no worries about destination wraps */
720c2c66affSColin Finck while (match_length-- > 0) *rundest++ = *runsrc++;
721c2c66affSColin Finck
722c2c66affSColin Finck }
723c2c66affSColin Finck }
724c2c66affSColin Finck break;
725c2c66affSColin Finck
726c2c66affSColin Finck case LZX_BLOCKTYPE_UNCOMPRESSED:
727c2c66affSColin Finck if ((inpos + this_run) > endinp) return DECR_ILLEGALDATA;
728c2c66affSColin Finck memcpy(window + window_posn, inpos, (size_t) this_run);
729c2c66affSColin Finck inpos += this_run; window_posn += this_run;
730c2c66affSColin Finck break;
731c2c66affSColin Finck
732c2c66affSColin Finck default:
733c2c66affSColin Finck return DECR_ILLEGALDATA; /* might as well */
734c2c66affSColin Finck }
735c2c66affSColin Finck
736c2c66affSColin Finck }
737c2c66affSColin Finck }
738c2c66affSColin Finck
739c2c66affSColin Finck if (togo != 0) return DECR_ILLEGALDATA;
740c2c66affSColin Finck memcpy(outpos, window + ((!window_posn) ? window_size : window_posn) - outlen, (size_t) outlen);
741c2c66affSColin Finck
742c2c66affSColin Finck pState->window_posn = window_posn;
743c2c66affSColin Finck pState->R0 = R0;
744c2c66affSColin Finck pState->R1 = R1;
745c2c66affSColin Finck pState->R2 = R2;
746c2c66affSColin Finck
747c2c66affSColin Finck /* intel E8 decoding */
748c2c66affSColin Finck if ((pState->frames_read++ < 32768) && pState->intel_filesize != 0) {
749c2c66affSColin Finck if (outlen <= 6 || !pState->intel_started) {
750c2c66affSColin Finck pState->intel_curpos += outlen;
751c2c66affSColin Finck }
752c2c66affSColin Finck else {
753c2c66affSColin Finck UBYTE *data = outpos;
754c2c66affSColin Finck UBYTE *dataend = data + outlen - 10;
755c2c66affSColin Finck LONG curpos = pState->intel_curpos;
756c2c66affSColin Finck LONG filesize = pState->intel_filesize;
757c2c66affSColin Finck LONG abs_off, rel_off;
758c2c66affSColin Finck
759c2c66affSColin Finck pState->intel_curpos = curpos + outlen;
760c2c66affSColin Finck
761c2c66affSColin Finck while (data < dataend) {
762c2c66affSColin Finck if (*data++ != 0xE8) { curpos++; continue; }
763c2c66affSColin Finck abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
764c2c66affSColin Finck if ((abs_off >= -curpos) && (abs_off < filesize)) {
765c2c66affSColin Finck rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
766c2c66affSColin Finck data[0] = (UBYTE) rel_off;
767c2c66affSColin Finck data[1] = (UBYTE) (rel_off >> 8);
768c2c66affSColin Finck data[2] = (UBYTE) (rel_off >> 16);
769c2c66affSColin Finck data[3] = (UBYTE) (rel_off >> 24);
770c2c66affSColin Finck }
771c2c66affSColin Finck data += 4;
772c2c66affSColin Finck curpos += 5;
773c2c66affSColin Finck }
774c2c66affSColin Finck }
775c2c66affSColin Finck }
776c2c66affSColin Finck return DECR_OK;
777c2c66affSColin Finck }
778c2c66affSColin Finck
779c2c66affSColin Finck #ifdef LZX_CHM_TESTDRIVER
main(int c,char ** v)780c2c66affSColin Finck int main(int c, char **v)
781c2c66affSColin Finck {
782c2c66affSColin Finck FILE *fin, *fout;
783c2c66affSColin Finck struct LZXstate state;
784c2c66affSColin Finck UBYTE ibuf[16384];
785c2c66affSColin Finck UBYTE obuf[32768];
786c2c66affSColin Finck int ilen, olen;
787c2c66affSColin Finck int status;
788c2c66affSColin Finck int i;
789c2c66affSColin Finck int count=0;
790c2c66affSColin Finck int w = atoi(v[1]);
791*da0cd273SAmine Khaldi LZXinit(&state, 1 << w);
792c2c66affSColin Finck fout = fopen(v[2], "wb");
793c2c66affSColin Finck for (i=3; i<c; i++)
794c2c66affSColin Finck {
795c2c66affSColin Finck fin = fopen(v[i], "rb");
796c2c66affSColin Finck ilen = fread(ibuf, 1, 16384, fin);
797c2c66affSColin Finck status = LZXdecompress(&state, ibuf, obuf, ilen, 32768);
798c2c66affSColin Finck switch (status)
799c2c66affSColin Finck {
800c2c66affSColin Finck case DECR_OK:
801c2c66affSColin Finck printf("ok\n");
802c2c66affSColin Finck fwrite(obuf, 1, 32768, fout);
803c2c66affSColin Finck break;
804c2c66affSColin Finck case DECR_DATAFORMAT:
805c2c66affSColin Finck printf("bad format\n");
806c2c66affSColin Finck break;
807c2c66affSColin Finck case DECR_ILLEGALDATA:
808c2c66affSColin Finck printf("illegal data\n");
809c2c66affSColin Finck break;
810c2c66affSColin Finck case DECR_NOMEMORY:
811c2c66affSColin Finck printf("no memory\n");
812c2c66affSColin Finck break;
813c2c66affSColin Finck default:
814c2c66affSColin Finck break;
815c2c66affSColin Finck }
816c2c66affSColin Finck fclose(fin);
817c2c66affSColin Finck if (++count == 2)
818c2c66affSColin Finck {
819c2c66affSColin Finck count = 0;
820c2c66affSColin Finck LZXreset(&state);
821c2c66affSColin Finck }
822c2c66affSColin Finck }
823c2c66affSColin Finck fclose(fout);
824c2c66affSColin Finck }
825c2c66affSColin Finck #endif
826