Planeshift

xdelta3-decode.h

Go to the documentation of this file.
00001 /* xdelta 3 - delta compression tools and library
00002  * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007.  Joshua P. MacDonald
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 #ifndef _XDELTA3_DECODE_H_
00020 #define _XDELTA3_DECODE_H_
00021 
00022 #define SRCORTGT(x) ((((x) & VCD_SRCORTGT) == VCD_SOURCE) ? \
00023                      VCD_SOURCE : ((((x) & VCD_SRCORTGT) == \
00024                                     VCD_TARGET) ? VCD_TARGET : 0))
00025 
00026 /* Initialize the decoder for a new window.  The dec_tgtlen value is
00027  * preserved across successive window decodings, and the update to
00028  * dec_winstart is delayed until a new window actually starts.  This
00029  * is to avoid throwing an error due to overflow until the last
00030  * possible moment.  This makes it possible to encode exactly 4GB
00031  * through a 32-bit encoder. */
00032 static int
00033 xd3_decode_init_window (xd3_stream *stream)
00034 {
00035   stream->dec_cpylen = 0;
00036   stream->dec_cpyoff = 0;
00037   stream->dec_cksumbytes = 0;
00038 
00039   xd3_init_cache (& stream->acache);
00040 
00041   return 0;
00042 }
00043 
00044 /* Allocates buffer space for the target window and possibly the
00045  * VCD_TARGET copy-window.  Also sets the base of the two copy
00046  * segments. */
00047 static int
00048 xd3_decode_setup_buffers (xd3_stream *stream)
00049 {
00050   /* If VCD_TARGET is set then the previous buffer may be reused. */
00051   if (stream->dec_win_ind & VCD_TARGET)
00052     {
00053       /* But this implementation only supports copying from the last
00054        * target window.  If the offset is outside that range, it can't
00055        * be done. */
00056       if (stream->dec_cpyoff < stream->dec_laststart)
00057         {
00058           stream->msg = "unsupported VCD_TARGET offset";
00059           return XD3_INVALID_INPUT;
00060         }
00061 
00062       /* See if the two windows are the same.  This indicates the
00063        * first time VCD_TARGET is used.  This causes a second buffer
00064        * to be allocated, after that the two are swapped in the
00065        * DEC_FINISH case. */
00066       if (stream->dec_lastwin == stream->next_out)
00067         {
00068           stream->next_out  = NULL;
00069           stream->space_out = 0;
00070         }
00071 
00072       // TODO: VCD_TARGET mode, this is broken
00073       stream->dec_cpyaddrbase = stream->dec_lastwin +
00074         (usize_t) (stream->dec_cpyoff - stream->dec_laststart);
00075     }
00076 
00077   /* See if the current output window is large enough. */
00078   if (stream->space_out < stream->dec_tgtlen)
00079     {
00080       xd3_free (stream, stream->dec_buffer);
00081 
00082       stream->space_out =
00083         xd3_round_blksize (stream->dec_tgtlen, XD3_ALLOCSIZE);
00084 
00085       if ((stream->dec_buffer =
00086            (uint8_t*) xd3_alloc (stream, stream->space_out, 1)) == NULL)
00087         {
00088           return ENOMEM;
00089         }
00090 
00091       stream->next_out = stream->dec_buffer;
00092     }
00093 
00094   /* dec_tgtaddrbase refers to an invalid base address, but it is
00095    * always used with a sufficiently large instruction offset (i.e.,
00096    * beyond the copy window).  This condition is enforced by
00097    * xd3_decode_output_halfinst. */
00098   stream->dec_tgtaddrbase = stream->next_out - stream->dec_cpylen;
00099 
00100   return 0;
00101 }
00102 
00103 static int
00104 xd3_decode_allocate (xd3_stream  *stream,
00105                      usize_t       size,
00106                      uint8_t    **buf_ptr,
00107                      usize_t      *buf_alloc)
00108 {
00109   if (*buf_ptr != NULL && *buf_alloc < size)
00110     {
00111       xd3_free (stream, *buf_ptr);
00112       *buf_ptr = NULL;
00113     }
00114 
00115   if (*buf_ptr == NULL)
00116     {
00117       *buf_alloc = xd3_round_blksize (size, XD3_ALLOCSIZE);
00118 
00119       if ((*buf_ptr = (uint8_t*) xd3_alloc (stream, *buf_alloc, 1)) == NULL)
00120         {
00121           return ENOMEM;
00122         }
00123     }
00124 
00125   return 0;
00126 }
00127 
00128 static int
00129 xd3_decode_section (xd3_stream *stream,
00130                     xd3_desect *section,
00131                     xd3_decode_state nstate,
00132                     int copy)
00133 {
00134   XD3_ASSERT (section->pos <= section->size);
00135   XD3_ASSERT (stream->dec_state != nstate);
00136 
00137   if (section->pos < section->size)
00138     {
00139       usize_t sect_take;
00140 
00141       if (stream->avail_in == 0)
00142         {
00143           return XD3_INPUT;
00144         }
00145 
00146       if ((copy == 0) && (section->pos == 0))
00147         {
00148           /* No allocation/copy needed */
00149           section->buf = stream->next_in;
00150           sect_take    = section->size;
00151         }
00152       else
00153         {
00154           usize_t sect_need = section->size - section->pos;
00155 
00156           /* Allocate and copy */
00157           sect_take = min (sect_need, stream->avail_in);
00158 
00159           if (section->pos == 0)
00160             {
00161               int ret;
00162 
00163               if ((ret = xd3_decode_allocate (stream,
00164                                               section->size,
00165                                               & section->copied1,
00166                                               & section->alloc1)))
00167                 {
00168                   return ret;
00169                 }
00170 
00171               section->buf = section->copied1;
00172             }
00173 
00174           memcpy (section->copied1 + section->pos,
00175                   stream->next_in,
00176                   sect_take);
00177         }
00178 
00179       section->pos += sect_take;
00180 
00181       stream->dec_winbytes += sect_take;
00182 
00183       DECODE_INPUT (sect_take);
00184     }
00185 
00186   if (section->pos < section->size)
00187     {
00188       stream->msg = "further input required";
00189       return XD3_INPUT;
00190     }
00191 
00192   XD3_ASSERT (section->pos == section->size);
00193 
00194   stream->dec_state = nstate;
00195   section->buf_max  = section->buf + section->size;
00196   section->pos      = 0;
00197   return 0;
00198 }
00199 
00200 /* Decode the size and address for half of an instruction (i.e., a
00201  * single opcode).  This updates the stream->dec_position, which are
00202  * bytes already output prior to processing this instruction.  Perform
00203  * bounds checking for sizes and copy addresses, which uses the
00204  * dec_position (which is why these checks are done here). */
00205 static int
00206 xd3_decode_parse_halfinst (xd3_stream *stream, xd3_hinst *inst)
00207 {
00208   int ret;
00209 
00210   /* If the size from the instruction table is zero then read a size value. */
00211   if ((inst->size == 0) &&
00212       (ret = xd3_read_size (stream,
00213                             & stream->inst_sect.buf,
00214                               stream->inst_sect.buf_max,
00215                             & inst->size)))
00216     {
00217       return XD3_INVALID_INPUT;
00218     }
00219 
00220   /* For copy instructions, read address. */
00221   if (inst->type >= XD3_CPY)
00222     {
00223       IF_DEBUG2 ({
00224         static int cnt = 0;
00225         DP(RINT "DECODE:%u: COPY at %"Q"u (winoffset %u) size %u winaddr %u\n",
00226                  cnt++,
00227                  stream->total_out + (stream->dec_position -
00228                                       stream->dec_cpylen),
00229                  (stream->dec_position - stream->dec_cpylen),
00230                  inst->size,
00231                  inst->addr);
00232       });
00233 
00234       if ((ret = xd3_decode_address (stream,
00235                                      stream->dec_position,
00236                                      inst->type - XD3_CPY,
00237                                      & stream->addr_sect.buf,
00238                                      stream->addr_sect.buf_max,
00239                                      & inst->addr)))
00240         {
00241           return ret;
00242         }
00243 
00244       /* Cannot copy an address before it is filled-in. */
00245       if (inst->addr >= stream->dec_position)
00246         {
00247           stream->msg = "address too large";
00248           return XD3_INVALID_INPUT;
00249         }
00250 
00251       /* Check: a VCD_TARGET or VCD_SOURCE copy cannot exceed the remaining
00252        * buffer space in its own segment. */
00253       if (inst->addr < stream->dec_cpylen &&
00254           inst->addr + inst->size > stream->dec_cpylen)
00255         {
00256           stream->msg = "size too large";
00257           return XD3_INVALID_INPUT;
00258         }
00259     }
00260   else
00261     {
00262       IF_DEBUG2 ({
00263         if (inst->type == XD3_ADD)
00264           {
00265             static int cnt;
00266             DP(RINT "DECODE:%d: ADD at %"Q"u (winoffset %u) size %u\n",
00267                cnt++,
00268                (stream->total_out + stream->dec_position - stream->dec_cpylen),
00269                stream->dec_position - stream->dec_cpylen,
00270                inst->size);
00271           }
00272         else
00273           {
00274             static int cnt;
00275             XD3_ASSERT (inst->type == XD3_RUN);
00276             DP(RINT "DECODE:%d: RUN at %"Q"u (winoffset %u) size %u\n",
00277                cnt++,
00278                stream->total_out + stream->dec_position - stream->dec_cpylen,
00279                stream->dec_position - stream->dec_cpylen,
00280                inst->size);
00281           }
00282       });
00283     }
00284 
00285   /* Check: The instruction will not overflow the output buffer. */
00286   if (stream->dec_position + inst->size > stream->dec_maxpos)
00287     {
00288       stream->msg = "size too large";
00289       return XD3_INVALID_INPUT;
00290     }
00291 
00292   stream->dec_position += inst->size;
00293   return 0;
00294 }
00295 
00296 /* Decode a single opcode and then decode the two half-instructions. */
00297 static int
00298 xd3_decode_instruction (xd3_stream *stream)
00299 {
00300   int ret;
00301   const xd3_dinst *inst;
00302 
00303   if (stream->inst_sect.buf == stream->inst_sect.buf_max)
00304     {
00305       stream->msg = "instruction underflow";
00306       return XD3_INVALID_INPUT;
00307     }
00308 
00309   inst = &stream->code_table[*stream->inst_sect.buf++];
00310 
00311   stream->dec_current1.type = inst->type1;
00312   stream->dec_current2.type = inst->type2;
00313   stream->dec_current1.size = inst->size1;
00314   stream->dec_current2.size = inst->size2;
00315 
00316   /* For each instruction with a real operation, decode the
00317    * corresponding size and addresses if necessary.  Assume a
00318    * code-table may have NOOP in either position, although this is
00319    * unlikely. */
00320   if (inst->type1 != XD3_NOOP &&
00321       (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current1)))
00322     {
00323       return ret;
00324     }
00325   if (inst->type2 != XD3_NOOP &&
00326       (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current2)))
00327     {
00328       return ret;
00329     }
00330   return 0;
00331 }
00332 
00333 /* Output the result of a single half-instruction. OPT: This the
00334    decoder hotspot.  Modifies "hinst", see below.  */
00335 static int
00336 xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst)
00337 {
00338   /* This method is reentrant for copy instructions which may return
00339    * XD3_GETSRCBLK to the caller.  Each time through a copy takes the
00340    * minimum of inst->size and the available space on whichever block
00341    * supplies the data */
00342   usize_t take = inst->size;
00343 
00344   XD3_ASSERT (inst->type != XD3_NOOP);
00345 
00346   switch (inst->type)
00347     {
00348     case XD3_RUN:
00349       {
00350         /* Only require a single data byte. */
00351         if (stream->data_sect.buf == stream->data_sect.buf_max)
00352           {
00353             stream->msg = "data underflow";
00354             return XD3_INVALID_INPUT;
00355           }
00356 
00357         memset (stream->next_out + stream->avail_out,
00358                 stream->data_sect.buf[0],
00359                 take);
00360 
00361         stream->data_sect.buf += 1;
00362         stream->avail_out += take;
00363         inst->type = XD3_NOOP;
00364         break;
00365       }
00366     case XD3_ADD:
00367       {
00368         /* Require at least TAKE data bytes. */
00369         if (stream->data_sect.buf + take > stream->data_sect.buf_max)
00370           {
00371             stream->msg = "data underflow";
00372             return XD3_INVALID_INPUT;
00373           }
00374 
00375         memcpy (stream->next_out + stream->avail_out,
00376                 stream->data_sect.buf,
00377                 take);
00378 
00379         stream->data_sect.buf += take;
00380         stream->avail_out += take;
00381         inst->type = XD3_NOOP;
00382         break;
00383       }
00384     default:
00385       {
00386         usize_t i;
00387         const uint8_t *src;
00388         uint8_t *dst;
00389         int overlap;
00390 
00391         /* See if it copies from the VCD_TARGET/VCD_SOURCE window or
00392          * the target window.  Out-of-bounds checks for the addresses
00393          * and sizes are performed in xd3_decode_parse_halfinst.  This
00394          * if/else must set "overlap", "src", and "dst". */
00395         if (inst->addr < stream->dec_cpylen)
00396           {
00397             /* In both branches we are copying from outside the
00398              * current decoder window, the first (VCD_TARGET) is
00399              * unimplemented. */
00400             overlap = 0;
00401             
00402             /* This branch sets "src".  As a side-effect, we modify
00403              * "inst" so that if we reenter this method after a
00404              * XD3_GETSRCBLK response the state is correct.  So if the
00405              * instruction can be fulfilled by a contiguous block of
00406              * memory then we will set:
00407              *
00408              *  inst->type = XD3_NOOP;
00409              *  inst->size = 0;
00410              */
00411             if (stream->dec_win_ind & VCD_TARGET)
00412               {
00413                 /* TODO: Users have requested long-distance copies of
00414                  * similar material within a target (e.g., for dup
00415                  * supression in backups). */
00416                 inst->size = 0;
00417                 inst->type = XD3_NOOP;
00418                 stream->msg = "VCD_TARGET not implemented";
00419                 return XD3_UNIMPLEMENTED;
00420               }
00421             else
00422               {
00423                 /* In this case we have to read a source block, which
00424                  * could return control to the caller.  We need to
00425                  * know the first block number needed for this
00426                  * copy. */
00427                 xd3_source *source = stream->src;
00428                 xoff_t block = source->cpyoff_blocks;
00429                 usize_t blkoff = source->cpyoff_blkoff;
00430                 const usize_t blksize = source->blksize;
00431                 int ret;
00432 
00433                 xd3_blksize_add (&block, &blkoff, source, inst->addr);
00434                 XD3_ASSERT (blkoff < blksize);
00435 
00436                 if ((ret = xd3_getblk (stream, block)))
00437                   {
00438                     /* could be a XD3_GETSRCBLK failure. */
00439                     if (ret == XD3_TOOFARBACK)
00440                       {
00441                         stream->msg = "non-seekable source in decode";
00442                         ret = XD3_INTERNAL;
00443                       }
00444                     return ret;
00445                   }
00446 
00447                 src = source->curblk + blkoff;
00448 
00449                 /* This block is either full, or a partial block that
00450                  * must contain enough bytes. */
00451                 if ((source->onblk != blksize) &&
00452                     (blkoff + take > source->onblk))
00453                   {
00454                     IF_DEBUG1(DP(RINT "[srcfile] short at blkno %"Q"u onblk "
00455                                  "%u blksize %u blkoff %u take %u\n",
00456                                  block,
00457                                  source->onblk,
00458                                  blksize,
00459                                  blkoff,
00460                                  take));
00461                     stream->msg = "source file too short";
00462                     return XD3_INVALID_INPUT;
00463                   }
00464 
00465                 XD3_ASSERT (blkoff != blksize);
00466 
00467                 /* Check if we have enough data on this block to
00468                  * finish the instruction. */
00469                 if (blkoff + take <= blksize)
00470                   {
00471                     inst->type = XD3_NOOP;
00472                     inst->size = 0;
00473                   }
00474                 else
00475                   {
00476                     take = blksize - blkoff;
00477                     inst->size -= take;
00478                     inst->addr += take;
00479 
00480                     /* because (blkoff + take > blksize), above */
00481                     XD3_ASSERT (inst->size != 0);
00482                   }
00483               }
00484           }
00485         else
00486           {
00487             /* TODO: the memcpy/overlap optimization, etc.  Overlap
00488              * here could be more specific, it's whether (inst->addr -
00489              * srclen) + inst->size > input_pos ?  And is the system
00490              * memcpy really any good? */
00491             overlap = 1;
00492 
00493             /* For a target-window copy, we know the entire range is
00494              * in-memory.  The dec_tgtaddrbase is negatively offset by
00495              * dec_cpylen because the addresses start beyond that
00496              * point. */
00497             src = stream->dec_tgtaddrbase + inst->addr;
00498             inst->type = XD3_NOOP;
00499             inst->size = 0;
00500           }
00501 
00502         dst = stream->next_out + stream->avail_out;
00503 
00504         stream->avail_out += take;
00505 
00506         if (overlap)
00507           {
00508             /* Can't just memcpy here due to possible overlap. */
00509             for (i = take; i != 0; i -= 1)
00510               {
00511                 *dst++ = *src++;
00512               }
00513           }
00514         else
00515           {
00516             memcpy (dst, src, take);
00517           }
00518       }
00519     }
00520 
00521   return 0;
00522 }
00523 
00524 static int
00525 xd3_decode_finish_window (xd3_stream *stream)
00526 {
00527   stream->dec_winbytes  = 0;
00528   stream->dec_state     = DEC_FINISH;
00529 
00530   stream->data_sect.pos = 0;
00531   stream->inst_sect.pos = 0;
00532   stream->addr_sect.pos = 0;
00533 
00534   return XD3_OUTPUT;
00535 }
00536 
00537 static int
00538 xd3_decode_secondary_sections (xd3_stream *secondary_stream)
00539 {
00540 #if SECONDARY_ANY
00541   int ret;
00542 #define DECODE_SECONDARY_SECTION(UPPER,LOWER) \
00543   ((secondary_stream->dec_del_ind & VCD_ ## UPPER ## COMP) && \
00544    (ret = xd3_decode_secondary (secondary_stream, \
00545                                 & secondary_stream-> LOWER ## _sect,    \
00546                                 & xd3_sec_ ## LOWER (secondary_stream))))
00547 
00548   if (DECODE_SECONDARY_SECTION (DATA, data) ||
00549       DECODE_SECONDARY_SECTION (INST, inst) ||
00550       DECODE_SECONDARY_SECTION (ADDR, addr))
00551     {
00552       return ret;
00553     }
00554 #undef DECODE_SECONDARY_SECTION
00555 #endif
00556   return 0;
00557 }
00558 
00559 static int
00560 xd3_decode_sections (xd3_stream *stream)
00561 {
00562   usize_t need, more, take;
00563   int copy, ret;
00564 
00565   if ((stream->flags & XD3_JUST_HDR) != 0)
00566     {
00567       /* Nothing left to do. */
00568       return xd3_decode_finish_window (stream);
00569     }
00570 
00571   /* To avoid copying, need this much data available */
00572   need = (stream->inst_sect.size +
00573           stream->addr_sect.size +
00574           stream->data_sect.size);
00575 
00576   /* The window may be entirely processed. */
00577   XD3_ASSERT (stream->dec_winbytes <= need);
00578 
00579   /* Compute how much more input is needed. */
00580   more = (need - stream->dec_winbytes);
00581 
00582   /* How much to consume. */
00583   take = min (more, stream->avail_in);
00584 
00585   /* See if the input is completely available, to avoid copy. */
00586   copy = (take != more);
00587 
00588   /* If the window is skipped... */
00589   if ((stream->flags & XD3_SKIP_WINDOW) != 0)
00590     {
00591       /* Skip the available input. */
00592       DECODE_INPUT (take);
00593 
00594       stream->dec_winbytes += take;
00595 
00596       if (copy)
00597         {
00598           stream->msg = "further input required";
00599           return XD3_INPUT;
00600         }
00601 
00602       return xd3_decode_finish_window (stream);
00603     }
00604 
00605   /* Process all but the DATA section. */
00606   switch (stream->dec_state)
00607     {
00608     default:
00609       stream->msg = "internal error";
00610       return XD3_INVALID_INPUT;
00611 
00612     case DEC_DATA:
00613       if ((ret = xd3_decode_section (stream, & stream->data_sect,
00614                                      DEC_INST, copy))) { return ret; }
00615     case DEC_INST:
00616       if ((ret = xd3_decode_section (stream, & stream->inst_sect,
00617                                      DEC_ADDR, copy))) { return ret; }
00618     case DEC_ADDR:
00619       if ((ret = xd3_decode_section (stream, & stream->addr_sect,
00620                                      DEC_EMIT, copy))) { return ret; }
00621     }
00622 
00623   XD3_ASSERT (stream->dec_winbytes == need);
00624 
00625   if ((ret = xd3_decode_secondary_sections (stream))) { return ret; }
00626 
00627   if (stream->flags & XD3_SKIP_EMIT)
00628     {
00629       return xd3_decode_finish_window (stream);
00630     }
00631 
00632   /* OPT: A possible optimization is to avoid allocating memory in
00633    * decode_setup_buffers and to avoid a large memcpy when the window
00634    * consists of a single VCD_SOURCE copy instruction. */
00635   if ((ret = xd3_decode_setup_buffers (stream))) { return ret; }
00636 
00637   return 0;
00638 }
00639 
00640 static int
00641 xd3_decode_emit (xd3_stream *stream)
00642 {
00643   int ret;
00644 
00645   /* Produce output: originally structured to allow reentrant code
00646    * that fills as much of the output buffer as possible, but VCDIFF
00647    * semantics allows to copy from anywhere from the target window, so
00648    * instead allocate a sufficiently sized buffer after the target
00649    * window length is decoded.
00650    *
00651    * This code still needs to be reentrant to allow XD3_GETSRCBLK to
00652    * return control.  This is handled by setting the
00653    * stream->dec_currentN instruction types to XD3_NOOP after they
00654    * have been processed. */
00655   XD3_ASSERT (! (stream->flags & XD3_SKIP_EMIT));
00656   XD3_ASSERT (stream->dec_tgtlen <= stream->space_out);
00657 
00658   while (stream->inst_sect.buf != stream->inst_sect.buf_max ||
00659          stream->dec_current1.type != XD3_NOOP ||
00660          stream->dec_current2.type != XD3_NOOP)
00661     {
00662       /* Decode next instruction pair. */
00663       if ((stream->dec_current1.type == XD3_NOOP) &&
00664           (stream->dec_current2.type == XD3_NOOP) &&
00665           (ret = xd3_decode_instruction (stream))) { return ret; }
00666 
00667       /* Output dec_current1 */
00668       while ((stream->dec_current1.type != XD3_NOOP))
00669         {
00670           if ((ret = xd3_decode_output_halfinst (stream, & stream->dec_current1)))
00671             {
00672               return ret;
00673             }
00674         }
00675       /* Output dec_current2 */
00676       while (stream->dec_current2.type != XD3_NOOP)
00677         {
00678           if ((ret = xd3_decode_output_halfinst (stream, & stream->dec_current2)))
00679             {
00680               return ret;
00681             }
00682         }
00683     }
00684 
00685   if (stream->avail_out != stream->dec_tgtlen)
00686     {
00687       IF_DEBUG2 (DP(RINT "AVAIL_OUT(%d) != DEC_TGTLEN(%d)\n",
00688                     stream->avail_out, stream->dec_tgtlen));
00689       stream->msg = "wrong window length";
00690       return XD3_INVALID_INPUT;
00691     }
00692 
00693   if (stream->data_sect.buf != stream->data_sect.buf_max)
00694     {
00695       stream->msg = "extra data section";
00696       return XD3_INVALID_INPUT;
00697     }
00698 
00699   if (stream->addr_sect.buf != stream->addr_sect.buf_max)
00700     {
00701       stream->msg = "extra address section";
00702       return XD3_INVALID_INPUT;
00703     }
00704 
00705   /* OPT: Should cksum computation be combined with the above loop? */
00706   if ((stream->dec_win_ind & VCD_ADLER32) != 0 &&
00707       (stream->flags & XD3_ADLER32_NOVER) == 0)
00708     {
00709       uint32_t a32 = adler32 (1L, stream->next_out, stream->avail_out);
00710 
00711       if (a32 != stream->dec_adler32)
00712         {
00713           stream->msg = "target window checksum mismatch";
00714           return XD3_INVALID_INPUT;
00715         }
00716     }
00717 
00718   /* Finished with a window. */
00719   return xd3_decode_finish_window (stream);
00720 }
00721 
00722 int
00723 xd3_decode_input (xd3_stream *stream)
00724 {
00725   int ret;
00726 
00727   if (stream->enc_state != 0)
00728     {
00729       stream->msg = "encoder/decoder transition";
00730       return XD3_INVALID_INPUT;
00731     }
00732 
00733 #define BYTE_CASE(expr,x,nstate) \
00734       do { \
00735       if ( (expr) && \
00736            ((ret = xd3_decode_byte (stream, & (x))) != 0) ) { return ret; } \
00737       stream->dec_state = (nstate); \
00738       } while (0)
00739 
00740 #define OFFSET_CASE(expr,x,nstate) \
00741       do { \
00742       if ( (expr) && \
00743            ((ret = xd3_decode_offset (stream, & (x))) != 0) ) { return ret; } \
00744       stream->dec_state = (nstate); \
00745       } while (0)
00746 
00747 #define SIZE_CASE(expr,x,nstate) \
00748       do { \
00749       if ( (expr) && \
00750            ((ret = xd3_decode_size (stream, & (x))) != 0) ) { return ret; } \
00751       stream->dec_state = (nstate); \
00752       } while (0)
00753 
00754   switch (stream->dec_state)
00755     {
00756     case DEC_VCHEAD:
00757       {
00758         if ((ret = xd3_decode_bytes (stream, stream->dec_magic,
00759                                      & stream->dec_magicbytes, 4)))
00760           {
00761             return ret;
00762           }
00763 
00764         if (stream->dec_magic[0] != VCDIFF_MAGIC1 ||
00765             stream->dec_magic[1] != VCDIFF_MAGIC2 ||
00766             stream->dec_magic[2] != VCDIFF_MAGIC3)
00767           {
00768             stream->msg = "not a VCDIFF input";
00769             return XD3_INVALID_INPUT;
00770           }
00771 
00772         if (stream->dec_magic[3] != 0)
00773           {
00774             stream->msg = "VCDIFF input version > 0 is not supported";
00775             return XD3_INVALID_INPUT;
00776           }
00777 
00778         stream->dec_state = DEC_HDRIND;
00779       }
00780     case DEC_HDRIND:
00781       {
00782         if ((ret = xd3_decode_byte (stream, & stream->dec_hdr_ind)))
00783           {
00784             return ret;
00785           }
00786 
00787         if ((stream->dec_hdr_ind & VCD_INVHDR) != 0)
00788           {
00789             stream->msg = "unrecognized header indicator bits set";
00790             return XD3_INVALID_INPUT;
00791           }
00792 
00793         stream->dec_state = DEC_SECONDID;
00794       }
00795 
00796     case DEC_SECONDID:
00797       /* Secondary compressor ID: only if VCD_SECONDARY is set */
00798       if ((stream->dec_hdr_ind & VCD_SECONDARY) != 0)
00799         {
00800           BYTE_CASE (1, stream->dec_secondid, DEC_TABLEN);
00801 
00802           switch (stream->dec_secondid)
00803             {
00804             case VCD_FGK_ID:
00805               FGK_CASE (stream);
00806             case VCD_DJW_ID:
00807               DJW_CASE (stream);
00808             default:
00809               stream->msg = "unknown secondary compressor ID";
00810               return XD3_INVALID_INPUT;
00811             }
00812         }
00813 
00814     case DEC_TABLEN:
00815       /* Length of code table data: only if VCD_CODETABLE is set */
00816       SIZE_CASE ((stream->dec_hdr_ind & VCD_CODETABLE) != 0,
00817                  stream->dec_codetblsz, DEC_NEAR);
00818 
00819       /* The codetblsz counts the two NEAR/SAME bytes */
00820       if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0) {
00821         if (stream->dec_codetblsz <= 2) {
00822           stream->msg = "invalid code table size";
00823           return ENOMEM;
00824         }
00825         stream->dec_codetblsz -= 2;
00826       }
00827     case DEC_NEAR:
00828       /* Near modes: only if VCD_CODETABLE is set */
00829       BYTE_CASE((stream->dec_hdr_ind & VCD_CODETABLE) != 0,
00830                 stream->acache.s_near, DEC_SAME);
00831     case DEC_SAME:
00832       /* Same modes: only if VCD_CODETABLE is set */
00833       BYTE_CASE((stream->dec_hdr_ind & VCD_CODETABLE) != 0,
00834                 stream->acache.s_same, DEC_TABDAT);
00835     case DEC_TABDAT:
00836       /* Compressed code table data */
00837 
00838       if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0)
00839         {
00840           /* Get the code table data. */
00841           if ((stream->dec_codetbl == NULL) &&
00842               (stream->dec_codetbl =
00843                (uint8_t*) xd3_alloc (stream,
00844                                      stream->dec_codetblsz, 1)) == NULL)
00845             {
00846               return ENOMEM;
00847             }
00848 
00849           if ((ret = xd3_decode_bytes (stream, stream->dec_codetbl,
00850                                        & stream->dec_codetblbytes,
00851                                        stream->dec_codetblsz)))
00852             {
00853               return ret;
00854             }
00855 
00856           if ((ret = xd3_apply_table_encoding (stream, stream->dec_codetbl,
00857                                                stream->dec_codetblbytes)))
00858             {
00859               return ret;
00860             }
00861         }
00862       else
00863         {
00864           /* Use the default table. */
00865           stream->acache.s_near = __rfc3284_code_table_desc.near_modes;
00866           stream->acache.s_same = __rfc3284_code_table_desc.same_modes;
00867           stream->code_table    = xd3_rfc3284_code_table ();
00868         }
00869 
00870       if ((ret = xd3_alloc_cache (stream))) { return ret; }
00871 
00872       stream->dec_state = DEC_APPLEN;
00873 
00874     case DEC_APPLEN:
00875       /* Length of application data */
00876       SIZE_CASE((stream->dec_hdr_ind & VCD_APPHEADER) != 0,
00877                 stream->dec_appheadsz, DEC_APPDAT);
00878 
00879     case DEC_APPDAT:
00880       /* Application data */
00881       if (stream->dec_hdr_ind & VCD_APPHEADER)
00882         {
00883           /* Note: we add an additional byte for padding, to allow
00884              0-termination. */
00885           if ((stream->dec_appheader == NULL) &&
00886               (stream->dec_appheader =
00887                (uint8_t*) xd3_alloc (stream,
00888                                      stream->dec_appheadsz+1, 1)) == NULL)
00889             {
00890               return ENOMEM;
00891             }
00892 
00893           stream->dec_appheader[stream->dec_appheadsz] = 0;
00894 
00895           if ((ret = xd3_decode_bytes (stream, stream->dec_appheader,
00896                                        & stream->dec_appheadbytes,
00897                                        stream->dec_appheadsz)))
00898             {
00899               return ret;
00900             }
00901         }
00902 
00903       /* xoff_t -> usize_t is safe because this is the first block. */
00904       stream->dec_hdrsize = (usize_t) stream->total_in;
00905       stream->dec_state = DEC_WININD;
00906 
00907     case DEC_WININD:
00908       {
00909         /* Start of a window: the window indicator */
00910         if ((ret = xd3_decode_byte (stream, & stream->dec_win_ind)))
00911           {
00912             return ret;
00913           }
00914 
00915         stream->current_window = stream->dec_window_count;
00916 
00917         if (XOFF_T_OVERFLOW (stream->dec_winstart, stream->dec_tgtlen))
00918           {
00919             stream->msg = "decoder file offset overflow";
00920             return XD3_INVALID_INPUT;
00921           }
00922 
00923         stream->dec_winstart += stream->dec_tgtlen;
00924 
00925         if ((stream->dec_win_ind & VCD_INVWIN) != 0)
00926           {
00927             stream->msg = "unrecognized window indicator bits set";
00928             return XD3_INVALID_INPUT;
00929           }
00930 
00931         if ((ret = xd3_decode_init_window (stream))) { return ret; }
00932 
00933         stream->dec_state = DEC_CPYLEN;
00934 
00935         IF_DEBUG2 (DP(RINT "--------- TARGET WINDOW %"Q"u -----------\n",
00936                       stream->current_window));
00937       }
00938 
00939     case DEC_CPYLEN:
00940       /* Copy window length: only if VCD_SOURCE or VCD_TARGET is set */
00941       SIZE_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpylen,
00942                 DEC_CPYOFF);
00943 
00944       /* Set the initial, logical decoder position (HERE address) in
00945        * dec_position.  This is set to just after the source/copy
00946        * window, as we are just about to output the first byte of
00947        * target window. */
00948       stream->dec_position = stream->dec_cpylen;
00949 
00950     case DEC_CPYOFF:
00951       /* Copy window offset: only if VCD_SOURCE or VCD_TARGET is set */
00952       OFFSET_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpyoff,
00953                   DEC_ENCLEN);
00954 
00955       /* Copy offset and copy length may not overflow. */
00956       if (XOFF_T_OVERFLOW (stream->dec_cpyoff, stream->dec_cpylen))
00957         {
00958           stream->msg = "decoder copy window overflows a file offset";
00959           return XD3_INVALID_INPUT;
00960         }
00961 
00962       /* Check copy window bounds: VCD_TARGET window may not exceed
00963          current position. */
00964       if ((stream->dec_win_ind & VCD_TARGET) &&
00965           (stream->dec_cpyoff + (xoff_t) stream->dec_cpylen >
00966            stream->dec_winstart))
00967         {
00968           stream->msg = "VCD_TARGET window out of bounds";
00969           return XD3_INVALID_INPUT;
00970         }
00971 
00972     case DEC_ENCLEN:
00973       /* Length of the delta encoding */
00974       SIZE_CASE(1, stream->dec_enclen, DEC_TGTLEN);
00975     case DEC_TGTLEN:
00976       /* Length of target window */
00977       SIZE_CASE(1, stream->dec_tgtlen, DEC_DELIND);
00978 
00979       /* Set the maximum decoder position, beyond which we should not
00980        * decode any data.  This is the maximum value for dec_position.
00981        * This may not exceed the size of a usize_t. */
00982       if (USIZE_T_OVERFLOW (stream->dec_cpylen, stream->dec_tgtlen))
00983         {
00984           stream->msg = "decoder target window overflows a usize_t";
00985           return XD3_INVALID_INPUT;
00986         }
00987 
00988       /* Check for malicious files. */
00989       if (stream->dec_tgtlen > XD3_HARDMAXWINSIZE)
00990         {
00991           stream->msg = "hard window size exceeded";
00992           return XD3_INVALID_INPUT;
00993         }
00994 
00995       stream->dec_maxpos = stream->dec_cpylen + stream->dec_tgtlen;
00996 
00997     case DEC_DELIND:
00998       /* Delta indicator */
00999       BYTE_CASE(1, stream->dec_del_ind, DEC_DATALEN);
01000 
01001       if ((stream->dec_del_ind & VCD_INVDEL) != 0)
01002         {
01003           stream->msg = "unrecognized delta indicator bits set";
01004           return XD3_INVALID_INPUT;
01005         }
01006 
01007       /* Delta indicator is only used with secondary compression. */
01008       if ((stream->dec_del_ind != 0) && (stream->sec_type == NULL))
01009         {
01010           stream->msg = "invalid delta indicator bits set";
01011           return XD3_INVALID_INPUT;
01012         }
01013 
01014       /* Section lengths */
01015     case DEC_DATALEN:
01016       SIZE_CASE(1, stream->data_sect.size, DEC_INSTLEN);
01017     case DEC_INSTLEN:
01018       SIZE_CASE(1, stream->inst_sect.size, DEC_ADDRLEN);
01019     case DEC_ADDRLEN:
01020       SIZE_CASE(1, stream->addr_sect.size, DEC_CKSUM);
01021 
01022     case DEC_CKSUM:
01023       /* Window checksum. */
01024       if ((stream->dec_win_ind & VCD_ADLER32) != 0)
01025         {
01026           int i;
01027 
01028           if ((ret = xd3_decode_bytes (stream, stream->dec_cksum,
01029                                        & stream->dec_cksumbytes, 4)))
01030             {
01031               return ret;
01032             }
01033 
01034           for (i = 0; i < 4; i += 1)
01035             {
01036               stream->dec_adler32 =
01037                 (stream->dec_adler32 << 8) | stream->dec_cksum[i];
01038             }
01039         }
01040 
01041       stream->dec_state = DEC_DATA;
01042 
01043       /* Check dec_enclen for redundency, otherwise it is not really used. */
01044       {
01045         usize_t enclen_check =
01046           (1 + (xd3_sizeof_size (stream->dec_tgtlen) +
01047                 xd3_sizeof_size (stream->data_sect.size) +
01048                 xd3_sizeof_size (stream->inst_sect.size) +
01049                 xd3_sizeof_size (stream->addr_sect.size)) +
01050            stream->data_sect.size +
01051            stream->inst_sect.size +
01052            stream->addr_sect.size +
01053            ((stream->dec_win_ind & VCD_ADLER32) ? 4 : 0));
01054 
01055         if (stream->dec_enclen != enclen_check)
01056           {
01057             stream->msg = "incorrect encoding length (redundent)";
01058             return XD3_INVALID_INPUT;
01059           }
01060       }
01061 
01062       /* Returning here gives the application a chance to inspect the
01063        * header, skip the window, etc. */
01064       if (stream->current_window == 0) { return XD3_GOTHEADER; }
01065       else                             { return XD3_WINSTART; }
01066 
01067     case DEC_DATA:
01068     case DEC_INST:
01069     case DEC_ADDR:
01070       /* Next read the three sections. */
01071      if ((ret = xd3_decode_sections (stream))) { return ret; }
01072 
01073     case DEC_EMIT:
01074 
01075       /* To speed VCD_SOURCE block-address calculations, the source
01076        * cpyoff_blocks and cpyoff_blkoff are pre-computed. */
01077       if (stream->dec_win_ind & VCD_SOURCE)
01078         {
01079           xd3_source *src = stream->src;
01080 
01081           if (src == NULL)
01082             {
01083               stream->msg = "source input required";
01084               return XD3_INVALID_INPUT;
01085             }
01086 
01087           xd3_blksize_div(stream->dec_cpyoff, src,
01088                           &src->cpyoff_blocks,
01089                           &src->cpyoff_blkoff);
01090           
01091           IF_DEBUG2(DP(RINT
01092                        "decode cpyoff %"Q"u "
01093                        "cpyblkno %"Q"u "
01094                        "cpyblkoff %u "
01095                        "blksize %u\n",
01096                        stream->dec_cpyoff,
01097                        src->cpyoff_blocks,
01098                        src->cpyoff_blkoff,
01099                        src->blksize));
01100         }
01101 
01102       /* xd3_decode_emit returns XD3_OUTPUT on every success. */
01103       if ((ret = xd3_decode_emit (stream)) == XD3_OUTPUT)
01104         {
01105           stream->total_out += (xoff_t) stream->avail_out;
01106         }
01107 
01108       return ret;
01109 
01110     case DEC_FINISH:
01111       {
01112         if (stream->dec_win_ind & VCD_TARGET)
01113           {
01114             if (stream->dec_lastwin == NULL)
01115               {
01116                 stream->dec_lastwin   = stream->next_out;
01117                 stream->dec_lastspace = stream->space_out;
01118               }
01119             else
01120               {
01121                 xd3_swap_uint8p (& stream->dec_lastwin,
01122                                  & stream->next_out);
01123                 xd3_swap_usize_t (& stream->dec_lastspace,
01124                                   & stream->space_out);
01125               }
01126           }
01127 
01128         stream->dec_lastlen   = stream->dec_tgtlen;
01129         stream->dec_laststart = stream->dec_winstart;
01130         stream->dec_window_count += 1;
01131 
01132         /* Note: the updates to dec_winstart & current_window are
01133          * deferred until after the next DEC_WININD byte is read. */
01134         stream->dec_state = DEC_WININD;
01135         return XD3_WINFINISH;
01136       }
01137 
01138     default:
01139       stream->msg = "invalid state";
01140       return XD3_INVALID_INPUT;
01141     }
01142 }
01143 
01144 #endif // _XDELTA3_DECODE_H_