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 **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 |
|
---|
126 | static int
|
---|
127 | xd3_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). */
|
---|
201 | static int
|
---|
202 | xd3_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. */
|
---|
291 | static int
|
---|
292 | xd3_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. */
|
---|
325 | static int
|
---|
326 | xd3_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 |
|
---|
488 | static int
|
---|
489 | xd3_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 |
|
---|
501 | static int
|
---|
502 | xd3_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 |
|
---|
592 | static int
|
---|
593 | xd3_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 |
|
---|
660 | int
|
---|
661 | xd3_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_
|
---|