⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xdelta3-decode.h

📁 Linux下一个可以比较二进制文件的工具xdelta3.0u的源码。
💻 H
📖 第 1 页 / 共 2 页
字号:
/* xdelta 3 - delta compression tools and library * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007.  Joshua P. MacDonald * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#ifndef _XDELTA3_DECODE_H_#define _XDELTA3_DECODE_H_#define SRCORTGT(x) ((((x) & VCD_SRCORTGT) == VCD_SOURCE) ? \                     VCD_SOURCE : ((((x) & VCD_SRCORTGT) == \                                    VCD_TARGET) ? VCD_TARGET : 0))/* Initialize the decoder for a new window.  The dec_tgtlen value is * preserved across successive window decodings, and the update to * dec_winstart is delayed until a new window actually starts.  This * is to avoid throwing an error due to overflow until the last * possible moment.  This makes it possible to encode exactly 4GB * through a 32-bit encoder. */static intxd3_decode_init_window (xd3_stream *stream){  stream->dec_cpylen = 0;  stream->dec_cpyoff = 0;  stream->dec_cksumbytes = 0;  xd3_init_cache (& stream->acache);  return 0;}/* Allocates buffer space for the target window and possibly the * VCD_TARGET copy-window.  Also sets the base of the two copy * segments. */static intxd3_decode_setup_buffers (xd3_stream *stream){  /* If VCD_TARGET is set then the previous buffer may be reused. */  if (stream->dec_win_ind & VCD_TARGET)    {      /* But this implementation only supports copying from the last       * target window.  If the offset is outside that range, it can't       * be done. */      if (stream->dec_cpyoff < stream->dec_laststart)	{	  stream->msg = "unsupported VCD_TARGET offset";	  return XD3_INVALID_INPUT;	}      /* See if the two windows are the same.  This indicates the       * first time VCD_TARGET is used.  This causes a second buffer       * to be allocated, after that the two are swapped in the       * DEC_FINISH case. */      if (stream->dec_lastwin == stream->next_out)	{	  stream->next_out  = NULL;	  stream->space_out = 0;	}      // TODO: VCD_TARGET mode, this is broken      stream->dec_cpyaddrbase = stream->dec_lastwin +	(usize_t) (stream->dec_cpyoff - stream->dec_laststart);    }  /* See if the current output window is large enough. */  if (stream->space_out < stream->dec_tgtlen)    {      xd3_free (stream, stream->dec_buffer);      stream->space_out =	xd3_round_blksize (stream->dec_tgtlen, XD3_ALLOCSIZE);      if ((stream->dec_buffer =	   (uint8_t*) xd3_alloc (stream, stream->space_out, 1)) == NULL)	{	  return ENOMEM;	}      stream->next_out = stream->dec_buffer;    }  /* dec_tgtaddrbase refers to an invalid base address, but it is   * always used with a sufficiently large instruction offset (i.e.,   * beyond the copy window).  This condition is enforced by   * xd3_decode_output_halfinst. */  stream->dec_tgtaddrbase = stream->next_out - stream->dec_cpylen;  return 0;}static intxd3_decode_allocate (xd3_stream  *stream,		     usize_t       size,		     uint8_t    **buf_ptr,		     usize_t      *buf_alloc){  if (*buf_ptr != NULL && *buf_alloc < size)    {      xd3_free (stream, *buf_ptr);      *buf_ptr = NULL;    }  if (*buf_ptr == NULL)    {      *buf_alloc = xd3_round_blksize (size, XD3_ALLOCSIZE);      if ((*buf_ptr = (uint8_t*) xd3_alloc (stream, *buf_alloc, 1)) == NULL)	{	  return ENOMEM;	}    }  return 0;}static intxd3_decode_section (xd3_stream *stream,		    xd3_desect *section,		    xd3_decode_state nstate,		    int copy){  XD3_ASSERT (section->pos <= section->size);  XD3_ASSERT (stream->dec_state != nstate);  if (section->pos < section->size)    {      usize_t sect_take;      if (stream->avail_in == 0)	{	  return XD3_INPUT;	}      if ((copy == 0) && (section->pos == 0))	{	  /* No allocation/copy needed */	  section->buf = stream->next_in;	  sect_take    = section->size;	}      else	{	  usize_t sect_need = section->size - section->pos;	  /* Allocate and copy */	  sect_take = min (sect_need, stream->avail_in);	  if (section->pos == 0)	    {	      int ret;	      if ((ret = xd3_decode_allocate (stream,					      section->size,					      & section->copied1,					      & section->alloc1)))		{		  return ret;		}	      section->buf = section->copied1;	    }	  memcpy (section->copied1 + section->pos,		  stream->next_in,		  sect_take);	}      section->pos += sect_take;      stream->dec_winbytes += sect_take;      DECODE_INPUT (sect_take);    }  if (section->pos < section->size)    {      stream->msg = "further input required";      return XD3_INPUT;    }  XD3_ASSERT (section->pos == section->size);  stream->dec_state = nstate;  section->buf_max  = section->buf + section->size;  section->pos      = 0;  return 0;}/* Decode the size and address for half of an instruction (i.e., a * single opcode).  This updates the stream->dec_position, which are * bytes already output prior to processing this instruction.  Perform * bounds checking for sizes and copy addresses, which uses the * dec_position (which is why these checks are done here). */static intxd3_decode_parse_halfinst (xd3_stream *stream, xd3_hinst *inst){  int ret;  /* If the size from the instruction table is zero then read a size value. */  if ((inst->size == 0) &&      (ret = xd3_read_size (stream, 			    & stream->inst_sect.buf,			      stream->inst_sect.buf_max,			    & inst->size)))    {      return XD3_INVALID_INPUT;    }  /* For copy instructions, read address. */  if (inst->type >= XD3_CPY)    {      IF_DEBUG2 ({	static int cnt = 0;	DP(RINT "DECODE:%u: COPY at %"Q"u (winoffset %u) size %u winaddr %u\n",		 cnt++,		 stream->total_out + (stream->dec_position -				      stream->dec_cpylen),		 (stream->dec_position - stream->dec_cpylen),		 inst->size,		 inst->addr);      });      if ((ret = xd3_decode_address (stream,				     stream->dec_position,				     inst->type - XD3_CPY,				     & stream->addr_sect.buf,				     stream->addr_sect.buf_max,				     & inst->addr)))	{	  return ret;	}      /* Cannot copy an address before it is filled-in. */      if (inst->addr >= stream->dec_position)	{	  stream->msg = "address too large";	  return XD3_INVALID_INPUT;	}      /* Check: a VCD_TARGET or VCD_SOURCE copy cannot exceed the remaining       * buffer space in its own segment. */      if (inst->addr < stream->dec_cpylen &&	  inst->addr + inst->size > stream->dec_cpylen)	{	  stream->msg = "size too large";	  return XD3_INVALID_INPUT;	}    }  else    {      IF_DEBUG2 ({	if (inst->type == XD3_ADD)	  {	    static int cnt;	    DP(RINT "DECODE:%d: ADD at %"Q"u (winoffset %u) size %u\n",	       cnt++,	       (stream->total_out + stream->dec_position - stream->dec_cpylen),	       stream->dec_position - stream->dec_cpylen,	       inst->size);	  }	else	  {	    static int cnt;	    XD3_ASSERT (inst->type == XD3_RUN);	    DP(RINT "DECODE:%d: RUN at %"Q"u (winoffset %u) size %u\n",	       cnt++,	       stream->total_out + stream->dec_position - stream->dec_cpylen,	       stream->dec_position - stream->dec_cpylen,	       inst->size);	  }      });    }  /* Check: The instruction will not overflow the output buffer. */  if (stream->dec_position + inst->size > stream->dec_maxpos)    {      stream->msg = "size too large";      return XD3_INVALID_INPUT;    }  stream->dec_position += inst->size;  return 0;}/* Decode a single opcode and then decode the two half-instructions. */static intxd3_decode_instruction (xd3_stream *stream){  int ret;  const xd3_dinst *inst;  if (stream->inst_sect.buf == stream->inst_sect.buf_max)    {      stream->msg = "instruction underflow";      return XD3_INVALID_INPUT;    }  inst = &stream->code_table[*stream->inst_sect.buf++];  stream->dec_current1.type = inst->type1;  stream->dec_current2.type = inst->type2;  stream->dec_current1.size = inst->size1;  stream->dec_current2.size = inst->size2;  /* For each instruction with a real operation, decode the   * corresponding size and addresses if necessary.  Assume a   * code-table may have NOOP in either position, although this is   * unlikely. */  if (inst->type1 != XD3_NOOP &&      (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current1)))    {      return ret;    }  if (inst->type2 != XD3_NOOP &&      (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current2)))    {      return ret;    }  return 0;}/* Output the result of a single half-instruction. OPT: This the   decoder hotspot. */static intxd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst){  /* To make this reentrant, set take = min (inst->size, available     space)... */  usize_t take = inst->size;  XD3_ASSERT (inst->type != XD3_NOOP);  switch (inst->type)    {    case XD3_RUN:      {	/* Only require a single data byte. */	if (stream->data_sect.buf == stream->data_sect.buf_max)	  {	    stream->msg = "data underflow";	    return XD3_INVALID_INPUT;	  }	memset (stream->next_out + stream->avail_out,		stream->data_sect.buf[0],		take);	stream->data_sect.buf += 1;	stream->avail_out += take;	inst->type = XD3_NOOP;	break;      }    case XD3_ADD:      {	/* Require at least TAKE data bytes. */	if (stream->data_sect.buf + take > stream->data_sect.buf_max)	  {	    stream->msg = "data underflow";	    return XD3_INVALID_INPUT;	  }	memcpy (stream->next_out + stream->avail_out,		stream->data_sect.buf,		take);	stream->data_sect.buf += take;	stream->avail_out += take;	inst->type = XD3_NOOP;	break;      }    default:      {	usize_t i;	const uint8_t *src;	uint8_t *dst;	/* See if it copies from the VCD_TARGET/VCD_SOURCE window or	 * the target window.  Out-of-bounds checks for the addresses	 * and sizes are performed in xd3_decode_parse_halfinst. */	if (inst->addr < stream->dec_cpylen)	  {	    if (stream->dec_win_ind & VCD_TARGET)	      {		/* For VCD_TARGET we know the entire range is		 * in-memory, as established by		 * decode_setup_buffers.                 *                 * TODO: this is totally bogus, VCD_TARGET won't work.                 */		src = stream->dec_cpyaddrbase + inst->addr;		inst->type = XD3_NOOP;		inst->size = 0;	      }	    else	      {		/* In this case we have to read a source block, which		 * could return control to the caller.  We need to		 * know the first block number needed for this		 * copy. */		xd3_source *source;		xoff_t block;		usize_t blkoff;		usize_t blksize;		int ret;	      more:		source  = stream->src;		block   = source->cpyoff_blocks;		blkoff  = source->cpyoff_blkoff + inst->addr;		blksize = source->blksize; 		while (blkoff >= blksize)		  {		    block  += 1;		    blkoff -= blksize;		  }		if ((ret = xd3_getblk (stream, block)))		  {		    /* could be a XD3_GETSRCBLK failure. */		    if (ret == XD3_TOOFARBACK)		      {			ret = XD3_INTERNAL;		      }		    return ret;		  }		src = source->curblk + blkoff;		/* This block either contains enough data or the source file		 * is short. */		if ((source->onblk != blksize) &&		    (blkoff + take > source->onblk))		  {		    stream->msg = "source file too short";		    return XD3_INVALID_INPUT;		  }		XD3_ASSERT (blkoff != blksize);		if (blkoff + take <= blksize)		  {		    inst->type = XD3_NOOP;		    inst->size = 0;		  }		else		  {		    /* This block doesn't contain all the data, modify		     * the instruction, do not set to XD3_NOOP. */		    take = blksize - blkoff;		    inst->size -= take;		    inst->addr += take;		  }	      }	  }	else	  {	    /* For a target-window copy, we know the entire range is	     * in-memory.  The dec_tgtaddrbase is negatively offset by	     * dec_cpylen because the addresses start beyond that	     * point. */	    src = stream->dec_tgtaddrbase + inst->addr;	    inst->type = XD3_NOOP;	    inst->size = 0;	  } 	dst = stream->next_out + stream->avail_out;	stream->avail_out += take;	/* Can't just memcpy here due to possible overlap. */	for (i = take; i != 0; i -= 1)	  {	    *dst++ = *src++;	  }	take = inst->size;	/* If there is more to copy, call getblk again. */	if (inst->type != XD3_NOOP)	  {	    XD3_ASSERT (take > 0);	    goto more;	  }	else	  {	    XD3_ASSERT (take == 0);	  }      }    }  return 0;}static intxd3_decode_finish_window (xd3_stream *stream){  stream->dec_winbytes  = 0;  stream->dec_state     = DEC_FINISH;  stream->data_sect.pos = 0;  stream->inst_sect.pos = 0;  stream->addr_sect.pos = 0;  return XD3_OUTPUT;}static intxd3_decode_secondary_sections (xd3_stream *secondary_stream){#if SECONDARY_ANY  int ret;#define DECODE_SECONDARY_SECTION(UPPER,LOWER) \  ((secondary_stream->dec_del_ind & VCD_ ## UPPER ## COMP) && \   (ret = xd3_decode_secondary (secondary_stream, \				& secondary_stream-> LOWER ## _sect,	\				& xd3_sec_ ## LOWER (secondary_stream))))  if (DECODE_SECONDARY_SECTION (DATA, data) ||      DECODE_SECONDARY_SECTION (INST, inst) ||      DECODE_SECONDARY_SECTION (ADDR, addr))    {      return ret;    }#undef DECODE_SECONDARY_SECTION#endif  return 0;}static intxd3_decode_sections (xd3_stream *stream){  usize_t need, more, take;  int copy, ret;  if ((stream->flags & XD3_JUST_HDR) != 0)    {      /* Nothing left to do. */      return xd3_decode_finish_window (stream);    }  /* To avoid copying, need this much data available */  need = (stream->inst_sect.size +	  stream->addr_sect.size +	  stream->data_sect.size);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -