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

Last change on this file since 185 was 185, checked in by geyser, 14 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.