[185] | 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_
|
---|