summaryrefslogtreecommitdiff
path: root/xdelta3/xdelta3-decode.h
diff options
context:
space:
mode:
Diffstat (limited to 'xdelta3/xdelta3-decode.h')
-rw-r--r--xdelta3/xdelta3-decode.h181
1 files changed, 102 insertions, 79 deletions
diff --git a/xdelta3/xdelta3-decode.h b/xdelta3/xdelta3-decode.h
index bb03c04..5ddf823 100644
--- a/xdelta3/xdelta3-decode.h
+++ b/xdelta3/xdelta3-decode.h
@@ -20,19 +20,21 @@
20#define _XDELTA3_DECODE_H_ 20#define _XDELTA3_DECODE_H_
21 21
22 22
23/* Return true if the caller must provide a source. Theoretically, this has to be checked 23/* Return true if the caller must provide a source. Theoretically,
24 * after every window. It could be that the first window requires no source, but the 24 * this has to be checked after every window. It could be that the
25 * second window does. In practice? */ 25 * first window requires no source, but the second window does. In
26 * practice? */
26int xd3_decoder_needs_source (xd3_stream *stream) 27int xd3_decoder_needs_source (xd3_stream *stream)
27{ 28{
28 return stream->dec_win_ind & VCD_SOURCE; 29 return stream->dec_win_ind & VCD_SOURCE;
29} 30}
30 31
31/* Initialize the decoder for a new window. The dec_tgtlen value is preserved across 32/* Initialize the decoder for a new window. The dec_tgtlen value is
32 * successive window decodings, and the update to dec_winstart is delayed until a new 33 * preserved across successive window decodings, and the update to
33 * window actually starts. This is to avoid throwing an error due to overflow until the 34 * dec_winstart is delayed until a new window actually starts. This
34 * last possible moment. This makes it possible to encode exactly 4GB through a 32-bit 35 * is to avoid throwing an error due to overflow until the last
35 * encoder. */ 36 * possible moment. This makes it possible to encode exactly 4GB
37 * through a 32-bit encoder. */
36static int 38static int
37xd3_decode_init_window (xd3_stream *stream) 39xd3_decode_init_window (xd3_stream *stream)
38{ 40{
@@ -45,25 +47,28 @@ xd3_decode_init_window (xd3_stream *stream)
45 return 0; 47 return 0;
46} 48}
47 49
48/* Allocates buffer space for the target window and possibly the VCD_TARGET copy-window. 50/* Allocates buffer space for the target window and possibly the
49 * Also sets the base of the two copy segments. */ 51 * VCD_TARGET copy-window. Also sets the base of the two copy
52 * segments. */
50static int 53static int
51xd3_decode_setup_buffers (xd3_stream *stream) 54xd3_decode_setup_buffers (xd3_stream *stream)
52{ 55{
53 /* If VCD_TARGET is set then the previous buffer may be reused. */ 56 /* If VCD_TARGET is set then the previous buffer may be reused. */
54 if (stream->dec_win_ind & VCD_TARGET) 57 if (stream->dec_win_ind & VCD_TARGET)
55 { 58 {
56 /* But this implementation only supports copying from the last target window. If the 59 /* But this implementation only supports copying from the last
57 * offset is outside that range, it can't be done. */ 60 * target window. If the offset is outside that range, it can't
61 * be done. */
58 if (stream->dec_cpyoff < stream->dec_laststart) 62 if (stream->dec_cpyoff < stream->dec_laststart)
59 { 63 {
60 stream->msg = "unsupported VCD_TARGET offset"; 64 stream->msg = "unsupported VCD_TARGET offset";
61 return XD3_INVALID_INPUT; 65 return XD3_INVALID_INPUT;
62 } 66 }
63 67
64 /* See if the two windows are the same. This indicates the first time VCD_TARGET is 68 /* See if the two windows are the same. This indicates the
65 * used. This causes a second buffer to be allocated, after that the two are 69 * first time VCD_TARGET is used. This causes a second buffer
66 * swapped in the DEC_FINISH case. */ 70 * to be allocated, after that the two are swapped in the
71 * DEC_FINISH case. */
67 if (stream->dec_lastwin == stream->next_out) 72 if (stream->dec_lastwin == stream->next_out)
68 { 73 {
69 stream->next_out = NULL; 74 stream->next_out = NULL;
@@ -88,9 +93,10 @@ xd3_decode_setup_buffers (xd3_stream *stream)
88 stream->next_out = stream->dec_buffer; 93 stream->next_out = stream->dec_buffer;
89 } 94 }
90 95
91 /* dec_tgtaddrbase refers to an invalid base address, but it is always used with a 96 /* dec_tgtaddrbase refers to an invalid base address, but it is
92 * sufficiently large instruction offset (i.e., beyond the copy window). This condition 97 * always used with a sufficiently large instruction offset (i.e.,
93 * is enforced by xd3_decode_output_halfinst. */ 98 * beyond the copy window). This condition is enforced by
99 * xd3_decode_output_halfinst. */
94 stream->dec_tgtaddrbase = stream->next_out - stream->dec_cpylen; 100 stream->dec_tgtaddrbase = stream->next_out - stream->dec_cpylen;
95 101
96 return 0; 102 return 0;
@@ -190,9 +196,10 @@ xd3_decode_section (xd3_stream *stream,
190 return 0; 196 return 0;
191} 197}
192 198
193/* Decode the size and address for half of an instruction (i.e., a single opcode). This 199/* Decode the size and address for half of an instruction (i.e., a
194 * updates the stream->dec_position, which are bytes already output prior to processing 200 * single opcode). This updates the stream->dec_position, which are
195 * this instruction. Perform bounds checking for sizes and copy addresses, which uses the 201 * bytes already output prior to processing this instruction. Perform
202 * bounds checking for sizes and copy addresses, which uses the
196 * dec_position (which is why these checks are done here). */ 203 * dec_position (which is why these checks are done here). */
197static int 204static int
198xd3_decode_parse_halfinst (xd3_stream *stream, xd3_hinst *inst) 205xd3_decode_parse_halfinst (xd3_stream *stream, xd3_hinst *inst)
@@ -303,9 +310,10 @@ xd3_decode_instruction (xd3_stream *stream)
303 stream->dec_current1.size = inst->size1; 310 stream->dec_current1.size = inst->size1;
304 stream->dec_current2.size = inst->size2; 311 stream->dec_current2.size = inst->size2;
305 312
306 /* For each instruction with a real operation, decode the corresponding size and 313 /* For each instruction with a real operation, decode the
307 * addresses if necessary. Assume a code-table may have NOOP in either position, 314 * corresponding size and addresses if necessary. Assume a
308 * although this is unlikely. */ 315 * code-table may have NOOP in either position, although this is
316 * unlikely. */
309 if (inst->type1 != XD3_NOOP && (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current1))) 317 if (inst->type1 != XD3_NOOP && (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current1)))
310 { 318 {
311 return ret; 319 return ret;
@@ -317,11 +325,13 @@ xd3_decode_instruction (xd3_stream *stream)
317 return 0; 325 return 0;
318} 326}
319 327
320/* Output the result of a single half-instruction. OPT: This the decoder hotspot. */ 328/* Output the result of a single half-instruction. OPT: This the
329 decoder hotspot. */
321static int 330static int
322xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst) 331xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst)
323{ 332{
324 /* To make this reentrant, set take = min (inst->size, available space)... */ 333 /* To make this reentrant, set take = min (inst->size, available
334 space)... */
325 usize_t take = inst->size; 335 usize_t take = inst->size;
326 336
327 XD3_ASSERT (inst->type != XD3_NOOP); 337 XD3_ASSERT (inst->type != XD3_NOOP);
@@ -370,14 +380,15 @@ xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst)
370 const uint8_t *src; 380 const uint8_t *src;
371 uint8_t *dst; 381 uint8_t *dst;
372 382
373 /* See if it copies from the VCD_TARGET/VCD_SOURCE window or the target window. 383 /* See if it copies from the VCD_TARGET/VCD_SOURCE window or
374 * Out-of-bounds checks for the addresses and sizes are performed in 384 * the target window. Out-of-bounds checks for the addresses
375 * xd3_decode_parse_halfinst. */ 385 * and sizes are performed in xd3_decode_parse_halfinst. */
376 if (inst->addr < stream->dec_cpylen) 386 if (inst->addr < stream->dec_cpylen)
377 { 387 {
378 if (stream->dec_win_ind & VCD_TARGET) 388 if (stream->dec_win_ind & VCD_TARGET)
379 { 389 {
380 /* For VCD_TARGET we know the entire range is in-memory, as established by 390 /* For VCD_TARGET we know the entire range is
391 * in-memory, as established by
381 * decode_setup_buffers. */ 392 * decode_setup_buffers. */
382 src = stream->dec_cpyaddrbase + inst->addr; 393 src = stream->dec_cpyaddrbase + inst->addr;
383 inst->type = XD3_NOOP; 394 inst->type = XD3_NOOP;
@@ -385,8 +396,9 @@ xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst)
385 } 396 }
386 else 397 else
387 { 398 {
388 /* In this case we have to read a source block, which could return control 399 /* In this case we have to read a source block, which
389 * to the caller. We need to know the first block number needed for this 400 * could return control to the caller. We need to
401 * know the first block number needed for this
390 * copy. */ 402 * copy. */
391 xd3_source *source; 403 xd3_source *source;
392 xoff_t block; 404 xoff_t block;
@@ -419,8 +431,8 @@ xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst)
419 431
420 src = source->curblk + blkoff; 432 src = source->curblk + blkoff;
421 433
422 /* This block either contains enough data or the source file is 434 /* This block either contains enough data or the
423 * short. */ 435 * source file is short. */
424 if ((source->onblk != blksize) && (blkoff + take > source->onblk)) 436 if ((source->onblk != blksize) && (blkoff + take > source->onblk))
425 { 437 {
426 stream->msg = "source file too short"; 438 stream->msg = "source file too short";
@@ -437,8 +449,8 @@ xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst)
437 } 449 }
438 else 450 else
439 { 451 {
440 /* This block doesn't contain all the data, modify the instruction, do 452 /* This block doesn't contain all the data, modify
441 * not set to XD3_NOOP. */ 453 * the instruction, do not set to XD3_NOOP. */
442 take = blksize - blkoff; 454 take = blksize - blkoff;
443 inst->size -= take; 455 inst->size -= take;
444 inst->addr += take; 456 inst->addr += take;
@@ -447,9 +459,10 @@ xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst)
447 } 459 }
448 else 460 else
449 { 461 {
450 /* For a target-window copy, we know the entire range is in-memory. The 462 /* For a target-window copy, we know the entire range is
451 * dec_tgtaddrbase is negatively offset by dec_cpylen because the addresses 463 * in-memory. The dec_tgtaddrbase is negatively offset by
452 * start beyond that point. */ 464 * dec_cpylen because the addresses start beyond that
465 * point. */
453 src = stream->dec_tgtaddrbase + inst->addr; 466 src = stream->dec_tgtaddrbase + inst->addr;
454 inst->type = XD3_NOOP; 467 inst->type = XD3_NOOP;
455 inst->size = 0; 468 inst->size = 0;
@@ -587,9 +600,10 @@ xd3_decode_sections (xd3_stream *stream)
587 return xd3_decode_finish_window (stream); 600 return xd3_decode_finish_window (stream);
588 } 601 }
589 602
590 /* OPT: A possible optimization is to avoid allocating memory in decode_setup_buffers 603 /* OPT: A possible optimization is to avoid allocating memory in
591 * and to avoid a large memcpy when the window consists of a single VCD_SOURCE copy 604 * decode_setup_buffers and to avoid a large memcpy when the window
592 * instruction. The only potential problem is if the following window is a VCD_TARGET, 605 * consists of a single VCD_SOURCE copy instruction. The only
606 * potential problem is if the following window is a VCD_TARGET,
593 * then you need to remember... */ 607 * then you need to remember... */
594 if ((ret = xd3_decode_setup_buffers (stream))) { return ret; } 608 if ((ret = xd3_decode_setup_buffers (stream))) { return ret; }
595 609
@@ -601,14 +615,16 @@ xd3_decode_emit (xd3_stream *stream)
601{ 615{
602 int ret; 616 int ret;
603 617
604 /* Produce output: originally structured to allow reentrant code that fills as much of 618 /* Produce output: originally structured to allow reentrant code
605 * the output buffer as possible, but VCDIFF semantics allows to copy from anywhere from 619 * that fills as much of the output buffer as possible, but VCDIFF
606 * the target window, so instead allocate a sufficiently sized buffer after the target 620 * semantics allows to copy from anywhere from the target window, so
621 * instead allocate a sufficiently sized buffer after the target
607 * window length is decoded. 622 * window length is decoded.
608 * 623 *
609 * This code still needs to be reentrant to allow XD3_GETSRCBLK to return control. This 624 * This code still needs to be reentrant to allow XD3_GETSRCBLK to
610 * is handled by setting the stream->dec_currentN instruction types to XD3_NOOP after 625 * return control. This is handled by setting the
611 * they have been processed. */ 626 * stream->dec_currentN instruction types to XD3_NOOP after they
627 * have been processed. */
612 XD3_ASSERT (! (stream->flags & XD3_SKIP_EMIT)); 628 XD3_ASSERT (! (stream->flags & XD3_SKIP_EMIT));
613 XD3_ASSERT (stream->dec_tgtlen <= stream->space_out); 629 XD3_ASSERT (stream->dec_tgtlen <= stream->space_out);
614 630
@@ -683,35 +699,39 @@ xd3_decode_input (xd3_stream *stream)
683 return XD3_INVALID_INPUT; 699 return XD3_INVALID_INPUT;
684 } 700 }
685 701
686#define BYTE_CASE(expr,x,nstate) \ 702#define BYTE_CASE(expr,x,nstate) \
687 do { \ 703 do { \
688 if ( (expr) && \ 704 if ( (expr) && \
689 ((ret = xd3_decode_byte (stream, & (x))) != 0) ) { return ret; } \ 705 ((ret = xd3_decode_byte (stream, & (x))) != 0) ) { return ret; } \
690 stream->dec_state = (nstate); \ 706 stream->dec_state = (nstate); \
691 } while (0) 707 } while (0)
692 708
693#define OFFSET_CASE(expr,x,nstate) \ 709#define OFFSET_CASE(expr,x,nstate) \
694 do { \ 710 do { \
695 if ( (expr) && \ 711 if ( (expr) && \
696 ((ret = xd3_decode_offset (stream, & (x))) != 0) ) { return ret; } \ 712 ((ret = xd3_decode_offset (stream, & (x))) != 0) ) { return ret; } \
697 stream->dec_state = (nstate); \ 713 stream->dec_state = (nstate); \
698 } while (0) 714 } while (0)
699 715
700#define SIZE_CASE(expr,x,nstate) \ 716#define SIZE_CASE(expr,x,nstate) \
701 do { \ 717 do { \
702 if ( (expr) && \ 718 if ( (expr) && \
703 ((ret = xd3_decode_size (stream, & (x))) != 0) ) { return ret; } \ 719 ((ret = xd3_decode_size (stream, & (x))) != 0) ) { return ret; } \
704 stream->dec_state = (nstate); \ 720 stream->dec_state = (nstate); \
705 } while (0) 721 } while (0)
706 722
707#define SRCORTGT(x) (((x) & VCD_SRCORTGT) == VCD_SOURCE || \ 723#define SRCORTGT(x) (((x) & VCD_SRCORTGT) == VCD_SOURCE || \
708 ((x) & VCD_SRCORTGT) == VCD_TARGET) 724 ((x) & VCD_SRCORTGT) == VCD_TARGET)
709 725
710 switch (stream->dec_state) 726 switch (stream->dec_state)
711 { 727 {
712 case DEC_VCHEAD: 728 case DEC_VCHEAD:
713 { 729 {
714 if ((ret = xd3_decode_bytes (stream, stream->dec_magic, & stream->dec_magicbytes, 4))) { return ret; } 730 if ((ret = xd3_decode_bytes (stream, stream->dec_magic,
731 & stream->dec_magicbytes, 4)))
732 {
733 return ret;
734 }
715 735
716 if (stream->dec_magic[0] != VCDIFF_MAGIC1 || 736 if (stream->dec_magic[0] != VCDIFF_MAGIC1 ||
717 stream->dec_magic[1] != VCDIFF_MAGIC2 || 737 stream->dec_magic[1] != VCDIFF_MAGIC2 ||
@@ -817,7 +837,8 @@ xd3_decode_input (xd3_stream *stream)
817 /* Application data */ 837 /* Application data */
818 if (stream->dec_hdr_ind & VCD_APPHEADER) 838 if (stream->dec_hdr_ind & VCD_APPHEADER)
819 { 839 {
820 /* Note: we add an additional byte for padding, to allow 0-termination. */ 840 /* Note: we add an additional byte for padding, to allow
841 0-termination. */
821 if ((stream->dec_appheader == NULL) && 842 if ((stream->dec_appheader == NULL) &&
822 (stream->dec_appheader = xd3_alloc (stream, stream->dec_appheadsz+1, 1)) == NULL) { return ENOMEM; } 843 (stream->dec_appheader = xd3_alloc (stream, stream->dec_appheadsz+1, 1)) == NULL) { return ENOMEM; }
823 844
@@ -865,9 +886,10 @@ xd3_decode_input (xd3_stream *stream)
865 /* Copy window length: only if VCD_SOURCE or VCD_TARGET is set */ 886 /* Copy window length: only if VCD_SOURCE or VCD_TARGET is set */
866 SIZE_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpylen, DEC_CPYOFF); 887 SIZE_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpylen, DEC_CPYOFF);
867 888
868 /* Set the initial, logical decoder position (HERE address) in dec_position. This 889 /* Set the initial, logical decoder position (HERE address) in
869 * is set to just after the source/copy window, as we are just about to output the 890 * dec_position. This is set to just after the source/copy
870 * first byte of target window. */ 891 * window, as we are just about to output the first byte of
892 * target window. */
871 stream->dec_position = stream->dec_cpylen; 893 stream->dec_position = stream->dec_cpylen;
872 894
873 case DEC_CPYOFF: 895 case DEC_CPYOFF:
@@ -881,7 +903,8 @@ xd3_decode_input (xd3_stream *stream)
881 return XD3_INVALID_INPUT; 903 return XD3_INVALID_INPUT;
882 } 904 }
883 905
884 /* Check copy window bounds: VCD_TARGET window may not exceed current position. */ 906 /* Check copy window bounds: VCD_TARGET window may not exceed
907 current position. */
885 if ((stream->dec_win_ind & VCD_TARGET) && 908 if ((stream->dec_win_ind & VCD_TARGET) &&
886 (stream->dec_cpyoff + (xoff_t) stream->dec_cpylen > stream->dec_winstart)) 909 (stream->dec_cpyoff + (xoff_t) stream->dec_cpylen > stream->dec_winstart))
887 { 910 {
@@ -896,9 +919,9 @@ xd3_decode_input (xd3_stream *stream)
896 /* Length of target window */ 919 /* Length of target window */
897 SIZE_CASE(1, stream->dec_tgtlen, DEC_DELIND); 920 SIZE_CASE(1, stream->dec_tgtlen, DEC_DELIND);
898 921
899 /* Set the maximum decoder position, beyond which we should not decode any data. 922 /* Set the maximum decoder position, beyond which we should not
900 * This is the maximum value for dec_position. This may not exceed the size of a 923 * decode any data. This is the maximum value for dec_position.
901 * usize_t. */ 924 * This may not exceed the size of a usize_t. */
902 if (USIZE_T_OVERFLOW (stream->dec_cpylen, stream->dec_tgtlen)) 925 if (USIZE_T_OVERFLOW (stream->dec_cpylen, stream->dec_tgtlen))
903 { 926 {
904 stream->msg = "decoder target window overflows a usize_t"; 927 stream->msg = "decoder target window overflows a usize_t";
@@ -973,8 +996,8 @@ xd3_decode_input (xd3_stream *stream)
973 } 996 }
974 } 997 }
975 998
976 /* Returning here gives the application a chance to inspect the header, skip the 999 /* Returning here gives the application a chance to inspect the
977 * window, etc. */ 1000 * header, skip the window, etc. */
978 if (stream->current_window == 0) { return XD3_GOTHEADER; } 1001 if (stream->current_window == 0) { return XD3_GOTHEADER; }
979 else { return XD3_WINSTART; } 1002 else { return XD3_WINSTART; }
980 1003
@@ -986,8 +1009,8 @@ xd3_decode_input (xd3_stream *stream)
986 1009
987 case DEC_EMIT: 1010 case DEC_EMIT:
988 1011
989 /* To speed VCD_SOURCE block-address calculations, the source cpyoff_blocks and 1012 /* To speed VCD_SOURCE block-address calculations, the source
990 * cpyoff_blkoff are pre-computed. */ 1013 * cpyoff_blocks and cpyoff_blkoff are pre-computed. */
991 if (stream->dec_win_ind & VCD_SOURCE) 1014 if (stream->dec_win_ind & VCD_SOURCE)
992 { 1015 {
993 xd3_source *src = stream->src; 1016 xd3_source *src = stream->src;
@@ -1030,8 +1053,8 @@ xd3_decode_input (xd3_stream *stream)
1030 stream->dec_laststart = stream->dec_winstart; 1053 stream->dec_laststart = stream->dec_winstart;
1031 stream->dec_window_count += 1; 1054 stream->dec_window_count += 1;
1032 1055
1033 /* Note: the updates to dec_winstart & current_window are deferred until after the 1056 /* Note: the updates to dec_winstart & current_window are
1034 * next DEC_WININD byte is read. */ 1057 * deferred until after the next DEC_WININD byte is read. */
1035 stream->dec_state = DEC_WININD; 1058 stream->dec_state = DEC_WININD;
1036 return XD3_WINFINISH; 1059 return XD3_WINFINISH;
1037 } 1060 }