source: nikanabo/current/xdelta/diy/xdelta3-decode.h

Last change on this file was 185, checked in by geyser, 17 years ago
File size: 29.0 KB
Line 
1/* xdelta 3 - delta compression tools and library
2 * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007. Joshua P. MacDonald
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19#ifndef _XDELTA3_DECODE_H_
20#define _XDELTA3_DECODE_H_
21
22
23/* Return true if the caller must provide a source. Theoretically, this has to be checked
24 * after every window. It could be that the first window requires no source, but the
25 * second window does. In practice? */
26int xd3_decoder_needs_source (xd3_stream *stream)
27{
28 return stream->dec_win_ind & VCD_SOURCE;
29}
30
31/* Initialize the decoder for a new window. The dec_tgtlen value is preserved across
32 * successive window decodings, and the update to dec_winstart is delayed until a new
33 * window actually starts. This is to avoid throwing an error due to overflow until the
34 * last possible moment. This makes it possible to encode exactly 4GB through a 32-bit
35 * encoder. */
36static int
37xd3_decode_init_window (xd3_stream *stream)
38{
39 stream->dec_cpylen = 0;
40 stream->dec_cpyoff = 0;
41 stream->dec_cksumbytes = 0;
42
43 xd3_init_cache (& stream->acache);
44
45 return 0;
46}
47
48/* Allocates buffer space for the target window and possibly the VCD_TARGET copy-window.
49 * Also sets the base of the two copy segments. */
50static int
51xd3_decode_setup_buffers (xd3_stream *stream)
52{
53 /* If VCD_TARGET is set then the previous buffer may be reused. */
54 if (stream->dec_win_ind & VCD_TARGET)
55 {
56 /* But this implementation only supports copying from the last target window. If the
57 * offset is outside that range, it can't be done. */
58 if (stream->dec_cpyoff < stream->dec_laststart)
59 {
60 stream->msg = "unsupported VCD_TARGET offset";
61 return XD3_INVALID_INPUT;
62 }
63
64 /* See if the two windows are the same. This indicates the first time VCD_TARGET is
65 * used. This causes a second buffer to be allocated, after that the two are
66 * swapped in the DEC_FINISH case. */
67 if (stream->dec_lastwin == stream->next_out)
68 {
69 stream->next_out = NULL;
70 stream->space_out = 0;
71 }
72
73 stream->dec_cpyaddrbase = stream->dec_lastwin + (usize_t) (stream->dec_cpyoff - stream->dec_laststart);
74 }
75
76 /* See if the current output window is large enough. */
77 if (stream->space_out < stream->dec_tgtlen)
78 {
79 xd3_free (stream, stream->dec_buffer);
80
81 stream->space_out = xd3_round_blksize (stream->dec_tgtlen, XD3_ALLOCSIZE);
82
83 if ((stream->dec_buffer = xd3_alloc (stream, stream->space_out, 1)) == NULL)
84 {
85 return ENOMEM;
86 }
87
88 stream->next_out = stream->dec_buffer;
89 }
90
91 /* dec_tgtaddrbase refers to an invalid base address, but it is always used with a
92 * sufficiently large instruction offset (i.e., beyond the copy window). This condition
93 * is enforced by xd3_decode_output_halfinst. */
94 stream->dec_tgtaddrbase = stream->next_out - stream->dec_cpylen;
95
96 return 0;
97}
98
99static int
100xd3_decode_allocate (xd3_stream *stream,
101 usize_t size,
102 uint8_t **copied1,
103 usize_t *alloc1,
104 uint8_t **copied2,
105 usize_t *alloc2)
106{
107 if (*copied1 != NULL && *alloc1 < size)
108 {
109 xd3_free (stream, *copied1);
110 *copied1 = NULL;
111 }
112
113 if (*copied1 == NULL)
114 {
115 *alloc1 = xd3_round_blksize (size, XD3_ALLOCSIZE);
116
117 if ((*copied1 = xd3_alloc (stream, *alloc1, 1)) == NULL)
118 {
119 return ENOMEM;
120 }
121 }
122
123 return 0;
124}
125
126static int
127xd3_decode_section (xd3_stream *stream,
128 xd3_desect *section,
129 xd3_decode_state nstate,
130 int copy)
131{
132 XD3_ASSERT (section->pos <= section->size);
133 XD3_ASSERT (stream->dec_state != nstate);
134
135 if (section->pos < section->size)
136 {
137 usize_t sect_take;
138
139 if (stream->avail_in == 0)
140 {
141 return XD3_INPUT;
142 }
143
144 if ((copy == 0) && (section->pos == 0))
145 {
146 /* No allocation/copy needed */
147 section->buf = stream->next_in;
148 sect_take = section->size;
149 }
150 else
151 {
152 usize_t sect_need = section->size - section->pos;
153
154 /* Allocate and copy */
155 sect_take = min (sect_need, stream->avail_in);
156
157 if (section->pos == 0)
158 {
159 int ret;
160
161 if ((ret = xd3_decode_allocate (stream,
162 section->size,
163 & section->copied1,
164 & section->alloc1,
165 & section->copied2,
166 & section->alloc2))) { return ret; }
167
168 section->buf = section->copied1;
169 }
170
171 memcpy (section->copied1 + section->pos,
172 stream->next_in,
173 sect_take);
174 }
175
176 section->pos += sect_take;
177
178 stream->dec_winbytes += sect_take;
179
180 DECODE_INPUT (sect_take);
181 }
182
183 if (section->pos < section->size)
184 {
185 stream->msg = "further input required";
186 return XD3_INPUT;
187 }
188
189 XD3_ASSERT (section->pos == section->size);
190
191 stream->dec_state = nstate;
192 section->buf_max = section->buf + section->size;
193 section->pos = 0;
194 return 0;
195}
196
197/* Decode the size and address for half of an instruction (i.e., a single opcode). This
198 * updates the stream->dec_position, which are bytes already output prior to processing
199 * this instruction. Perform bounds checking for sizes and copy addresses, which uses the
200 * dec_position (which is why these checks are done here). */
201static int
202xd3_decode_parse_halfinst (xd3_stream *stream, xd3_hinst *inst)
203{
204 int ret;
205
206 /* If the size from the instruction table is zero then read a size value. */
207 if ((inst->size == 0) &&
208 (ret = xd3_read_size (stream,
209 & stream->inst_sect.buf,
210 stream->inst_sect.buf_max,
211 & inst->size)))
212 {
213 return XD3_INVALID_INPUT;
214 }
215
216 /* For copy instructions, read address. */
217 if (inst->type >= XD3_CPY)
218 {
219 IF_DEBUG1 ({
220 static int cnt = 0;
221 DP(RINT "DECODE:%u: COPY at %"Q"u (winoffset %u) size %u winaddr %u\n",
222 cnt++,
223 stream->total_out + (stream->dec_position - stream->dec_cpylen),
224 (stream->dec_position - stream->dec_cpylen),
225 inst->size,
226 inst->addr);
227 });
228
229 if ((ret = xd3_decode_address (stream,
230 stream->dec_position,
231 inst->type - XD3_CPY,
232 & stream->addr_sect.buf,
233 stream->addr_sect.buf_max,
234 & inst->addr)))
235 {
236 return ret;
237 }
238
239 /* Cannot copy an address before it is filled-in. */
240 if (inst->addr >= stream->dec_position)
241 {
242 stream->msg = "address too large";
243 return XD3_INVALID_INPUT;
244 }
245
246 /* Check: a VCD_TARGET or VCD_SOURCE copy cannot exceed the remaining buffer space
247 * in its own segment. */
248 if (inst->addr < stream->dec_cpylen && inst->addr + inst->size > stream->dec_cpylen)
249 {
250 stream->msg = "size too large";
251 return XD3_INVALID_INPUT;
252 }
253 }
254 else
255 {
256 IF_DEBUG1 ({
257 if (inst->type == XD3_ADD)
258 {
259 static int cnt;
260 DP(RINT "DECODE:%d: ADD at %"Q"u (winoffset %u) size %u\n",
261 cnt++,
262 stream->total_out + stream->dec_position - stream->dec_cpylen,
263 stream->dec_position - stream->dec_cpylen,
264 inst->size);
265 }
266 else
267 {
268 static int cnt;
269 XD3_ASSERT (inst->type == XD3_RUN);
270 DP(RINT "DECODE:%d: RUN at %"Q"u (winoffset %u) size %u\n",
271 cnt++,
272 stream->total_out + stream->dec_position - stream->dec_cpylen,
273 stream->dec_position - stream->dec_cpylen,
274 inst->size);
275 }
276 });
277 }
278
279 /* Check: The instruction will not overflow the output buffer. */
280 if (stream->dec_position + inst->size > stream->dec_maxpos)
281 {
282 stream->msg = "size too large";
283 return XD3_INVALID_INPUT;
284 }
285
286 stream->dec_position += inst->size;
287 return 0;
288}
289
290/* Decode a single opcode and then decode the two half-instructions. */
291static int
292xd3_decode_instruction (xd3_stream *stream)
293{
294 int ret;
295 const xd3_dinst *inst;
296
297 if (stream->inst_sect.buf == stream->inst_sect.buf_max)
298 {
299 stream->msg = "instruction underflow";
300 return XD3_INVALID_INPUT;
301 }
302
303 inst = &stream->code_table[*stream->inst_sect.buf++];
304
305 stream->dec_current1.type = inst->type1;
306 stream->dec_current2.type = inst->type2;
307 stream->dec_current1.size = inst->size1;
308 stream->dec_current2.size = inst->size2;
309
310 /* For each instruction with a real operation, decode the corresponding size and
311 * addresses if necessary. Assume a code-table may have NOOP in either position,
312 * although this is unlikely. */
313 if (inst->type1 != XD3_NOOP && (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current1)))
314 {
315 return ret;
316 }
317 if (inst->type2 != XD3_NOOP && (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current2)))
318 {
319 return ret;
320 }
321 return 0;
322}
323
324/* Output the result of a single half-instruction. OPT: This the decoder hotspot. */
325static int
326xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst)
327{
328 /* To make this reentrant, set take = min (inst->size, available space)... */
329 usize_t take = inst->size;
330
331 XD3_ASSERT (inst->type != XD3_NOOP);
332
333 switch (inst->type)
334 {
335 case XD3_RUN:
336 {
337 /* Only require a single data byte. */
338 if (stream->data_sect.buf == stream->data_sect.buf_max)
339 {
340 stream->msg = "data underflow";
341 return XD3_INVALID_INPUT;
342 }
343
344 /* TUNE: Probably want to eliminate memset/memcpy here */
345 memset (stream->next_out + stream->avail_out,
346 stream->data_sect.buf[0],
347 take);
348
349 stream->data_sect.buf += 1;
350 stream->avail_out += take;
351 inst->type = XD3_NOOP;
352 break;
353 }
354 case XD3_ADD:
355 {
356 /* Require at least TAKE data bytes. */
357 if (stream->data_sect.buf + take > stream->data_sect.buf_max)
358 {
359 stream->msg = "data underflow";
360 return XD3_INVALID_INPUT;
361 }
362
363 memcpy (stream->next_out + stream->avail_out,
364 stream->data_sect.buf,
365 take);
366
367 stream->data_sect.buf += take;
368 stream->avail_out += take;
369 inst->type = XD3_NOOP;
370 break;
371 }
372 default:
373 {
374 usize_t i;
375 const uint8_t *src;
376 uint8_t *dst;
377
378 /* See if it copies from the VCD_TARGET/VCD_SOURCE window or the target window.
379 * Out-of-bounds checks for the addresses and sizes are performed in
380 * xd3_decode_parse_halfinst. */
381 if (inst->addr < stream->dec_cpylen)
382 {
383 if (stream->dec_win_ind & VCD_TARGET)
384 {
385 /* For VCD_TARGET we know the entire range is in-memory, as established by
386 * decode_setup_buffers. */
387 src = stream->dec_cpyaddrbase + inst->addr;
388 inst->type = XD3_NOOP;
389 inst->size = 0;
390 }
391 else
392 {
393 /* In this case we have to read a source block, which could return control
394 * to the caller. We need to know the first block number needed for this
395 * copy. */
396 xd3_source *source;
397 xoff_t block;
398 usize_t blkoff;
399 usize_t blksize;
400 int ret;
401
402 more:
403
404 source = stream->src;
405 block = source->cpyoff_blocks;
406 blkoff = source->cpyoff_blkoff + inst->addr;
407 blksize = source->blksize;
408
409 while (blkoff >= blksize)
410 {
411 block += 1;
412 blkoff -= blksize;
413 }
414
415 if ((ret = xd3_getblk (stream, block)))
416 {
417 /* could be a XD3_GETSRCBLK failure. */
418 XD3_ASSERT(ret != XD3_TOOFARBACK);
419 return ret;
420 }
421
422 src = source->curblk + blkoff;
423
424 /* This block either contains enough data or the source file is
425 * short. */
426 if ((source->onblk != blksize) && (blkoff + take > source->onblk))
427 {
428 stream->msg = "source file too short";
429 return XD3_INVALID_INPUT;
430
431 }
432
433 XD3_ASSERT (blkoff != blksize);
434
435 if (blkoff + take <= blksize)
436 {
437 inst->type = XD3_NOOP;
438 inst->size = 0;
439 }
440 else
441 {
442 /* This block doesn't contain all the data, modify the instruction, do
443 * not set to XD3_NOOP. */
444 take = blksize - blkoff;
445 inst->size -= take;
446 inst->addr += take;
447 }
448 }
449 }
450 else
451 {
452 /* For a target-window copy, we know the entire range is in-memory. The
453 * dec_tgtaddrbase is negatively offset by dec_cpylen because the addresses
454 * start beyond that point. */
455 src = stream->dec_tgtaddrbase + inst->addr;
456 inst->type = XD3_NOOP;
457 inst->size = 0;
458 }
459
460 dst = stream->next_out + stream->avail_out;
461
462 stream->avail_out += take;
463
464 /* Can't just memcpy here due to possible overlap. */
465 for (i = take; i != 0; i -= 1)
466 {
467 *dst++ = *src++;
468 }
469
470 take = inst->size;
471
472 /* If there is more to copy, call getblk again. */
473 if (inst->type != XD3_NOOP)
474 {
475 XD3_ASSERT (take > 0);
476 goto more;
477 }
478 else
479 {
480 XD3_ASSERT (take == 0);
481 }
482 }
483 }
484
485 return 0;
486}
487
488static int
489xd3_decode_finish_window (xd3_stream *stream)
490{
491 stream->dec_winbytes = 0;
492 stream->dec_state = DEC_FINISH;
493
494 stream->data_sect.pos = 0;
495 stream->inst_sect.pos = 0;
496 stream->addr_sect.pos = 0;
497
498 return XD3_OUTPUT;
499}
500
501static int
502xd3_decode_sections (xd3_stream *stream)
503{
504 usize_t need, more, take;
505 int copy, ret;
506
507 if ((stream->flags & XD3_JUST_HDR) != 0)
508 {
509 /* Nothing left to do. */
510 return xd3_decode_finish_window (stream);
511 }
512
513 /* To avoid copying, need this much data available */
514 need = (stream->inst_sect.size +
515 stream->addr_sect.size +
516 stream->data_sect.size);
517
518 /* The window may be entirely processed. */
519 XD3_ASSERT (stream->dec_winbytes <= need);
520
521 /* Compute how much more input is needed. */
522 more = (need - stream->dec_winbytes);
523
524 /* How much to consume. */
525 take = min (more, stream->avail_in);
526
527 /* See if the input is completely available, to avoid copy. */
528 copy = (take != more);
529
530 /* If the window is skipped... */
531 if ((stream->flags & XD3_SKIP_WINDOW) != 0)
532 {
533 /* Skip the available input. */
534 DECODE_INPUT (take);
535
536 stream->dec_winbytes += take;
537
538 if (copy)
539 {
540 stream->msg = "further input required";
541 return XD3_INPUT;
542 }
543
544 return xd3_decode_finish_window (stream);
545 }
546
547 /* Process all but the DATA section. */
548 switch (stream->dec_state)
549 {
550 default:
551 stream->msg = "internal error";
552 return XD3_INVALID_INPUT;
553
554 case DEC_DATA:
555 if ((ret = xd3_decode_section (stream, & stream->data_sect, DEC_INST, copy))) { return ret; }
556 case DEC_INST:
557 if ((ret = xd3_decode_section (stream, & stream->inst_sect, DEC_ADDR, copy))) { return ret; }
558 case DEC_ADDR:
559 if ((ret = xd3_decode_section (stream, & stream->addr_sect, DEC_EMIT, copy))) { return ret; }
560 }
561
562 XD3_ASSERT (stream->dec_winbytes == need);
563
564#if SECONDARY_ANY
565#define DECODE_SECONDARY_SECTION(UPPER,LOWER) \
566 ((stream->dec_del_ind & VCD_ ## UPPER ## COMP) && \
567 (ret = xd3_decode_secondary (stream, & stream-> LOWER ## _sect, \
568 & xd3_sec_ ## LOWER (stream))))
569
570 if (DECODE_SECONDARY_SECTION (DATA, data) ||
571 DECODE_SECONDARY_SECTION (INST, inst) ||
572 DECODE_SECONDARY_SECTION (ADDR, addr))
573 {
574 return ret;
575 }
576#endif
577
578 if (stream->flags & XD3_SKIP_EMIT)
579 {
580 return xd3_decode_finish_window (stream);
581 }
582
583 /* OPT: A possible optimization is to avoid allocating memory in decode_setup_buffers
584 * and to avoid a large memcpy when the window consists of a single VCD_SOURCE copy
585 * instruction. The only potential problem is if the following window is a VCD_TARGET,
586 * then you need to remember... */
587 if ((ret = xd3_decode_setup_buffers (stream))) { return ret; }
588
589 return 0;
590}
591
592static int
593xd3_decode_emit (xd3_stream *stream)
594{
595 int ret;
596
597 /* Produce output: originally structured to allow reentrant code that fills as much of
598 * the output buffer as possible, but VCDIFF semantics allows to copy from anywhere from
599 * the target window, so instead allocate a sufficiently sized buffer after the target
600 * window length is decoded.
601 *
602 * This code still needs to be reentrant to allow XD3_GETSRCBLK to return control. This
603 * is handled by setting the stream->dec_currentN instruction types to XD3_NOOP after
604 * they have been processed. */
605 XD3_ASSERT (! (stream->flags & XD3_SKIP_EMIT));
606 XD3_ASSERT (stream->avail_out == 0);
607 XD3_ASSERT (stream->dec_tgtlen <= stream->space_out);
608
609 while (stream->inst_sect.buf != stream->inst_sect.buf_max)
610 {
611 /* Decode next instruction pair. */
612 if ((stream->dec_current1.type == XD3_NOOP) &&
613 (stream->dec_current2.type == XD3_NOOP) &&
614 (ret = xd3_decode_instruction (stream))) { return ret; }
615
616 /* Output for each instruction. */
617 if ((stream->dec_current1.type != XD3_NOOP) &&
618 (ret = xd3_decode_output_halfinst (stream, & stream->dec_current1))) { return ret; }
619
620 if ((stream->dec_current2.type != XD3_NOOP) &&
621 (ret = xd3_decode_output_halfinst (stream, & stream->dec_current2))) { return ret; }
622 }
623
624 if (stream->avail_out != stream->dec_tgtlen)
625 {
626 IF_DEBUG1 (DP(RINT "AVAIL_OUT(%d) != DEC_TGTLEN(%d)\n", stream->avail_out, stream->dec_tgtlen));
627 stream->msg = "wrong window length";
628 return XD3_INVALID_INPUT;
629 }
630
631 if (stream->data_sect.buf != stream->data_sect.buf_max)
632 {
633 stream->msg = "extra data section";
634 return XD3_INVALID_INPUT;
635 }
636
637 if (stream->addr_sect.buf != stream->addr_sect.buf_max)
638 {
639 stream->msg = "extra address section";
640 return XD3_INVALID_INPUT;
641 }
642
643 /* OPT: Should cksum computation be combined with the above loop? */
644 if ((stream->dec_win_ind & VCD_ADLER32) != 0 &&
645 (stream->flags & XD3_ADLER32_NOVER) == 0)
646 {
647 uint32_t a32 = adler32 (1L, stream->next_out, stream->avail_out);
648
649 if (a32 != stream->dec_adler32)
650 {
651 stream->msg = "target window checksum mismatch";
652 return XD3_INVALID_INPUT;
653 }
654 }
655
656 /* Finished with a window. */
657 return xd3_decode_finish_window (stream);
658}
659
660int
661xd3_decode_input (xd3_stream *stream)
662{
663 int ret;
664
665 if (stream->enc_state != 0)
666 {
667 stream->msg = "encoder/decoder transition";
668 return XD3_INVALID_INPUT;
669 }
670
671#define BYTE_CASE(expr,x,nstate) \
672 do { \
673 if ( (expr) && \
674 ((ret = xd3_decode_byte (stream, & (x))) != 0) ) { return ret; } \
675 stream->dec_state = (nstate); \
676 } while (0)
677
678#define OFFSET_CASE(expr,x,nstate) \
679 do { \
680 if ( (expr) && \
681 ((ret = xd3_decode_offset (stream, & (x))) != 0) ) { return ret; } \
682 stream->dec_state = (nstate); \
683 } while (0)
684
685#define SIZE_CASE(expr,x,nstate) \
686 do { \
687 if ( (expr) && \
688 ((ret = xd3_decode_size (stream, & (x))) != 0) ) { return ret; } \
689 stream->dec_state = (nstate); \
690 } while (0)
691
692#define SRCORTGT(x) (((x) & VCD_SRCORTGT) == VCD_SOURCE || \
693 ((x) & VCD_SRCORTGT) == VCD_TARGET)
694
695 switch (stream->dec_state)
696 {
697 case DEC_VCHEAD:
698 {
699 if ((ret = xd3_decode_bytes (stream, stream->dec_magic, & stream->dec_magicbytes, 4))) { return ret; }
700
701 if (stream->dec_magic[0] != VCDIFF_MAGIC1 ||
702 stream->dec_magic[1] != VCDIFF_MAGIC2 ||
703 stream->dec_magic[2] != VCDIFF_MAGIC3)
704 {
705 stream->msg = "not a VCDIFF input";
706 return XD3_INVALID_INPUT;
707 }
708
709 if (stream->dec_magic[3] != 0)
710 {
711 stream->msg = "VCDIFF input version > 0 is not supported";
712 return XD3_INVALID_INPUT;
713 }
714
715 stream->dec_state = DEC_HDRIND;
716 }
717 case DEC_HDRIND:
718 {
719 if ((ret = xd3_decode_byte (stream, & stream->dec_hdr_ind))) { return ret; }
720
721 if ((stream->dec_hdr_ind & VCD_INVHDR) != 0)
722 {
723 stream->msg = "unrecognized header indicator bits set";
724 return XD3_INVALID_INPUT;
725 }
726
727 stream->dec_state = DEC_SECONDID;
728 }
729
730 case DEC_SECONDID:
731 /* Secondary compressor ID: only if VCD_SECONDARY is set */
732 if ((stream->dec_hdr_ind & VCD_SECONDARY) != 0)
733 {
734 BYTE_CASE (1, stream->dec_secondid, DEC_TABLEN);
735
736 switch (stream->dec_secondid)
737 {
738 case VCD_FGK_ID:
739 FGK_CASE (stream);
740 case VCD_DJW_ID:
741 DJW_CASE (stream);
742 default:
743 stream->msg = "unknown secondary compressor ID";
744 return XD3_INVALID_INPUT;
745 }
746 }
747
748 case DEC_TABLEN:
749 /* Length of code table data: only if VCD_CODETABLE is set */
750 SIZE_CASE ((stream->dec_hdr_ind & VCD_CODETABLE) != 0, stream->dec_codetblsz, DEC_NEAR);
751
752 /* The codetblsz counts the two NEAR/SAME bytes */
753 if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0) {
754 if (stream->dec_codetblsz <= 2) {
755 stream->msg = "invalid code table size";
756 return ENOMEM;
757 }
758 stream->dec_codetblsz -= 2;
759 }
760 case DEC_NEAR:
761 /* Near modes: only if VCD_CODETABLE is set */
762 BYTE_CASE((stream->dec_hdr_ind & VCD_CODETABLE) != 0, stream->acache.s_near, DEC_SAME);
763 case DEC_SAME:
764 /* Same modes: only if VCD_CODETABLE is set */
765 BYTE_CASE((stream->dec_hdr_ind & VCD_CODETABLE) != 0, stream->acache.s_same, DEC_TABDAT);
766 case DEC_TABDAT:
767 /* Compressed code table data */
768
769 if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0)
770 {
771 /* Get the code table data. */
772 if ((stream->dec_codetbl == NULL) &&
773 (stream->dec_codetbl = xd3_alloc (stream, stream->dec_codetblsz, 1)) == NULL) { return ENOMEM; }
774
775 if ((ret = xd3_decode_bytes (stream, stream->dec_codetbl, & stream->dec_codetblbytes, stream->dec_codetblsz)))
776 {
777 return ret;
778 }
779
780 if ((ret = xd3_apply_table_encoding (stream, stream->dec_codetbl, stream->dec_codetblbytes)))
781 {
782 return ret;
783 }
784 }
785 else
786 {
787 /* Use the default table. */
788 stream->acache.s_near = __rfc3284_code_table_desc.near_modes;
789 stream->acache.s_same = __rfc3284_code_table_desc.same_modes;
790 stream->code_table = xd3_rfc3284_code_table ();
791 }
792
793 if ((ret = xd3_alloc_cache (stream))) { return ret; }
794
795 stream->dec_state = DEC_APPLEN;
796
797 case DEC_APPLEN:
798 /* Length of application data */
799 SIZE_CASE((stream->dec_hdr_ind & VCD_APPHEADER) != 0, stream->dec_appheadsz, DEC_APPDAT);
800
801 case DEC_APPDAT:
802 /* Application data */
803 if (stream->dec_hdr_ind & VCD_APPHEADER)
804 {
805 /* Note: we add an additional byte for padding, to allow 0-termination. */
806 if ((stream->dec_appheader == NULL) &&
807 (stream->dec_appheader = xd3_alloc (stream, stream->dec_appheadsz+1, 1)) == NULL) { return ENOMEM; }
808
809 stream->dec_appheader[stream->dec_appheadsz] = 0;
810
811 if ((ret = xd3_decode_bytes (stream, stream->dec_appheader, & stream->dec_appheadbytes, stream->dec_appheadsz)))
812 {
813 return ret;
814 }
815 }
816
817 stream->dec_hdrsize = stream->total_in;
818 stream->dec_state = DEC_WININD;
819
820 case DEC_WININD:
821 {
822 /* Start of a window: the window indicator */
823
824 if ((ret = xd3_decode_byte (stream, & stream->dec_win_ind))) { return ret; }
825
826 stream->current_window = stream->dec_window_count;
827
828 if (XOFF_T_OVERFLOW (stream->dec_winstart, stream->dec_tgtlen))
829 {
830 stream->msg = "decoder file offset overflow";
831 return XD3_INVALID_INPUT;
832 }
833
834 stream->dec_winstart += stream->dec_tgtlen;
835
836 if ((stream->dec_win_ind & VCD_INVWIN) != 0)
837 {
838 stream->msg = "unrecognized window indicator bits set";
839 return XD3_INVALID_INPUT;
840 }
841
842 if ((ret = xd3_decode_init_window (stream))) { return ret; }
843
844 stream->dec_state = DEC_CPYLEN;
845
846 IF_DEBUG1 (DP(RINT "--------- TARGET WINDOW %"Q"u ------------------\n", stream->current_window));
847 }
848
849 case DEC_CPYLEN:
850 /* Copy window length: only if VCD_SOURCE or VCD_TARGET is set */
851 SIZE_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpylen, DEC_CPYOFF);
852
853 /* Set the initial, logical decoder position (HERE address) in dec_position. This
854 * is set to just after the source/copy window, as we are just about to output the
855 * first byte of target window. */
856 stream->dec_position = stream->dec_cpylen;
857
858 case DEC_CPYOFF:
859 /* Copy window offset: only if VCD_SOURCE or VCD_TARGET is set */
860 OFFSET_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpyoff, DEC_ENCLEN);
861
862 /* Copy offset and copy length may not overflow. */
863 if (XOFF_T_OVERFLOW (stream->dec_cpyoff, stream->dec_cpylen))
864 {
865 stream->msg = "decoder copy window overflows a file offset";
866 return XD3_INVALID_INPUT;
867 }
868
869 /* Check copy window bounds: VCD_TARGET window may not exceed current position. */
870 if ((stream->dec_win_ind & VCD_TARGET) &&
871 (stream->dec_cpyoff + (xoff_t) stream->dec_cpylen > stream->dec_winstart))
872 {
873 stream->msg = "VCD_TARGET window out of bounds";
874 return XD3_INVALID_INPUT;
875 }
876
877 case DEC_ENCLEN:
878 /* Length of the delta encoding */
879 SIZE_CASE(1, stream->dec_enclen, DEC_TGTLEN);
880 case DEC_TGTLEN:
881 /* Length of target window */
882 SIZE_CASE(1, stream->dec_tgtlen, DEC_DELIND);
883
884 /* Set the maximum decoder position, beyond which we should not decode any data.
885 * This is the maximum value for dec_position. This may not exceed the size of a
886 * usize_t. */
887 if (USIZE_T_OVERFLOW (stream->dec_cpylen, stream->dec_tgtlen))
888 {
889 stream->msg = "decoder target window overflows a usize_t";
890 return XD3_INVALID_INPUT;
891 }
892
893 /* Check for malicious files. */
894 if (stream->dec_tgtlen > XD3_HARDMAXWINSIZE)
895 {
896 stream->msg = "hard window size exceeded";
897 return XD3_INVALID_INPUT;
898 }
899
900 stream->dec_maxpos = stream->dec_cpylen + stream->dec_tgtlen;
901
902 case DEC_DELIND:
903 /* Delta indicator */
904 BYTE_CASE(1, stream->dec_del_ind, DEC_DATALEN);
905
906 if ((stream->dec_del_ind & VCD_INVDEL) != 0)
907 {
908 stream->msg = "unrecognized delta indicator bits set";
909 return XD3_INVALID_INPUT;
910 }
911
912 /* Delta indicator is only used with secondary compression. */
913 if ((stream->dec_del_ind != 0) && (stream->sec_type == NULL))
914 {
915 stream->msg = "invalid delta indicator bits set";
916 return XD3_INVALID_INPUT;
917 }
918
919 /* Section lengths */
920 case DEC_DATALEN:
921 SIZE_CASE(1, stream->data_sect.size, DEC_INSTLEN);
922 case DEC_INSTLEN:
923 SIZE_CASE(1, stream->inst_sect.size, DEC_ADDRLEN);
924 case DEC_ADDRLEN:
925 SIZE_CASE(1, stream->addr_sect.size, DEC_CKSUM);
926
927 case DEC_CKSUM:
928 /* Window checksum. */
929 if ((stream->dec_win_ind & VCD_ADLER32) != 0)
930 {
931 int i;
932
933 if ((ret = xd3_decode_bytes (stream, stream->dec_cksum, & stream->dec_cksumbytes, 4))) { return ret; }
934
935 for (i = 0; i < 4; i += 1)
936 {
937 stream->dec_adler32 = (stream->dec_adler32 << 8) | stream->dec_cksum[i];
938 }
939 }
940
941 stream->dec_state = DEC_DATA;
942
943 /* Check dec_enclen for redundency, otherwise it is not really used. */
944 {
945 usize_t enclen_check = (1 + (xd3_sizeof_size (stream->dec_tgtlen) +
946 xd3_sizeof_size (stream->data_sect.size) +
947 xd3_sizeof_size (stream->inst_sect.size) +
948 xd3_sizeof_size (stream->addr_sect.size)) +
949 stream->data_sect.size +
950 stream->inst_sect.size +
951 stream->addr_sect.size +
952 ((stream->dec_win_ind & VCD_ADLER32) ? 4 : 0));
953
954 if (stream->dec_enclen != enclen_check)
955 {
956 stream->msg = "incorrect encoding length (redundent)";
957 return XD3_INVALID_INPUT;
958 }
959 }
960
961 /* Returning here gives the application a chance to inspect the header, skip the
962 * window, etc. */
963 if (stream->current_window == 0) { return XD3_GOTHEADER; }
964 else { return XD3_WINSTART; }
965
966 case DEC_DATA:
967 case DEC_INST:
968 case DEC_ADDR:
969 /* Next read the three sections. */
970 if ((ret = xd3_decode_sections (stream))) { return ret; }
971
972 case DEC_EMIT:
973
974 /* To speed VCD_SOURCE block-address calculations, the source cpyoff_blocks and
975 * cpyoff_blkoff are pre-computed. */
976 if (stream->dec_win_ind & VCD_SOURCE)
977 {
978 xd3_source *src = stream->src;
979
980 if (src == NULL)
981 {
982 stream->msg = "source input required";
983 return XD3_INVALID_INPUT;
984 }
985
986 src->cpyoff_blocks = stream->dec_cpyoff / src->blksize;
987 src->cpyoff_blkoff = stream->dec_cpyoff % src->blksize;
988 }
989
990 /* xd3_decode_emit returns XD3_OUTPUT on every success. */
991 if ((ret = xd3_decode_emit (stream)) == XD3_OUTPUT)
992 {
993 stream->total_out += (xoff_t) stream->avail_out;
994 }
995
996 return ret;
997
998 case DEC_FINISH:
999 {
1000 if (stream->dec_win_ind & VCD_TARGET)
1001 {
1002 if (stream->dec_lastwin == NULL)
1003 {
1004 stream->dec_lastwin = stream->next_out;
1005 stream->dec_lastspace = stream->space_out;
1006 }
1007 else
1008 {
1009 xd3_swap_uint8p (& stream->dec_lastwin, & stream->next_out);
1010 xd3_swap_usize_t (& stream->dec_lastspace, & stream->space_out);
1011 }
1012 }
1013
1014 stream->dec_lastlen = stream->dec_tgtlen;
1015 stream->dec_laststart = stream->dec_winstart;
1016 stream->dec_window_count += 1;
1017
1018 /* Note: the updates to dec_winstart & current_window are deferred until after the
1019 * next DEC_WININD byte is read. */
1020 stream->dec_state = DEC_WININD;
1021 return XD3_WINFINISH;
1022 }
1023
1024 default:
1025 stream->msg = "invalid state";
1026 return XD3_INVALID_INPUT;
1027 }
1028}
1029
1030#endif // _XDELTA3_DECODE_H_
Note: See TracBrowser for help on using the repository browser.