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