root/vowfsc/xdelta3-decode.h

Revision 36, 29.2 kB (checked in by dmajnem2, 10 months ago)

Beginning xdelta stuffs

  • Property svn:executable set to *
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? */
26 int 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. */
36 static int
37 xd3_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. */
50 static int
51 xd3_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
99 static int
100 xd3_decode_allocate (xd3_stream  *stream,
101                      usize_t       size,
102                      uint8_t    **buf_ptr,
103                      usize_t      *buf_alloc)
104 {
105   if (*buf_ptr != NULL && *buf_alloc < size)
106     {
107       xd3_free (stream, *buf_ptr);
108       *buf_ptr = NULL;
109     }
110
111   if (*buf_ptr == NULL)
112     {
113       *buf_alloc = xd3_round_blksize (size, XD3_ALLOCSIZE);
114
115       if ((*buf_ptr = xd3_alloc (stream, *buf_alloc, 1)) == NULL)
116         {
117           return ENOMEM;
118         }
119     }
120
121   return 0;
122 }
123
124 static int
125 xd3_decode_section (xd3_stream *stream,
126                     xd3_desect *section,
127                     xd3_decode_state nstate,
128                     int copy)
129 {
130   XD3_ASSERT (section->pos <= section->size);
131   XD3_ASSERT (stream->dec_state != nstate);
132
133   if (section->pos < section->size)
134     {
135       usize_t sect_take;
136
137       if (stream->avail_in == 0)
138         {
139           return XD3_INPUT;
140         }
141
142       if ((copy == 0) && (section->pos == 0))
143         {
144           /* No allocation/copy needed */
145           section->buf = stream->next_in;
146           sect_take    = section->size;
147         }
148       else
149         {
150           usize_t sect_need = section->size - section->pos;
151
152           /* Allocate and copy */
153           sect_take = min (sect_need, stream->avail_in);
154
155           if (section->pos == 0)
156             {
157               int ret;
158
159               if ((ret = xd3_decode_allocate (stream,
160                                               section->size,
161                                               & section->copied1,
162                                               & section->alloc1))) { return ret; }
163
164               section->buf = section->copied1;
165             }
166
167           memcpy (section->copied1 + section->pos,
168                   stream->next_in,
169                   sect_take);
170         }
171
172       section->pos += sect_take;
173
174       stream->dec_winbytes += sect_take;
175
176       DECODE_INPUT (sect_take);
177     }
178
179   if (section->pos < section->size)
180     {
181       stream->msg = "further input required";
182       return XD3_INPUT;
183     }
184
185   XD3_ASSERT (section->pos == section->size);
186
187   stream->dec_state = nstate;
188   section->buf_max  = section->buf + section->size;
189   section->pos      = 0;
190   return 0;
191 }
192
193 /* Decode the size and address for half of an instruction (i.e., a single opcode).  This
194  * updates the stream->dec_position, which are bytes already output prior to processing
195  * this instruction.  Perform bounds checking for sizes and copy addresses, which uses the
196  * dec_position (which is why these checks are done here). */
197 static int
198 xd3_decode_parse_halfinst (xd3_stream *stream, xd3_hinst *inst)
199 {
200   int ret;
201
202   /* If the size from the instruction table is zero then read a size value. */
203   if ((inst->size == 0) &&
204       (ret = xd3_read_size (stream,
205                             & stream->inst_sect.buf,
206                               stream->inst_sect.buf_max,
207                             & inst->size)))
208     {
209       return XD3_INVALID_INPUT;
210     }
211
212   /* For copy instructions, read address. */
213   if (inst->type >= XD3_CPY)
214     {
215       IF_DEBUG1 ({
216         static int cnt = 0;
217         DP(RINT "DECODE:%u: COPY at %"Q"u (winoffset %u) size %u winaddr %u\n",
218                  cnt++,
219                  stream->total_out + (stream->dec_position - stream->dec_cpylen),
220                  (stream->dec_position - stream->dec_cpylen),
221                  inst->size,
222                  inst->addr);
223       });
224
225       if ((ret = xd3_decode_address (stream,
226                                      stream->dec_position,
227                                      inst->type - XD3_CPY,
228                                      & stream->addr_sect.buf,
229                                      stream->addr_sect.buf_max,
230                                      & inst->addr)))
231         {
232           return ret;
233         }
234
235       /* Cannot copy an address before it is filled-in. */
236       if (inst->addr >= stream->dec_position)
237         {
238           stream->msg = "address too large";
239           return XD3_INVALID_INPUT;
240         }
241
242       /* Check: a VCD_TARGET or VCD_SOURCE copy cannot exceed the remaining buffer space
243        * in its own segment. */
244       if (inst->addr < stream->dec_cpylen && inst->addr + inst->size > stream->dec_cpylen)
245         {
246           stream->msg = "size too large";
247           return XD3_INVALID_INPUT;
248         }
249     }
250   else
251     {
252       IF_DEBUG1 ({
253         if (inst->type == XD3_ADD)
254           {
255             static int cnt;
256             DP(RINT "DECODE:%d: ADD at %"Q"u (winoffset %u) size %u\n",
257                      cnt++,
258                      stream->total_out + stream->dec_position - stream->dec_cpylen,
259                      stream->dec_position - stream->dec_cpylen,
260                      inst->size);
261           }
262         else
263           {
264             static int cnt;
265             XD3_ASSERT (inst->type == XD3_RUN);
266             DP(RINT "DECODE:%d: RUN at %"Q"u (winoffset %u) size %u\n",
267                      cnt++,
268                      stream->total_out + stream->dec_position - stream->dec_cpylen,
269                      stream->dec_position - stream->dec_cpylen,
270                      inst->size);
271           }
272       });
273     }
274
275   /* Check: The instruction will not overflow the output buffer. */
276   if (stream->dec_position + inst->size > stream->dec_maxpos)
277     {
278       stream->msg = "size too large";
279       return XD3_INVALID_INPUT;
280     }
281
282   stream->dec_position += inst->size;
283   return 0;
284 }
285
286 /* Decode a single opcode and then decode the two half-instructions. */
287 static int
288 xd3_decode_instruction (xd3_stream *stream)
289 {
290   int ret;
291   const xd3_dinst *inst;
292
293   if (stream->inst_sect.buf == stream->inst_sect.buf_max)
294     {
295       stream->msg = "instruction underflow";
296       return XD3_INVALID_INPUT;
297     }
298
299   inst = &stream->code_table[*stream->inst_sect.buf++];
300
301   stream->dec_current1.type = inst->type1;
302   stream->dec_current2.type = inst->type2;
303   stream->dec_current1.size = inst->size1;
304   stream->dec_current2.size = inst->size2;
305
306   /* For each instruction with a real operation, decode the corresponding size and
307    * addresses if necessary.  Assume a code-table may have NOOP in either position,
308    * although this is unlikely. */
309   if (inst->type1 != XD3_NOOP && (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current1)))
310     {
311       return ret;
312     }
313   if (inst->type2 != XD3_NOOP && (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current2)))
314     {
315       return ret;
316     }
317   return 0;
318 }
319
320 /* Output the result of a single half-instruction. OPT: This the decoder hotspot. */
321 static int
322 xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst)
323 {
324   /* To make this reentrant, set take = min (inst->size, available space)... */
325   usize_t take = inst->size;
326
327   XD3_ASSERT (inst->type != XD3_NOOP);
328
329   switch (inst->type)
330     {
331     case XD3_RUN:
332       {
333         /* Only require a single data byte. */
334         if (stream->data_sect.buf == stream->data_sect.buf_max)
335           {
336             stream->msg = "data underflow";
337             return XD3_INVALID_INPUT;
338           }
339
340         memset (stream->next_out + stream->avail_out,
341                 stream->data_sect.buf[0],
342                 take);
343
344         stream->data_sect.buf += 1;
345         stream->avail_out += take;
346         inst->type = XD3_NOOP;
347         break;
348       }
349     case XD3_ADD:
350       {
351         /* Require at least TAKE data bytes. */
352         if (stream->data_sect.buf + take > stream->data_sect.buf_max)
353           {
354             stream->msg = "data underflow";
355             return XD3_INVALID_INPUT;
356           }
357
358         memcpy (stream->next_out + stream->avail_out,
359                 stream->data_sect.buf,
360                 take);
361
362         stream->data_sect.buf += take;
363         stream->avail_out += take;
364         inst->type = XD3_NOOP;
365         break;
366       }
367     default:
368       {
369         usize_t i;
370         const uint8_t *src;
371         uint8_t *dst;
372
373         /* See if it copies from the VCD_TARGET/VCD_SOURCE window or the target window.
374          * Out-of-bounds checks for the addresses and sizes are performed in
375          * xd3_decode_parse_halfinst. */
376         if (inst->addr < stream->dec_cpylen)
377           {
378             if (stream->dec_win_ind & VCD_TARGET)
379               {
380                 /* For VCD_TARGET we know the entire range is in-memory, as established by
381                  * decode_setup_buffers. */
382                 src = stream->dec_cpyaddrbase + inst->addr;
383                 inst->type = XD3_NOOP;
384                 inst->size = 0;
385               }
386             else
387               {
388                 /* In this case we have to read a source block, which could return control
389                  * to the caller.  We need to know the first block number needed for this
390                  * copy. */
391                 xd3_source *source;
392                 xoff_t block;
393                 usize_t blkoff;
394                 usize_t blksize;
395                 int ret;
396
397               more:
398
399                 source  = stream->src;
400                 block   = source->cpyoff_blocks;
401                 blkoff  = source->cpyoff_blkoff + inst->addr;
402                 blksize = source->blksize;
403
404                 while (blkoff >= blksize)
405                   {
406                     block  += 1;
407                     blkoff -= blksize;
408                   }
409
410                 if ((ret = xd3_getblk (stream, block)))
411                   {
412                     /* could be a XD3_GETSRCBLK failure. */
413                     if (ret == XD3_TOOFARBACK)
414                       {
415                         ret = XD3_INTERNAL;
416                       }
417                     return ret;
418                   }
419
420                 src = source->curblk + blkoff;
421
422                 /* This block either contains enough data or the source file is
423                  * short. */
424                 if ((source->onblk != blksize) && (blkoff + take > source->onblk))
425                   {
426                     stream->msg = "source file too short";
427                     return XD3_INVALID_INPUT;
428
429                   }
430
431                 XD3_ASSERT (blkoff != blksize);
432
433                 if (blkoff + take <= blksize)
434                   {
435                     inst->type = XD3_NOOP;
436                     inst->size = 0;
437                   }
438                 else
439                   {
440                     /* This block doesn't contain all the data, modify the instruction, do
441                      * not set to XD3_NOOP. */
442                     take = blksize - blkoff;
443                     inst->size -= take;
444                     inst->addr += take;
445                   }
446               }
447           }
448         else
449           {
450             /* For a target-window copy, we know the entire range is in-memory.  The
451              * dec_tgtaddrbase is negatively offset by dec_cpylen because the addresses
452              * start beyond that point. */
453             src = stream->dec_tgtaddrbase + inst->addr;
454             inst->type = XD3_NOOP;
455             inst->size = 0;
456           }
457
458         dst = stream->next_out + stream->avail_out;
459
460         stream->avail_out += take;
461
462         /* Can't just memcpy here due to possible overlap. */
463         for (i = take; i != 0; i -= 1)
464           {
465             *dst++ = *src++;
466           }
467
468         take = inst->size;
469
470         /* If there is more to copy, call getblk again. */
471         if (inst->type != XD3_NOOP)
472           {
473             XD3_ASSERT (take > 0);
474             goto more;
475           }
476         else
477           {
478             XD3_ASSERT (take == 0);
479           }
480       }
481     }
482
483   return 0;
484 }
485
486 static int
487 xd3_decode_finish_window (xd3_stream *stream)
488 {
489   stream->dec_winbytes  = 0;
490   stream->dec_state     = DEC_FINISH;
491
492   stream->data_sect.pos = 0;
493   stream->inst_sect.pos = 0;
494   stream->addr_sect.pos = 0;
495
496   return XD3_OUTPUT;
497 }
498
499 static int
500 xd3_decode_secondary_sections (xd3_stream *secondary_stream)
501 {
502 #if SECONDARY_ANY
503   int ret;
504 #define DECODE_SECONDARY_SECTION(UPPER,LOWER) \
505   ((secondary_stream->dec_del_ind & VCD_ ## UPPER ## COMP) && \
506    (ret = xd3_decode_secondary (secondary_stream, & secondary_stream-> LOWER ## _sect, \
507                                         & xd3_sec_ ## LOWER (secondary_stream))))
508
509   if (DECODE_SECONDARY_SECTION (DATA, data) ||
510       DECODE_SECONDARY_SECTION (INST, inst) ||
511       DECODE_SECONDARY_SECTION (ADDR, addr))
512     {
513       return ret;
514     }
515 #undef DECODE_SECONDARY_SECTION
516 #endif
517   return 0;
518 }
519
520 static int
521 xd3_decode_sections (xd3_stream *stream)
522 {
523   usize_t need, more, take;
524   int copy, ret;
525
526   if ((stream->flags & XD3_JUST_HDR) != 0)
527     {
528       /* Nothing left to do. */
529       return xd3_decode_finish_window (stream);
530     }
531
532   /* To avoid copying, need this much data available */
533   need = (stream->inst_sect.size +
534           stream->addr_sect.size +
535           stream->data_sect.size);
536
537   /* The window may be entirely processed. */
538   XD3_ASSERT (stream->dec_winbytes <= need);
539
540   /* Compute how much more input is needed. */
541   more = (need - stream->dec_winbytes);
542
543   /* How much to consume. */
544   take = min (more, stream->avail_in);
545
546   /* See if the input is completely available, to avoid copy. */
547   copy = (take != more);
548
549   /* If the window is skipped... */
550   if ((stream->flags & XD3_SKIP_WINDOW) != 0)
551     {
552       /* Skip the available input. */
553       DECODE_INPUT (take);
554
555       stream->dec_winbytes += take;
556
557       if (copy)
558         {
559           stream->msg = "further input required";
560           return XD3_INPUT;
561         }
562
563       return xd3_decode_finish_window (stream);
564     }
565
566   /* Process all but the DATA section. */
567   switch (stream->dec_state)
568     {
569     default:
570       stream->msg = "internal error";
571       return XD3_INVALID_INPUT;
572
573     case DEC_DATA:
574       if ((ret = xd3_decode_section (stream, & stream->data_sect, DEC_INST, copy))) { return ret; }
575     case DEC_INST:
576       if ((ret =