diff options
Diffstat (limited to 'rbutil/rbutilqt/mspack/lzxd.c')
-rw-r--r-- | rbutil/rbutilqt/mspack/lzxd.c | 793 |
1 files changed, 480 insertions, 313 deletions
diff --git a/rbutil/rbutilqt/mspack/lzxd.c b/rbutil/rbutilqt/mspack/lzxd.c index 9b26bac3e0..88cfd90c2a 100644 --- a/rbutil/rbutilqt/mspack/lzxd.c +++ b/rbutil/rbutilqt/mspack/lzxd.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* This file is part of libmspack. | 1 | /* This file is part of libmspack. |
2 | * (C) 2003-2004 Stuart Caie. | 2 | * (C) 2003-2013 Stuart Caie. |
3 | * | 3 | * |
4 | * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted | 4 | * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted |
5 | * by Microsoft Corporation. | 5 | * by Microsoft Corporation. |
@@ -70,6 +70,10 @@ | |||
70 | * The maximum window size has increased from 2MB to 32MB. This also | 70 | * The maximum window size has increased from 2MB to 32MB. This also |
71 | * increases the maximum number of position slots, etc. | 71 | * increases the maximum number of position slots, etc. |
72 | * | 72 | * |
73 | * If the match length is 257 (the maximum possible), this signals | ||
74 | * a further length decoding step, that allows for matches up to | ||
75 | * 33024 bytes long. | ||
76 | * | ||
73 | * The format now allows for "reference data", supplied by the caller. | 77 | * The format now allows for "reference data", supplied by the caller. |
74 | * If match offsets go further back than the number of bytes | 78 | * If match offsets go further back than the number of bytes |
75 | * decompressed so far, that is them accessing the reference data. | 79 | * decompressed so far, that is them accessing the reference data. |
@@ -79,11 +83,11 @@ | |||
79 | #define BITS_TYPE struct lzxd_stream | 83 | #define BITS_TYPE struct lzxd_stream |
80 | #define BITS_VAR lzx | 84 | #define BITS_VAR lzx |
81 | #define BITS_ORDER_MSB | 85 | #define BITS_ORDER_MSB |
82 | #define READ_BYTES do { \ | 86 | #define READ_BYTES do { \ |
83 | unsigned char b0, b1; \ | 87 | unsigned char b0, b1; \ |
84 | READ_IF_NEEDED; b0 = *i_ptr++; \ | 88 | READ_IF_NEEDED; b0 = *i_ptr++; \ |
85 | READ_IF_NEEDED; b1 = *i_ptr++; \ | 89 | READ_IF_NEEDED; b1 = *i_ptr++; \ |
86 | INJECT_BITS((b1 << 8) | b0, 16); \ | 90 | INJECT_BITS((b1 << 8) | b0, 16); \ |
87 | } while (0) | 91 | } while (0) |
88 | #include "readbits.h" | 92 | #include "readbits.h" |
89 | 93 | ||
@@ -96,43 +100,43 @@ | |||
96 | #include "readhuff.h" | 100 | #include "readhuff.h" |
97 | 101 | ||
98 | /* BUILD_TABLE(tbl) builds a huffman lookup table from code lengths */ | 102 | /* BUILD_TABLE(tbl) builds a huffman lookup table from code lengths */ |
99 | #define BUILD_TABLE(tbl) \ | 103 | #define BUILD_TABLE(tbl) \ |
100 | if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \ | 104 | if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \ |
101 | &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \ | 105 | &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \ |
102 | { \ | 106 | { \ |
103 | D(("failed to build %s table", #tbl)) \ | 107 | D(("failed to build %s table", #tbl)) \ |
104 | return lzx->error = MSPACK_ERR_DECRUNCH; \ | 108 | return lzx->error = MSPACK_ERR_DECRUNCH; \ |
105 | } | 109 | } |
106 | 110 | ||
107 | #define BUILD_TABLE_MAYBE_EMPTY(tbl) do { \ | 111 | #define BUILD_TABLE_MAYBE_EMPTY(tbl) do { \ |
108 | lzx->tbl##_empty = 0; \ | 112 | lzx->tbl##_empty = 0; \ |
109 | if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \ | 113 | if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \ |
110 | &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \ | 114 | &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \ |
111 | { \ | 115 | { \ |
112 | for (i = 0; i < MAXSYMBOLS(tbl); i++) { \ | 116 | for (i = 0; i < MAXSYMBOLS(tbl); i++) { \ |
113 | if (HUFF_LEN(tbl, i) > 0) { \ | 117 | if (HUFF_LEN(tbl, i) > 0) { \ |
114 | D(("failed to build %s table", #tbl)) \ | 118 | D(("failed to build %s table", #tbl)) \ |
115 | return lzx->error = MSPACK_ERR_DECRUNCH; \ | 119 | return lzx->error = MSPACK_ERR_DECRUNCH; \ |
116 | } \ | 120 | } \ |
117 | } \ | 121 | } \ |
118 | /* empty tree - allow it, but don't decode symbols with it */ \ | 122 | /* empty tree - allow it, but don't decode symbols with it */ \ |
119 | lzx->tbl##_empty = 1; \ | 123 | lzx->tbl##_empty = 1; \ |
120 | } \ | 124 | } \ |
121 | } while (0) | 125 | } while (0) |
122 | 126 | ||
123 | /* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols | 127 | /* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols |
124 | * first to last in the given table. The code lengths are stored in their | 128 | * first to last in the given table. The code lengths are stored in their |
125 | * own special LZX way. | 129 | * own special LZX way. |
126 | */ | 130 | */ |
127 | #define READ_LENGTHS(tbl, first, last) do { \ | 131 | #define READ_LENGTHS(tbl, first, last) do { \ |
128 | STORE_BITS; \ | 132 | STORE_BITS; \ |
129 | if (lzxd_read_lens(lzx, &HUFF_LEN(tbl, 0), (first), \ | 133 | if (lzxd_read_lens(lzx, &HUFF_LEN(tbl, 0), (first), \ |
130 | (unsigned int)(last))) return lzx->error; \ | 134 | (unsigned int)(last))) return lzx->error; \ |
131 | RESTORE_BITS; \ | 135 | RESTORE_BITS; \ |
132 | } while (0) | 136 | } while (0) |
133 | 137 | ||
134 | static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens, | 138 | static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens, |
135 | unsigned int first, unsigned int last) | 139 | unsigned int first, unsigned int last) |
136 | { | 140 | { |
137 | /* bit buffer and huffman symbol decode variables */ | 141 | /* bit buffer and huffman symbol decode variables */ |
138 | register unsigned int bit_buffer; | 142 | register unsigned int bit_buffer; |
@@ -189,27 +193,70 @@ static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens, | |||
189 | * a small 'position slot' number and a small offset from that slot are | 193 | * a small 'position slot' number and a small offset from that slot are |
190 | * encoded instead of one large offset. | 194 | * encoded instead of one large offset. |
191 | * | 195 | * |
196 | * The number of slots is decided by how many are needed to encode the | ||
197 | * largest offset for a given window size. This is easy when the gap between | ||
198 | * slots is less than 128Kb, it's a linear relationship. But when extra_bits | ||
199 | * reaches its limit of 17 (because LZX can only ensure reading 17 bits of | ||
200 | * data at a time), we can only jump 128Kb at a time and have to start | ||
201 | * using more and more position slots as each window size doubles. | ||
202 | * | ||
192 | * position_base[] is an index to the position slot bases | 203 | * position_base[] is an index to the position slot bases |
193 | * | 204 | * |
194 | * extra_bits[] states how many bits of offset-from-base data is needed. | 205 | * extra_bits[] states how many bits of offset-from-base data is needed. |
195 | * | 206 | * |
196 | * They are generated like so: | 207 | * They are calculated as follows: |
197 | * for (i = 0; i < 4; i++) extra_bits[i] = 0; | 208 | * extra_bits[i] = 0 where i < 4 |
198 | * for (i = 4, j = 0; i < 36; i+=2) extra_bits[i] = extra_bits[i+1] = j++; | 209 | * extra_bits[i] = floor(i/2)-1 where i >= 4 && i < 36 |
199 | * for (i = 36; i < 51; i++) extra_bits[i] = 17; | 210 | * extra_bits[i] = 17 where i >= 36 |
200 | * for (i = 0, j = 0; i < 51; j += 1 << extra_bits[i++]) position_base[i] = j; | 211 | * position_base[0] = 0 |
212 | * position_base[i] = position_base[i-1] + (1 << extra_bits[i-1]) | ||
201 | */ | 213 | */ |
202 | static const unsigned int position_base[51] = { | 214 | static const unsigned int position_slots[11] = { |
203 | 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, | 215 | 30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290 |
204 | 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, | 216 | }; |
205 | 16384, 24576, 32768, 49152, 65536, 98304, 131072, 196608, 262144, | 217 | static const unsigned char extra_bits[36] = { |
206 | 393216, 524288, 655360, 786432, 917504, 1048576, 1179648, 1310720, | 218 | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, |
207 | 1441792, 1572864, 1703936, 1835008, 1966080, 2097152 | 219 | 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16 |
208 | }; | 220 | }; |
209 | static const unsigned char extra_bits[51] = { | 221 | static const unsigned int position_base[290] = { |
210 | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, | 222 | 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, |
211 | 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, | 223 | 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, |
212 | 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 | 224 | 49152, 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360, |
225 | 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936, | ||
226 | 1835008, 1966080, 2097152, 2228224, 2359296, 2490368, 2621440, 2752512, | ||
227 | 2883584, 3014656, 3145728, 3276800, 3407872, 3538944, 3670016, 3801088, | ||
228 | 3932160, 4063232, 4194304, 4325376, 4456448, 4587520, 4718592, 4849664, | ||
229 | 4980736, 5111808, 5242880, 5373952, 5505024, 5636096, 5767168, 5898240, | ||
230 | 6029312, 6160384, 6291456, 6422528, 6553600, 6684672, 6815744, 6946816, | ||
231 | 7077888, 7208960, 7340032, 7471104, 7602176, 7733248, 7864320, 7995392, | ||
232 | 8126464, 8257536, 8388608, 8519680, 8650752, 8781824, 8912896, 9043968, | ||
233 | 9175040, 9306112, 9437184, 9568256, 9699328, 9830400, 9961472, 10092544, | ||
234 | 10223616, 10354688, 10485760, 10616832, 10747904, 10878976, 11010048, | ||
235 | 11141120, 11272192, 11403264, 11534336, 11665408, 11796480, 11927552, | ||
236 | 12058624, 12189696, 12320768, 12451840, 12582912, 12713984, 12845056, | ||
237 | 12976128, 13107200, 13238272, 13369344, 13500416, 13631488, 13762560, | ||
238 | 13893632, 14024704, 14155776, 14286848, 14417920, 14548992, 14680064, | ||
239 | 14811136, 14942208, 15073280, 15204352, 15335424, 15466496, 15597568, | ||
240 | 15728640, 15859712, 15990784, 16121856, 16252928, 16384000, 16515072, | ||
241 | 16646144, 16777216, 16908288, 17039360, 17170432, 17301504, 17432576, | ||
242 | 17563648, 17694720, 17825792, 17956864, 18087936, 18219008, 18350080, | ||
243 | 18481152, 18612224, 18743296, 18874368, 19005440, 19136512, 19267584, | ||
244 | 19398656, 19529728, 19660800, 19791872, 19922944, 20054016, 20185088, | ||
245 | 20316160, 20447232, 20578304, 20709376, 20840448, 20971520, 21102592, | ||
246 | 21233664, 21364736, 21495808, 21626880, 21757952, 21889024, 22020096, | ||
247 | 22151168, 22282240, 22413312, 22544384, 22675456, 22806528, 22937600, | ||
248 | 23068672, 23199744, 23330816, 23461888, 23592960, 23724032, 23855104, | ||
249 | 23986176, 24117248, 24248320, 24379392, 24510464, 24641536, 24772608, | ||
250 | 24903680, 25034752, 25165824, 25296896, 25427968, 25559040, 25690112, | ||
251 | 25821184, 25952256, 26083328, 26214400, 26345472, 26476544, 26607616, | ||
252 | 26738688, 26869760, 27000832, 27131904, 27262976, 27394048, 27525120, | ||
253 | 27656192, 27787264, 27918336, 28049408, 28180480, 28311552, 28442624, | ||
254 | 28573696, 28704768, 28835840, 28966912, 29097984, 29229056, 29360128, | ||
255 | 29491200, 29622272, 29753344, 29884416, 30015488, 30146560, 30277632, | ||
256 | 30408704, 30539776, 30670848, 30801920, 30932992, 31064064, 31195136, | ||
257 | 31326208, 31457280, 31588352, 31719424, 31850496, 31981568, 32112640, | ||
258 | 32243712, 32374784, 32505856, 32636928, 32768000, 32899072, 33030144, | ||
259 | 33161216, 33292288, 33423360 | ||
213 | }; | 260 | }; |
214 | 261 | ||
215 | static void lzxd_reset_state(struct lzxd_stream *lzx) { | 262 | static void lzxd_reset_state(struct lzxd_stream *lzx) { |
@@ -230,23 +277,37 @@ static void lzxd_reset_state(struct lzxd_stream *lzx) { | |||
230 | /*-------- main LZX code --------*/ | 277 | /*-------- main LZX code --------*/ |
231 | 278 | ||
232 | struct lzxd_stream *lzxd_init(struct mspack_system *system, | 279 | struct lzxd_stream *lzxd_init(struct mspack_system *system, |
233 | struct mspack_file *input, | 280 | struct mspack_file *input, |
234 | struct mspack_file *output, | 281 | struct mspack_file *output, |
235 | int window_bits, | 282 | int window_bits, |
236 | int reset_interval, | 283 | int reset_interval, |
237 | int input_buffer_size, | 284 | int input_buffer_size, |
238 | off_t output_length) | 285 | off_t output_length, |
286 | char is_delta) | ||
239 | { | 287 | { |
240 | unsigned int window_size = 1 << window_bits; | 288 | unsigned int window_size = 1 << window_bits; |
241 | struct lzxd_stream *lzx; | 289 | struct lzxd_stream *lzx; |
242 | 290 | ||
243 | if (!system) return NULL; | 291 | if (!system) return NULL; |
244 | 292 | ||
245 | /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */ | 293 | /* LZX DELTA window sizes are between 2^17 (128KiB) and 2^25 (32MiB), |
246 | if (window_bits < 15 || window_bits > 21) return NULL; | 294 | * regular LZX windows are between 2^15 (32KiB) and 2^21 (2MiB) |
295 | */ | ||
296 | if (is_delta) { | ||
297 | if (window_bits < 17 || window_bits > 25) return NULL; | ||
298 | } | ||
299 | else { | ||
300 | if (window_bits < 15 || window_bits > 21) return NULL; | ||
301 | } | ||
247 | 302 | ||
303 | if (reset_interval < 0 || output_length < 0) { | ||
304 | D(("reset interval or output length < 0")) | ||
305 | return NULL; | ||
306 | } | ||
307 | |||
308 | /* round up input buffer size to multiple of two */ | ||
248 | input_buffer_size = (input_buffer_size + 1) & -2; | 309 | input_buffer_size = (input_buffer_size + 1) & -2; |
249 | if (!input_buffer_size) return NULL; | 310 | if (input_buffer_size < 2) return NULL; |
250 | 311 | ||
251 | /* allocate decompression state */ | 312 | /* allocate decompression state */ |
252 | if (!(lzx = (struct lzxd_stream *) system->alloc(system, sizeof(struct lzxd_stream)))) { | 313 | if (!(lzx = (struct lzxd_stream *) system->alloc(system, sizeof(struct lzxd_stream)))) { |
@@ -272,6 +333,7 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system, | |||
272 | 333 | ||
273 | lzx->inbuf_size = input_buffer_size; | 334 | lzx->inbuf_size = input_buffer_size; |
274 | lzx->window_size = 1 << window_bits; | 335 | lzx->window_size = 1 << window_bits; |
336 | lzx->ref_data_size = 0; | ||
275 | lzx->window_posn = 0; | 337 | lzx->window_posn = 0; |
276 | lzx->frame_posn = 0; | 338 | lzx->frame_posn = 0; |
277 | lzx->frame = 0; | 339 | lzx->frame = 0; |
@@ -280,11 +342,8 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system, | |||
280 | lzx->intel_curpos = 0; | 342 | lzx->intel_curpos = 0; |
281 | lzx->intel_started = 0; | 343 | lzx->intel_started = 0; |
282 | lzx->error = MSPACK_ERR_OK; | 344 | lzx->error = MSPACK_ERR_OK; |
283 | 345 | lzx->num_offsets = position_slots[window_bits - 15] << 3; | |
284 | /* window bits: 15 16 17 18 19 20 21 | 346 | lzx->is_delta = is_delta; |
285 | * position slots: 30 32 34 36 38 42 50 */ | ||
286 | lzx->posn_slots = ((window_bits == 21) ? 50 : | ||
287 | ((window_bits == 20) ? 42 : (window_bits << 1))); | ||
288 | 347 | ||
289 | lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0]; | 348 | lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0]; |
290 | lzxd_reset_state(lzx); | 349 | lzxd_reset_state(lzx); |
@@ -292,8 +351,44 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system, | |||
292 | return lzx; | 351 | return lzx; |
293 | } | 352 | } |
294 | 353 | ||
354 | int lzxd_set_reference_data(struct lzxd_stream *lzx, | ||
355 | struct mspack_system *system, | ||
356 | struct mspack_file *input, | ||
357 | unsigned int length) | ||
358 | { | ||
359 | if (!lzx) return MSPACK_ERR_ARGS; | ||
360 | |||
361 | if (!lzx->is_delta) { | ||
362 | D(("only LZX DELTA streams support reference data")) | ||
363 | return MSPACK_ERR_ARGS; | ||
364 | } | ||
365 | if (lzx->offset) { | ||
366 | D(("too late to set reference data after decoding starts")) | ||
367 | return MSPACK_ERR_ARGS; | ||
368 | } | ||
369 | if (length > lzx->window_size) { | ||
370 | D(("reference length (%u) is longer than the window", length)) | ||
371 | return MSPACK_ERR_ARGS; | ||
372 | } | ||
373 | if (length > 0 && (!system || !input)) { | ||
374 | D(("length > 0 but no system or input")) | ||
375 | return MSPACK_ERR_ARGS; | ||
376 | } | ||
377 | |||
378 | lzx->ref_data_size = length; | ||
379 | if (length > 0) { | ||
380 | /* copy reference data */ | ||
381 | unsigned char *pos = &lzx->window[lzx->window_size - length]; | ||
382 | int bytes = system->read(input, pos, length); | ||
383 | /* length can't be more than 2^25, so no signedness problem */ | ||
384 | if (bytes < (int)length) return MSPACK_ERR_READ; | ||
385 | } | ||
386 | lzx->ref_data_size = length; | ||
387 | return MSPACK_ERR_OK; | ||
388 | } | ||
389 | |||
295 | void lzxd_set_output_length(struct lzxd_stream *lzx, off_t out_bytes) { | 390 | void lzxd_set_output_length(struct lzxd_stream *lzx, off_t out_bytes) { |
296 | if (lzx) lzx->length = out_bytes; | 391 | if (lzx && out_bytes > 0) lzx->length = out_bytes; |
297 | } | 392 | } |
298 | 393 | ||
299 | int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { | 394 | int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { |
@@ -304,7 +399,7 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { | |||
304 | register unsigned short sym; | 399 | register unsigned short sym; |
305 | 400 | ||
306 | int match_length, length_footer, extra, verbatim_bits, bytes_todo; | 401 | int match_length, length_footer, extra, verbatim_bits, bytes_todo; |
307 | int this_run, main_element, aligned_bits, j; | 402 | int this_run, main_element, aligned_bits, j, warned = 0; |
308 | unsigned char *window, *runsrc, *rundest, buf[12]; | 403 | unsigned char *window, *runsrc, *rundest, buf[12]; |
309 | unsigned int frame_size=0, end_frame, match_offset, window_posn; | 404 | unsigned int frame_size=0, end_frame, match_offset, window_posn; |
310 | unsigned int R0, R1, R2; | 405 | unsigned int R0, R1, R2; |
@@ -340,8 +435,12 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { | |||
340 | /* have we reached the reset interval? (if there is one?) */ | 435 | /* have we reached the reset interval? (if there is one?) */ |
341 | if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) { | 436 | if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) { |
342 | if (lzx->block_remaining) { | 437 | if (lzx->block_remaining) { |
343 | D(("%d bytes remaining at reset interval", lzx->block_remaining)) | 438 | /* this is a file format error, we can make a best effort to extract what we can */ |
344 | return lzx->error = MSPACK_ERR_DECRUNCH; | 439 | D(("%d bytes remaining at reset interval", lzx->block_remaining)) |
440 | if (!warned) { | ||
441 | lzx->sys->message(NULL, "WARNING; invalid reset interval detected during LZX decompression"); | ||
442 | warned++; | ||
443 | } | ||
345 | } | 444 | } |
346 | 445 | ||
347 | /* re-read the intel header and reset the huffman lengths */ | 446 | /* re-read the intel header and reset the huffman lengths */ |
@@ -351,6 +450,12 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { | |||
351 | R2 = lzx->R2; | 450 | R2 = lzx->R2; |
352 | } | 451 | } |
353 | 452 | ||
453 | /* LZX DELTA format has chunk_size, not present in LZX format */ | ||
454 | if (lzx->is_delta) { | ||
455 | ENSURE_BITS(16); | ||
456 | REMOVE_BITS(16); | ||
457 | } | ||
458 | |||
354 | /* read header if necessary */ | 459 | /* read header if necessary */ |
355 | if (!lzx->header_read) { | 460 | if (!lzx->header_read) { |
356 | /* read 1 bit. if bit=0, intel filesize = 0. | 461 | /* read 1 bit. if bit=0, intel filesize = 0. |
@@ -373,62 +478,61 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { | |||
373 | while (bytes_todo > 0) { | 478 | while (bytes_todo > 0) { |
374 | /* initialise new block, if one is needed */ | 479 | /* initialise new block, if one is needed */ |
375 | if (lzx->block_remaining == 0) { | 480 | if (lzx->block_remaining == 0) { |
376 | /* realign if previous block was an odd-sized UNCOMPRESSED block */ | 481 | /* realign if previous block was an odd-sized UNCOMPRESSED block */ |
377 | if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) && | 482 | if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) && |
378 | (lzx->block_length & 1)) | 483 | (lzx->block_length & 1)) |
379 | { | 484 | { |
380 | READ_IF_NEEDED; | 485 | READ_IF_NEEDED; |
381 | i_ptr++; | 486 | i_ptr++; |
382 | } | 487 | } |
383 | 488 | ||
384 | /* read block type (3 bits) and block length (24 bits) */ | 489 | /* read block type (3 bits) and block length (24 bits) */ |
385 | READ_BITS(lzx->block_type, 3); | 490 | READ_BITS(lzx->block_type, 3); |
386 | READ_BITS(i, 16); READ_BITS(j, 8); | 491 | READ_BITS(i, 16); READ_BITS(j, 8); |
387 | lzx->block_remaining = lzx->block_length = (i << 8) | j; | 492 | lzx->block_remaining = lzx->block_length = (i << 8) | j; |
388 | /*D(("new block t%d len %u", lzx->block_type, lzx->block_length))*/ | 493 | /*D(("new block t%d len %u", lzx->block_type, lzx->block_length))*/ |
389 | 494 | ||
390 | /* read individual block headers */ | 495 | /* read individual block headers */ |
391 | switch (lzx->block_type) { | 496 | switch (lzx->block_type) { |
392 | case LZX_BLOCKTYPE_ALIGNED: | 497 | case LZX_BLOCKTYPE_ALIGNED: |
393 | /* read lengths of and build aligned huffman decoding tree */ | 498 | /* read lengths of and build aligned huffman decoding tree */ |
394 | for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; } | 499 | for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; } |
395 | BUILD_TABLE(ALIGNED); | 500 | BUILD_TABLE(ALIGNED); |
396 | /* no break -- rest of aligned header is same as verbatim */ | 501 | /* rest of aligned header is same as verbatim */ /*@fallthrough@*/ |
397 | case LZX_BLOCKTYPE_VERBATIM: | 502 | case LZX_BLOCKTYPE_VERBATIM: |
398 | /* read lengths of and build main huffman decoding tree */ | 503 | /* read lengths of and build main huffman decoding tree */ |
399 | READ_LENGTHS(MAINTREE, 0, 256); | 504 | READ_LENGTHS(MAINTREE, 0, 256); |
400 | READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + (lzx->posn_slots << 3)); | 505 | READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx->num_offsets); |
401 | BUILD_TABLE(MAINTREE); | 506 | BUILD_TABLE(MAINTREE); |
402 | /* if the literal 0xE8 is anywhere in the block... */ | 507 | /* if the literal 0xE8 is anywhere in the block... */ |
403 | if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1; | 508 | if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1; |
404 | /* read lengths of and build lengths huffman decoding tree */ | 509 | /* read lengths of and build lengths huffman decoding tree */ |
405 | READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS); | 510 | READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS); |
406 | BUILD_TABLE_MAYBE_EMPTY(LENGTH); | 511 | BUILD_TABLE_MAYBE_EMPTY(LENGTH); |
407 | break; | 512 | break; |
408 | 513 | ||
409 | case LZX_BLOCKTYPE_UNCOMPRESSED: | 514 | case LZX_BLOCKTYPE_UNCOMPRESSED: |
410 | /* because we can't assume otherwise */ | 515 | /* because we can't assume otherwise */ |
411 | lzx->intel_started = 1; | 516 | lzx->intel_started = 1; |
412 | 517 | ||
413 | /* read 1-16 (not 0-15) bits to align to bytes */ | 518 | /* read 1-16 (not 0-15) bits to align to bytes */ |
414 | ENSURE_BITS(16); | 519 | if (bits_left == 0) ENSURE_BITS(16); |
415 | if (bits_left > 16) i_ptr -= 2; | 520 | bits_left = 0; bit_buffer = 0; |
416 | bits_left = 0; bit_buffer = 0; | 521 | |
417 | 522 | /* read 12 bytes of stored R0 / R1 / R2 values */ | |
418 | /* read 12 bytes of stored R0 / R1 / R2 values */ | 523 | for (rundest = &buf[0], i = 0; i < 12; i++) { |
419 | for (rundest = &buf[0], i = 0; i < 12; i++) { | 524 | READ_IF_NEEDED; |
420 | READ_IF_NEEDED; | 525 | *rundest++ = *i_ptr++; |
421 | *rundest++ = *i_ptr++; | 526 | } |
422 | } | 527 | R0 = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); |
423 | R0 = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); | 528 | R1 = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24); |
424 | R1 = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24); | 529 | R2 = buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24); |
425 | R2 = buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24); | 530 | break; |
426 | break; | 531 | |
427 | 532 | default: | |
428 | default: | 533 | D(("bad block type")) |
429 | D(("bad block type")) | 534 | return lzx->error = MSPACK_ERR_DECRUNCH; |
430 | return lzx->error = MSPACK_ERR_DECRUNCH; | 535 | } |
431 | } | ||
432 | } | 536 | } |
433 | 537 | ||
434 | /* decode more of the block: | 538 | /* decode more of the block: |
@@ -443,208 +547,270 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { | |||
443 | /* decode at least this_run bytes */ | 547 | /* decode at least this_run bytes */ |
444 | switch (lzx->block_type) { | 548 | switch (lzx->block_type) { |
445 | case LZX_BLOCKTYPE_VERBATIM: | 549 | case LZX_BLOCKTYPE_VERBATIM: |
446 | while (this_run > 0) { | 550 | while (this_run > 0) { |
447 | READ_HUFFSYM(MAINTREE, main_element); | 551 | READ_HUFFSYM(MAINTREE, main_element); |
448 | if (main_element < LZX_NUM_CHARS) { | 552 | if (main_element < LZX_NUM_CHARS) { |
449 | /* literal: 0 to LZX_NUM_CHARS-1 */ | 553 | /* literal: 0 to LZX_NUM_CHARS-1 */ |
450 | window[window_posn++] = main_element; | 554 | window[window_posn++] = main_element; |
451 | this_run--; | 555 | this_run--; |
452 | } | 556 | } |
453 | else { | 557 | else { |
454 | /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ | 558 | /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ |
455 | main_element -= LZX_NUM_CHARS; | 559 | main_element -= LZX_NUM_CHARS; |
456 | 560 | ||
457 | /* get match length */ | 561 | /* get match length */ |
458 | match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; | 562 | match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; |
459 | if (match_length == LZX_NUM_PRIMARY_LENGTHS) { | 563 | if (match_length == LZX_NUM_PRIMARY_LENGTHS) { |
460 | if (lzx->LENGTH_empty) { | 564 | if (lzx->LENGTH_empty) { |
461 | D(("LENGTH symbol needed but tree is empty")) | 565 | D(("LENGTH symbol needed but tree is empty")) |
462 | return lzx->error = MSPACK_ERR_DECRUNCH; | 566 | return lzx->error = MSPACK_ERR_DECRUNCH; |
463 | } | 567 | } |
464 | READ_HUFFSYM(LENGTH, length_footer); | 568 | READ_HUFFSYM(LENGTH, length_footer); |
465 | match_length += length_footer; | 569 | match_length += length_footer; |
466 | } | 570 | } |
467 | match_length += LZX_MIN_MATCH; | 571 | match_length += LZX_MIN_MATCH; |
468 | 572 | ||
469 | /* get match offset */ | 573 | /* get match offset */ |
470 | switch ((match_offset = (main_element >> 3))) { | 574 | switch ((match_offset = (main_element >> 3))) { |
471 | case 0: match_offset = R0; break; | 575 | case 0: match_offset = R0; break; |
472 | case 1: match_offset = R1; R1=R0; R0 = match_offset; break; | 576 | case 1: match_offset = R1; R1=R0; R0 = match_offset; break; |
473 | case 2: match_offset = R2; R2=R0; R0 = match_offset; break; | 577 | case 2: match_offset = R2; R2=R0; R0 = match_offset; break; |
474 | case 3: match_offset = 1; R2=R1; R1=R0; R0 = match_offset; break; | 578 | case 3: match_offset = 1; R2=R1; R1=R0; R0 = match_offset; break; |
475 | default: | 579 | default: |
476 | extra = extra_bits[match_offset]; | 580 | extra = (match_offset >= 36) ? 17 : extra_bits[match_offset]; |
477 | READ_BITS(verbatim_bits, extra); | 581 | READ_BITS(verbatim_bits, extra); |
478 | match_offset = position_base[match_offset] - 2 + verbatim_bits; | 582 | match_offset = position_base[match_offset] - 2 + verbatim_bits; |
479 | R2 = R1; R1 = R0; R0 = match_offset; | 583 | R2 = R1; R1 = R0; R0 = match_offset; |
480 | } | 584 | } |
481 | 585 | ||
482 | if ((window_posn + match_length) > lzx->window_size) { | 586 | /* LZX DELTA uses max match length to signal even longer match */ |
483 | D(("match ran over window wrap")) | 587 | if (match_length == LZX_MAX_MATCH && lzx->is_delta) { |
484 | return lzx->error = MSPACK_ERR_DECRUNCH; | 588 | int extra_len = 0; |
485 | } | 589 | ENSURE_BITS(3); /* 4 entry huffman tree */ |
486 | 590 | if (PEEK_BITS(1) == 0) { | |
487 | /* copy match */ | 591 | REMOVE_BITS(1); /* '0' -> 8 extra length bits */ |
488 | rundest = &window[window_posn]; | 592 | READ_BITS(extra_len, 8); |
489 | i = match_length; | 593 | } |
490 | /* does match offset wrap the window? */ | 594 | else if (PEEK_BITS(2) == 2) { |
491 | if (match_offset > window_posn) { | 595 | REMOVE_BITS(2); /* '10' -> 10 extra length bits + 0x100 */ |
492 | /* j = length from match offset to end of window */ | 596 | READ_BITS(extra_len, 10); |
493 | j = match_offset - window_posn; | 597 | extra_len += 0x100; |
494 | if (j > (int) lzx->window_size) { | 598 | } |
495 | D(("match offset beyond window boundaries")) | 599 | else if (PEEK_BITS(3) == 6) { |
496 | return lzx->error = MSPACK_ERR_DECRUNCH; | 600 | REMOVE_BITS(3); /* '110' -> 12 extra length bits + 0x500 */ |
497 | } | 601 | READ_BITS(extra_len, 12); |
498 | runsrc = &window[lzx->window_size - j]; | 602 | extra_len += 0x500; |
499 | if (j < i) { | 603 | } |
500 | /* if match goes over the window edge, do two copy runs */ | 604 | else { |
501 | i -= j; while (j-- > 0) *rundest++ = *runsrc++; | 605 | REMOVE_BITS(3); /* '111' -> 15 extra length bits */ |
502 | runsrc = window; | 606 | READ_BITS(extra_len, 15); |
503 | } | 607 | } |
504 | while (i-- > 0) *rundest++ = *runsrc++; | 608 | match_length += extra_len; |
505 | } | 609 | } |
506 | else { | 610 | |
507 | runsrc = rundest - match_offset; | 611 | if ((window_posn + match_length) > lzx->window_size) { |
508 | while (i-- > 0) *rundest++ = *runsrc++; | 612 | D(("match ran over window wrap")) |
509 | } | 613 | return lzx->error = MSPACK_ERR_DECRUNCH; |
510 | 614 | } | |
511 | this_run -= match_length; | 615 | |
512 | window_posn += match_length; | 616 | /* copy match */ |
513 | } | 617 | rundest = &window[window_posn]; |
514 | } /* while (this_run > 0) */ | 618 | i = match_length; |
515 | break; | 619 | /* does match offset wrap the window? */ |
620 | if (match_offset > window_posn) { | ||
621 | if (match_offset > lzx->offset && | ||
622 | (match_offset - window_posn) > lzx->ref_data_size) | ||
623 | { | ||
624 | D(("match offset beyond LZX stream")) | ||
625 | return lzx->error = MSPACK_ERR_DECRUNCH; | ||
626 | } | ||
627 | /* j = length from match offset to end of window */ | ||
628 | j = match_offset - window_posn; | ||
629 | if (j > (int) lzx->window_size) { | ||
630 | D(("match offset beyond window boundaries")) | ||
631 | return lzx->error = MSPACK_ERR_DECRUNCH; | ||
632 | } | ||
633 | runsrc = &window[lzx->window_size - j]; | ||
634 | if (j < i) { | ||
635 | /* if match goes over the window edge, do two copy runs */ | ||
636 | i -= j; while (j-- > 0) *rundest++ = *runsrc++; | ||
637 | runsrc = window; | ||
638 | } | ||
639 | while (i-- > 0) *rundest++ = *runsrc++; | ||
640 | } | ||
641 | else { | ||
642 | runsrc = rundest - match_offset; | ||
643 | while (i-- > 0) *rundest++ = *runsrc++; | ||
644 | } | ||
645 | |||
646 | this_run -= match_length; | ||
647 | window_posn += match_length; | ||
648 | } | ||
649 | } /* while (this_run > 0) */ | ||
650 | break; | ||
516 | 651 | ||
517 | case LZX_BLOCKTYPE_ALIGNED: | 652 | case LZX_BLOCKTYPE_ALIGNED: |
518 | while (this_run > 0) { | 653 | while (this_run > 0) { |
519 | READ_HUFFSYM(MAINTREE, main_element); | 654 | READ_HUFFSYM(MAINTREE, main_element); |
520 | if (main_element < LZX_NUM_CHARS) { | 655 | if (main_element < LZX_NUM_CHARS) { |
521 | /* literal: 0 to LZX_NUM_CHARS-1 */ | 656 | /* literal: 0 to LZX_NUM_CHARS-1 */ |
522 | window[window_posn++] = main_element; | 657 | window[window_posn++] = main_element; |
523 | this_run--; | 658 | this_run--; |
524 | } | 659 | } |
525 | else { | 660 | else { |
526 | /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ | 661 | /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ |
527 | main_element -= LZX_NUM_CHARS; | 662 | main_element -= LZX_NUM_CHARS; |
528 | 663 | ||
529 | /* get match length */ | 664 | /* get match length */ |
530 | match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; | 665 | match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; |
531 | if (match_length == LZX_NUM_PRIMARY_LENGTHS) { | 666 | if (match_length == LZX_NUM_PRIMARY_LENGTHS) { |
532 | if (lzx->LENGTH_empty) { | 667 | if (lzx->LENGTH_empty) { |
533 | D(("LENGTH symbol needed but tree is empty")) | 668 | D(("LENGTH symbol needed but tree is empty")) |
534 | return lzx->error = MSPACK_ERR_DECRUNCH; | 669 | return lzx->error = MSPACK_ERR_DECRUNCH; |
535 | } | 670 | } |
536 | READ_HUFFSYM(LENGTH, length_footer); | 671 | READ_HUFFSYM(LENGTH, length_footer); |
537 | match_length += length_footer; | 672 | match_length += length_footer; |
538 | } | 673 | } |
539 | match_length += LZX_MIN_MATCH; | 674 | match_length += LZX_MIN_MATCH; |
540 | 675 | ||
541 | /* get match offset */ | 676 | /* get match offset */ |
542 | switch ((match_offset = (main_element >> 3))) { | 677 | switch ((match_offset = (main_element >> 3))) { |
543 | case 0: match_offset = R0; break; | 678 | case 0: match_offset = R0; break; |
544 | case 1: match_offset = R1; R1 = R0; R0 = match_offset; break; | 679 | case 1: match_offset = R1; R1 = R0; R0 = match_offset; break; |
545 | case 2: match_offset = R2; R2 = R0; R0 = match_offset; break; | 680 | case 2: match_offset = R2; R2 = R0; R0 = match_offset; break; |
546 | default: | 681 | default: |
547 | extra = extra_bits[match_offset]; | 682 | extra = (match_offset >= 36) ? 17 : extra_bits[match_offset]; |
548 | match_offset = position_base[match_offset] - 2; | 683 | match_offset = position_base[match_offset] - 2; |
549 | if (extra > 3) { | 684 | if (extra > 3) { |
550 | /* verbatim and aligned bits */ | 685 | /* verbatim and aligned bits */ |
551 | extra -= 3; | 686 | extra -= 3; |
552 | READ_BITS(verbatim_bits, extra); | 687 | READ_BITS(verbatim_bits, extra); |
553 | match_offset += (verbatim_bits << 3); | 688 | match_offset += (verbatim_bits << 3); |
554 | READ_HUFFSYM(ALIGNED, aligned_bits); | 689 | READ_HUFFSYM(ALIGNED, aligned_bits); |
555 | match_offset += aligned_bits; | 690 | match_offset += aligned_bits; |
556 | } | 691 | } |
557 | else if (extra == 3) { | 692 | else if (extra == 3) { |
558 | /* aligned bits only */ | 693 | /* aligned bits only */ |
559 | READ_HUFFSYM(ALIGNED, aligned_bits); | 694 | READ_HUFFSYM(ALIGNED, aligned_bits); |
560 | match_offset += aligned_bits; | 695 | match_offset += aligned_bits; |
561 | } | 696 | } |
562 | else if (extra > 0) { /* extra==1, extra==2 */ | 697 | else if (extra > 0) { /* extra==1, extra==2 */ |
563 | /* verbatim bits only */ | 698 | /* verbatim bits only */ |
564 | READ_BITS(verbatim_bits, extra); | 699 | READ_BITS(verbatim_bits, extra); |
565 | match_offset += verbatim_bits; | 700 | match_offset += verbatim_bits; |
566 | } | 701 | } |
567 | else /* extra == 0 */ { | 702 | else /* extra == 0 */ { |
568 | /* ??? not defined in LZX specification! */ | 703 | /* ??? not defined in LZX specification! */ |
569 | match_offset = 1; | 704 | match_offset = 1; |
570 | } | 705 | } |
571 | /* update repeated offset LRU queue */ | 706 | /* update repeated offset LRU queue */ |
572 | R2 = R1; R1 = R0; R0 = match_offset; | 707 | R2 = R1; R1 = R0; R0 = match_offset; |
573 | } | 708 | } |
574 | 709 | ||
575 | if ((window_posn + match_length) > lzx->window_size) { | 710 | /* LZX DELTA uses max match length to signal even longer match */ |
576 | D(("match ran over window wrap")) | 711 | if (match_length == LZX_MAX_MATCH && lzx->is_delta) { |
577 | return lzx->error = MSPACK_ERR_DECRUNCH; | 712 | int extra_len = 0; |
578 | } | 713 | ENSURE_BITS(3); /* 4 entry huffman tree */ |
579 | 714 | if (PEEK_BITS(1) == 0) { | |
580 | /* copy match */ | 715 | REMOVE_BITS(1); /* '0' -> 8 extra length bits */ |
581 | rundest = &window[window_posn]; | 716 | READ_BITS(extra_len, 8); |
582 | i = match_length; | 717 | } |
583 | /* does match offset wrap the window? */ | 718 | else if (PEEK_BITS(2) == 2) { |
584 | if (match_offset > window_posn) { | 719 | REMOVE_BITS(2); /* '10' -> 10 extra length bits + 0x100 */ |
585 | /* j = length from match offset to end of window */ | 720 | READ_BITS(extra_len, 10); |
586 | j = match_offset - window_posn; | 721 | extra_len += 0x100; |
587 | if (j > (int) lzx->window_size) { | 722 | } |
588 | D(("match offset beyond window boundaries")) | 723 | else if (PEEK_BITS(3) == 6) { |
589 | return lzx->error = MSPACK_ERR_DECRUNCH; | 724 | REMOVE_BITS(3); /* '110' -> 12 extra length bits + 0x500 */ |
590 | } | 725 | READ_BITS(extra_len, 12); |
591 | runsrc = &window[lzx->window_size - j]; | 726 | extra_len += 0x500; |
592 | if (j < i) { | 727 | } |
593 | /* if match goes over the window edge, do two copy runs */ | 728 | else { |
594 | i -= j; while (j-- > 0) *rundest++ = *runsrc++; | 729 | REMOVE_BITS(3); /* '111' -> 15 extra length bits */ |
595 | runsrc = window; | 730 | READ_BITS(extra_len, 15); |
596 | } | 731 | } |
597 | while (i-- > 0) *rundest++ = *runsrc++; | 732 | match_length += extra_len; |
598 | } | 733 | } |
599 | else { | 734 | |
600 | runsrc = rundest - match_offset; | 735 | if ((window_posn + match_length) > lzx->window_size) { |
601 | while (i-- > 0) *rundest++ = *runsrc++; | 736 | D(("match ran over window wrap")) |
602 | } | 737 | return lzx->error = MSPACK_ERR_DECRUNCH; |
603 | 738 | } | |
604 | this_run -= match_length; | 739 | |
605 | window_posn += match_length; | 740 | /* copy match */ |
606 | } | 741 | rundest = &window[window_posn]; |
607 | } /* while (this_run > 0) */ | 742 | i = match_length; |
608 | break; | 743 | /* does match offset wrap the window? */ |
744 | if (match_offset > window_posn) { | ||
745 | if (match_offset > lzx->offset && | ||
746 | (match_offset - window_posn) > lzx->ref_data_size) | ||
747 | { | ||
748 | D(("match offset beyond LZX stream")) | ||
749 | return lzx->error = MSPACK_ERR_DECRUNCH; | ||
750 | } | ||
751 | /* j = length from match offset to end of window */ | ||
752 | j = match_offset - window_posn; | ||
753 | if (j > (int) lzx->window_size) { | ||
754 | D(("match offset beyond window boundaries")) | ||
755 | return lzx->error = MSPACK_ERR_DECRUNCH; | ||
756 | } | ||
757 | runsrc = &window[lzx->window_size - j]; | ||
758 | if (j < i) { | ||
759 | /* if match goes over the window edge, do two copy runs */ | ||
760 | i -= j; while (j-- > 0) *rundest++ = *runsrc++; | ||
761 | runsrc = window; | ||
762 | } | ||
763 | while (i-- > 0) *rundest++ = *runsrc++; | ||
764 | } | ||
765 | else { | ||
766 | runsrc = rundest - match_offset; | ||
767 | while (i-- > 0) *rundest++ = *runsrc++; | ||
768 | } | ||
769 | |||
770 | this_run -= match_length; | ||
771 | window_posn += match_length; | ||
772 | } | ||
773 | } /* while (this_run > 0) */ | ||
774 | break; | ||
609 | 775 | ||
610 | case LZX_BLOCKTYPE_UNCOMPRESSED: | 776 | case LZX_BLOCKTYPE_UNCOMPRESSED: |
611 | /* as this_run is limited not to wrap a frame, this also means it | 777 | /* as this_run is limited not to wrap a frame, this also means it |
612 | * won't wrap the window (as the window is a multiple of 32k) */ | 778 | * won't wrap the window (as the window is a multiple of 32k) */ |
613 | rundest = &window[window_posn]; | 779 | rundest = &window[window_posn]; |
614 | window_posn += this_run; | 780 | window_posn += this_run; |
615 | while (this_run > 0) { | 781 | while (this_run > 0) { |
616 | if ((i = i_end - i_ptr) == 0) { | 782 | if ((i = i_end - i_ptr) == 0) { |
617 | READ_IF_NEEDED; | 783 | READ_IF_NEEDED; |
618 | } | 784 | } |
619 | else { | 785 | else { |
620 | if (i > this_run) i = this_run; | 786 | if (i > this_run) i = this_run; |
621 | lzx->sys->copy(i_ptr, rundest, (size_t) i); | 787 | lzx->sys->copy(i_ptr, rundest, (size_t) i); |
622 | rundest += i; | 788 | rundest += i; |
623 | i_ptr += i; | 789 | i_ptr += i; |
624 | this_run -= i; | 790 | this_run -= i; |
625 | } | 791 | } |
626 | } | 792 | } |
627 | break; | 793 | break; |
628 | 794 | ||
629 | default: | 795 | default: |
630 | return lzx->error = MSPACK_ERR_DECRUNCH; /* might as well */ | 796 | return lzx->error = MSPACK_ERR_DECRUNCH; /* might as well */ |
631 | } | 797 | } |
632 | 798 | ||
633 | /* did the final match overrun our desired this_run length? */ | 799 | /* did the final match overrun our desired this_run length? */ |
634 | if (this_run < 0) { | 800 | if (this_run < 0) { |
635 | if ((unsigned int)(-this_run) > lzx->block_remaining) { | 801 | if ((unsigned int)(-this_run) > lzx->block_remaining) { |
636 | D(("overrun went past end of block by %d (%d remaining)", | 802 | D(("overrun went past end of block by %d (%d remaining)", |
637 | -this_run, lzx->block_remaining )) | 803 | -this_run, lzx->block_remaining )) |
638 | return lzx->error = MSPACK_ERR_DECRUNCH; | 804 | return lzx->error = MSPACK_ERR_DECRUNCH; |
639 | } | 805 | } |
640 | lzx->block_remaining -= -this_run; | 806 | lzx->block_remaining -= -this_run; |
641 | } | 807 | } |
642 | } /* while (bytes_todo > 0) */ | 808 | } /* while (bytes_todo > 0) */ |
643 | 809 | ||
644 | /* streams don't extend over frame boundaries */ | 810 | /* streams don't extend over frame boundaries */ |
645 | if ((window_posn - lzx->frame_posn) != frame_size) { | 811 | if ((window_posn - lzx->frame_posn) != frame_size) { |
646 | D(("decode beyond output frame limits! %d != %d", | 812 | D(("decode beyond output frame limits! %d != %d", |
647 | window_posn - lzx->frame_posn, frame_size)) | 813 | window_posn - lzx->frame_posn, frame_size)) |
648 | return lzx->error = MSPACK_ERR_DECRUNCH; | 814 | return lzx->error = MSPACK_ERR_DECRUNCH; |
649 | } | 815 | } |
650 | 816 | ||
@@ -654,13 +820,14 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { | |||
654 | 820 | ||
655 | /* check that we've used all of the previous frame first */ | 821 | /* check that we've used all of the previous frame first */ |
656 | if (lzx->o_ptr != lzx->o_end) { | 822 | if (lzx->o_ptr != lzx->o_end) { |
657 | D(("%ld avail bytes, new %d frame", lzx->o_end-lzx->o_ptr, frame_size)) | 823 | D(("%ld avail bytes, new %d frame", |
824 | (long)(lzx->o_end - lzx->o_ptr), frame_size)) | ||
658 | return lzx->error = MSPACK_ERR_DECRUNCH; | 825 | return lzx->error = MSPACK_ERR_DECRUNCH; |
659 | } | 826 | } |
660 | 827 | ||
661 | /* does this intel block _really_ need decoding? */ | 828 | /* does this intel block _really_ need decoding? */ |
662 | if (lzx->intel_started && lzx->intel_filesize && | 829 | if (lzx->intel_started && lzx->intel_filesize && |
663 | (lzx->frame <= 32768) && (frame_size > 10)) | 830 | (lzx->frame <= 32768) && (frame_size > 10)) |
664 | { | 831 | { |
665 | unsigned char *data = &lzx->e8_buf[0]; | 832 | unsigned char *data = &lzx->e8_buf[0]; |
666 | unsigned char *dataend = &lzx->e8_buf[frame_size - 10]; | 833 | unsigned char *dataend = &lzx->e8_buf[frame_size - 10]; |
@@ -673,17 +840,17 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { | |||
673 | lzx->sys->copy(&lzx->window[lzx->frame_posn], data, frame_size); | 840 | lzx->sys->copy(&lzx->window[lzx->frame_posn], data, frame_size); |
674 | 841 | ||
675 | while (data < dataend) { | 842 | while (data < dataend) { |
676 | if (*data++ != 0xE8) { curpos++; continue; } | 843 | if (*data++ != 0xE8) { curpos++; continue; } |
677 | abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24); | 844 | abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24); |
678 | if ((abs_off >= -curpos) && (abs_off < filesize)) { | 845 | if ((abs_off >= -curpos) && (abs_off < filesize)) { |
679 | rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize; | 846 | rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize; |
680 | data[0] = (unsigned char) rel_off; | 847 | data[0] = (unsigned char) rel_off; |
681 | data[1] = (unsigned char) (rel_off >> 8); | 848 | data[1] = (unsigned char) (rel_off >> 8); |
682 | data[2] = (unsigned char) (rel_off >> 16); | 849 | data[2] = (unsigned char) (rel_off >> 16); |
683 | data[3] = (unsigned char) (rel_off >> 24); | 850 | data[3] = (unsigned char) (rel_off >> 24); |
684 | } | 851 | } |
685 | data += 4; | 852 | data += 4; |
686 | curpos += 5; | 853 | curpos += 5; |
687 | } | 854 | } |
688 | lzx->intel_curpos += frame_size; | 855 | lzx->intel_curpos += frame_size; |
689 | } | 856 | } |