📄 xdelta3-decode.h
字号:
/* The window may be entirely processed. */ XD3_ASSERT (stream->dec_winbytes <= need); /* Compute how much more input is needed. */ more = (need - stream->dec_winbytes); /* How much to consume. */ take = min (more, stream->avail_in); /* See if the input is completely available, to avoid copy. */ copy = (take != more); /* If the window is skipped... */ if ((stream->flags & XD3_SKIP_WINDOW) != 0) { /* Skip the available input. */ DECODE_INPUT (take); stream->dec_winbytes += take; if (copy) { stream->msg = "further input required"; return XD3_INPUT; } return xd3_decode_finish_window (stream); } /* Process all but the DATA section. */ switch (stream->dec_state) { default: stream->msg = "internal error"; return XD3_INVALID_INPUT; case DEC_DATA: if ((ret = xd3_decode_section (stream, & stream->data_sect, DEC_INST, copy))) { return ret; } case DEC_INST: if ((ret = xd3_decode_section (stream, & stream->inst_sect, DEC_ADDR, copy))) { return ret; } case DEC_ADDR: if ((ret = xd3_decode_section (stream, & stream->addr_sect, DEC_EMIT, copy))) { return ret; } } XD3_ASSERT (stream->dec_winbytes == need); if ((ret = xd3_decode_secondary_sections (stream))) { return ret; } if (stream->flags & XD3_SKIP_EMIT) { return xd3_decode_finish_window (stream); } /* OPT: A possible optimization is to avoid allocating memory in * decode_setup_buffers and to avoid a large memcpy when the window * consists of a single VCD_SOURCE copy instruction. The only * potential problem is if the following window is a VCD_TARGET, * then you need to remember... */ if ((ret = xd3_decode_setup_buffers (stream))) { return ret; } return 0;}static intxd3_decode_emit (xd3_stream *stream){ int ret; /* Produce output: originally structured to allow reentrant code * that fills as much of the output buffer as possible, but VCDIFF * semantics allows to copy from anywhere from the target window, so * instead allocate a sufficiently sized buffer after the target * window length is decoded. * * This code still needs to be reentrant to allow XD3_GETSRCBLK to * return control. This is handled by setting the * stream->dec_currentN instruction types to XD3_NOOP after they * have been processed. */ XD3_ASSERT (! (stream->flags & XD3_SKIP_EMIT)); XD3_ASSERT (stream->dec_tgtlen <= stream->space_out); while (stream->inst_sect.buf != stream->inst_sect.buf_max || stream->dec_current1.type != XD3_NOOP || stream->dec_current2.type != XD3_NOOP) { /* Decode next instruction pair. */ if ((stream->dec_current1.type == XD3_NOOP) && (stream->dec_current2.type == XD3_NOOP) && (ret = xd3_decode_instruction (stream))) { return ret; } /* Output for each instruction. */ if ((stream->dec_current1.type != XD3_NOOP) && (ret = xd3_decode_output_halfinst (stream, & stream->dec_current1))) { return ret; } if ((stream->dec_current2.type != XD3_NOOP) && (ret = xd3_decode_output_halfinst (stream, & stream->dec_current2))) { return ret; } } if (stream->avail_out != stream->dec_tgtlen) { IF_DEBUG1 (DP(RINT "AVAIL_OUT(%d) != DEC_TGTLEN(%d)\n", stream->avail_out, stream->dec_tgtlen)); stream->msg = "wrong window length"; return XD3_INVALID_INPUT; } if (stream->data_sect.buf != stream->data_sect.buf_max) { stream->msg = "extra data section"; return XD3_INVALID_INPUT; } if (stream->addr_sect.buf != stream->addr_sect.buf_max) { stream->msg = "extra address section"; return XD3_INVALID_INPUT; } /* OPT: Should cksum computation be combined with the above loop? */ if ((stream->dec_win_ind & VCD_ADLER32) != 0 && (stream->flags & XD3_ADLER32_NOVER) == 0) { uint32_t a32 = adler32 (1L, stream->next_out, stream->avail_out); if (a32 != stream->dec_adler32) { stream->msg = "target window checksum mismatch"; return XD3_INVALID_INPUT; } } /* Finished with a window. */ return xd3_decode_finish_window (stream);}intxd3_decode_input (xd3_stream *stream){ int ret; if (stream->enc_state != 0) { stream->msg = "encoder/decoder transition"; return XD3_INVALID_INPUT; }#define BYTE_CASE(expr,x,nstate) \ do { \ if ( (expr) && \ ((ret = xd3_decode_byte (stream, & (x))) != 0) ) { return ret; } \ stream->dec_state = (nstate); \ } while (0)#define OFFSET_CASE(expr,x,nstate) \ do { \ if ( (expr) && \ ((ret = xd3_decode_offset (stream, & (x))) != 0) ) { return ret; } \ stream->dec_state = (nstate); \ } while (0)#define SIZE_CASE(expr,x,nstate) \ do { \ if ( (expr) && \ ((ret = xd3_decode_size (stream, & (x))) != 0) ) { return ret; } \ stream->dec_state = (nstate); \ } while (0) switch (stream->dec_state) { case DEC_VCHEAD: { if ((ret = xd3_decode_bytes (stream, stream->dec_magic, & stream->dec_magicbytes, 4))) { return ret; } if (stream->dec_magic[0] != VCDIFF_MAGIC1 || stream->dec_magic[1] != VCDIFF_MAGIC2 || stream->dec_magic[2] != VCDIFF_MAGIC3) { stream->msg = "not a VCDIFF input"; return XD3_INVALID_INPUT; } if (stream->dec_magic[3] != 0) { stream->msg = "VCDIFF input version > 0 is not supported"; return XD3_INVALID_INPUT; } stream->dec_state = DEC_HDRIND; } case DEC_HDRIND: { if ((ret = xd3_decode_byte (stream, & stream->dec_hdr_ind))) { return ret; } if ((stream->dec_hdr_ind & VCD_INVHDR) != 0) { stream->msg = "unrecognized header indicator bits set"; return XD3_INVALID_INPUT; } stream->dec_state = DEC_SECONDID; } case DEC_SECONDID: /* Secondary compressor ID: only if VCD_SECONDARY is set */ if ((stream->dec_hdr_ind & VCD_SECONDARY) != 0) { BYTE_CASE (1, stream->dec_secondid, DEC_TABLEN); switch (stream->dec_secondid) { case VCD_FGK_ID: FGK_CASE (stream); case VCD_DJW_ID: DJW_CASE (stream); default: stream->msg = "unknown secondary compressor ID"; return XD3_INVALID_INPUT; } } case DEC_TABLEN: /* Length of code table data: only if VCD_CODETABLE is set */ SIZE_CASE ((stream->dec_hdr_ind & VCD_CODETABLE) != 0, stream->dec_codetblsz, DEC_NEAR); /* The codetblsz counts the two NEAR/SAME bytes */ if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0) { if (stream->dec_codetblsz <= 2) { stream->msg = "invalid code table size"; return ENOMEM; } stream->dec_codetblsz -= 2; } case DEC_NEAR: /* Near modes: only if VCD_CODETABLE is set */ BYTE_CASE((stream->dec_hdr_ind & VCD_CODETABLE) != 0, stream->acache.s_near, DEC_SAME); case DEC_SAME: /* Same modes: only if VCD_CODETABLE is set */ BYTE_CASE((stream->dec_hdr_ind & VCD_CODETABLE) != 0, stream->acache.s_same, DEC_TABDAT); case DEC_TABDAT: /* Compressed code table data */ if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0) { /* Get the code table data. */ if ((stream->dec_codetbl == NULL) && (stream->dec_codetbl = (uint8_t*) xd3_alloc (stream, stream->dec_codetblsz, 1)) == NULL) { return ENOMEM; } if ((ret = xd3_decode_bytes (stream, stream->dec_codetbl, & stream->dec_codetblbytes, stream->dec_codetblsz))) { return ret; } if ((ret = xd3_apply_table_encoding (stream, stream->dec_codetbl, stream->dec_codetblbytes))) { return ret; } } else { /* Use the default table. */ stream->acache.s_near = __rfc3284_code_table_desc.near_modes; stream->acache.s_same = __rfc3284_code_table_desc.same_modes; stream->code_table = xd3_rfc3284_code_table (); } if ((ret = xd3_alloc_cache (stream))) { return ret; } stream->dec_state = DEC_APPLEN; case DEC_APPLEN: /* Length of application data */ SIZE_CASE((stream->dec_hdr_ind & VCD_APPHEADER) != 0, stream->dec_appheadsz, DEC_APPDAT); case DEC_APPDAT: /* Application data */ if (stream->dec_hdr_ind & VCD_APPHEADER) { /* Note: we add an additional byte for padding, to allow 0-termination. */ if ((stream->dec_appheader == NULL) && (stream->dec_appheader = (uint8_t*) xd3_alloc (stream, stream->dec_appheadsz+1, 1)) == NULL) { return ENOMEM; } stream->dec_appheader[stream->dec_appheadsz] = 0; if ((ret = xd3_decode_bytes (stream, stream->dec_appheader, & stream->dec_appheadbytes, stream->dec_appheadsz))) { return ret; } } stream->dec_hdrsize = stream->total_in; stream->dec_state = DEC_WININD; case DEC_WININD: { /* Start of a window: the window indicator */ if ((ret = xd3_decode_byte (stream, & stream->dec_win_ind))) { return ret; } stream->current_window = stream->dec_window_count; if (XOFF_T_OVERFLOW (stream->dec_winstart, stream->dec_tgtlen)) { stream->msg = "decoder file offset overflow"; return XD3_INVALID_INPUT; } stream->dec_winstart += stream->dec_tgtlen; if ((stream->dec_win_ind & VCD_INVWIN) != 0) { stream->msg = "unrecognized window indicator bits set"; return XD3_INVALID_INPUT; } if ((ret = xd3_decode_init_window (stream))) { return ret; } stream->dec_state = DEC_CPYLEN; IF_DEBUG1 (DP(RINT "--------- TARGET WINDOW %"Q"u -----------\n", stream->current_window)); } case DEC_CPYLEN: /* Copy window length: only if VCD_SOURCE or VCD_TARGET is set */ SIZE_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpylen, DEC_CPYOFF); /* Set the initial, logical decoder position (HERE address) in * dec_position. This is set to just after the source/copy * window, as we are just about to output the first byte of * target window. */ stream->dec_position = stream->dec_cpylen; case DEC_CPYOFF: /* Copy window offset: only if VCD_SOURCE or VCD_TARGET is set */ OFFSET_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpyoff, DEC_ENCLEN); /* Copy offset and copy length may not overflow. */ if (XOFF_T_OVERFLOW (stream->dec_cpyoff, stream->dec_cpylen)) { stream->msg = "decoder copy window overflows a file offset"; return XD3_INVALID_INPUT; } /* Check copy window bounds: VCD_TARGET window may not exceed current position. */ if ((stream->dec_win_ind & VCD_TARGET) && (stream->dec_cpyoff + (xoff_t) stream->dec_cpylen > stream->dec_winstart)) { stream->msg = "VCD_TARGET window out of bounds"; return XD3_INVALID_INPUT; } case DEC_ENCLEN: /* Length of the delta encoding */ SIZE_CASE(1, stream->dec_enclen, DEC_TGTLEN); case DEC_TGTLEN: /* Length of target window */ SIZE_CASE(1, stream->dec_tgtlen, DEC_DELIND); /* Set the maximum decoder position, beyond which we should not * decode any data. This is the maximum value for dec_position. * This may not exceed the size of a usize_t. */ if (USIZE_T_OVERFLOW (stream->dec_cpylen, stream->dec_tgtlen)) { stream->msg = "decoder target window overflows a usize_t"; return XD3_INVALID_INPUT; } /* Check for malicious files. */ if (stream->dec_tgtlen > XD3_HARDMAXWINSIZE) { stream->msg = "hard window size exceeded"; return XD3_INVALID_INPUT; } stream->dec_maxpos = stream->dec_cpylen + stream->dec_tgtlen; case DEC_DELIND: /* Delta indicator */ BYTE_CASE(1, stream->dec_del_ind, DEC_DATALEN); if ((stream->dec_del_ind & VCD_INVDEL) != 0) { stream->msg = "unrecognized delta indicator bits set"; return XD3_INVALID_INPUT; } /* Delta indicator is only used with secondary compression. */ if ((stream->dec_del_ind != 0) && (stream->sec_type == NULL)) { stream->msg = "invalid delta indicator bits set"; return XD3_INVALID_INPUT; } /* Section lengths */ case DEC_DATALEN: SIZE_CASE(1, stream->data_sect.size, DEC_INSTLEN); case DEC_INSTLEN: SIZE_CASE(1, stream->inst_sect.size, DEC_ADDRLEN); case DEC_ADDRLEN: SIZE_CASE(1, stream->addr_sect.size, DEC_CKSUM); case DEC_CKSUM: /* Window checksum. */ if ((stream->dec_win_ind & VCD_ADLER32) != 0) { int i; if ((ret = xd3_decode_bytes (stream, stream->dec_cksum, & stream->dec_cksumbytes, 4))) { return ret; } for (i = 0; i < 4; i += 1) { stream->dec_adler32 = (stream->dec_adler32 << 8) | stream->dec_cksum[i]; } } stream->dec_state = DEC_DATA; /* Check dec_enclen for redundency, otherwise it is not really used. */ { usize_t enclen_check = (1 + (xd3_sizeof_size (stream->dec_tgtlen) + xd3_sizeof_size (stream->data_sect.size) + xd3_sizeof_size (stream->inst_sect.size) + xd3_sizeof_size (stream->addr_sect.size)) + stream->data_sect.size + stream->inst_sect.size + stream->addr_sect.size + ((stream->dec_win_ind & VCD_ADLER32) ? 4 : 0)); if (stream->dec_enclen != enclen_check) { stream->msg = "incorrect encoding length (redundent)"; return XD3_INVALID_INPUT; } } /* Returning here gives the application a chance to inspect the * header, skip the window, etc. */ if (stream->current_window == 0) { return XD3_GOTHEADER; } else { return XD3_WINSTART; } case DEC_DATA: case DEC_INST: case DEC_ADDR: /* Next read the three sections. */ if ((ret = xd3_decode_sections (stream))) { return ret; } case DEC_EMIT: /* To speed VCD_SOURCE block-address calculations, the source * cpyoff_blocks and cpyoff_blkoff are pre-computed. */ if (stream->dec_win_ind & VCD_SOURCE) { xd3_source *src = stream->src; if (src == NULL) { stream->msg = "source input required"; return XD3_INVALID_INPUT; } xd3_blksize_div(stream->dec_cpyoff, src, &src->cpyoff_blocks, &src->cpyoff_blkoff); } /* xd3_decode_emit returns XD3_OUTPUT on every success. */ if ((ret = xd3_decode_emit (stream)) == XD3_OUTPUT) { stream->total_out += (xoff_t) stream->avail_out; } return ret; case DEC_FINISH: { if (stream->dec_win_ind & VCD_TARGET) { if (stream->dec_lastwin == NULL) { stream->dec_lastwin = stream->next_out; stream->dec_lastspace = stream->space_out; } else { xd3_swap_uint8p (& stream->dec_lastwin, & stream->next_out); xd3_swap_usize_t (& stream->dec_lastspace, & stream->space_out); } } stream->dec_lastlen = stream->dec_tgtlen; stream->dec_laststart = stream->dec_winstart; stream->dec_window_count += 1; /* Note: the updates to dec_winstart & current_window are * deferred until after the next DEC_WININD byte is read. */ stream->dec_state = DEC_WININD; return XD3_WINFINISH; } default: stream->msg = "invalid state"; return XD3_INVALID_INPUT; }}#endif // _XDELTA3_DECODE_H_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -