static int _xd3_set_source (xd3_stream *stream, xd3_cmd cmd, _xd3_file *sfile, xd3_source *source) { int ret = 0; usize_t i; xoff_t source_size = 0; usize_t blksize; XD3_ASSERT (lru == NULL); XD3_ASSERT (stream->src == NULL); XD3_ASSERT (option_srcwinsz >= XD3_MINSRCWINSZ); /* TODO: this code needs refactoring into FIFO, LRU, FAKE. Yuck! * This is simplified from 3.0z which had issues with sizing the * source buffer memory allocation and the source blocksize. */ /* LRU-specific */ main_blklru_list_init (& lru_list); if ((ret = _xd3_file_open (sfile, sfile->filename, XO_READ))) { return ret; } /* If the file is regular we know it's size. If the file turns * out to be externally compressed, size_known may change. */ sfile->size_known = (_xd3_file_stat(sfile, &source_size) == 0); /* Note: The API requires a power-of-two blocksize and srcwinsz * (-B). The logic here will use a single block if the entire file * is known to fit into srcwinsz. */ option_srcwinsz = xd3_pow2_roundup (option_srcwinsz); /* Though called "lru", it is not LRU-specific. We always allocate * a maximum number of source block buffers. If the entire file * fits into srcwinsz, this buffer will stay as the only * (lru_size==1) source block. Otherwise, we know that at least * option_srcwinsz bytes are available. Split the source window * into buffers. */ if ((lru = (main_blklru*)_xd3_alloc(NULL, MAX_LRU_SIZE, sizeof (main_blklru))) == NULL) { ret = ENOMEM; return ret; } memset (lru, 0, sizeof(lru[0]) * MAX_LRU_SIZE); /* Allocate the entire buffer. */ if ((lru[0].blk = (uint8_t*)_xd3_alloc(NULL, 1, option_srcwinsz))) { ret = ENOMEM; return ret; } /* Main calls _xd3_getblk_func() once before xd3_set_source(). This * is the point at which external decompression may begin. Set the * system for a single block. */ lru_size = 1; lru[0].blkno = (xoff_t) -1; blksize = option_srcwinsz; main_blklru_list_push_back (& lru_list, & lru[0]); XD3_ASSERT (blksize != 0); /* Initialize xd3_source. */ source->blksize = blksize; source->name = sfile->filename; source->ioh = sfile; source->curblkno = (xoff_t) -1; source->curblk = NULL; source->max_winsize = option_srcwinsz; if ((ret = _xd3_getblk_func (stream, source, 0)) != 0) { return ret; } source->onblk = lru[0].size; /* xd3 sets onblk */ /* If the file is smaller than a block, size is known. */ if (!sfile->size_known && source->onblk < blksize) { source_size = source->onblk; sfile->size_known = 1; } /* If the size is not known or is greater than the buffer size, we * split the buffer across MAX_LRU_SIZE blocks (already allocated in * "lru"). */ if (!sfile->size_known || source_size > option_srcwinsz) { /* Modify block 0, change blocksize. */ blksize = option_srcwinsz / MAX_LRU_SIZE; source->blksize = blksize; source->onblk = blksize; /* xd3 sets onblk */ /* Note: source->max_winsize is unchanged. */ lru[0].size = blksize; lru_size = MAX_LRU_SIZE; /* Setup rest of blocks. */ for (i = 1; i < lru_size; i += 1) { lru[i].blk = lru[0].blk + (blksize * i); lru[i].blkno = i; lru[i].size = blksize; main_blklru_list_push_back (& lru_list, & lru[i]); } } /* Call the appropriate set_source method, handle errors, print * verbose message, etc. */ if (sfile->size_known) { ret = xd3_set_source_and_size (stream, source, source_size); } else { ret = xd3_set_source (stream, source); } if (ret) { return ret; } return 0; }
int BinDiff(void *in, void *buffer, size_t size) { stream_p modified = ((bindiff_p)(in))->in2; diffdata_p data = (diffdata_p)(((bindiff_p)(in))->userdata); int retcode; int len_done = 0; // Alloc resources if needed if(data == NULL) { data = malloc(sizeof(diffdata_t)); xd3_init_config(&data->config, 0); data->config.winsize = BIN_DIFF_WINDOW_SIZE; data->config.getblk = &GetblkCallback; retcode = xd3_config_stream(&data->stream, &data->config); if (retcode != 0) return STREAM_EOF; data->source.ioh = in; data->source.curblkno = (xoff_t) -1; data->source.curblk = NULL; data->source.blksize = BIN_DIFF_WINDOW_SIZE; retcode = xd3_set_source(&data->stream, &data->source); if (retcode != 0) return STREAM_EOF; data->haveData = 0; data->reachedEOF = 0; data->org_cur = data->org_last = 0; ((bindiff_p)(in))->userdata = data; } if(data->haveData) { if((size_t)data->haveData >= size) { memcpy (buffer, &data->stream.next_out[data->stream.avail_out-data->haveData], size); data->haveData = data->haveData - size; return size; } else { memcpy (buffer, &data->stream.next_out[data->stream.avail_out-data->haveData], data->haveData); len_done = data->haveData; data->stream.avail_out = 0; data->haveData = 0; } } do { if(((bindiff_p)(in))->isPatch) retcode = xd3_decode_input(&data->stream); else retcode = xd3_encode_input(&data->stream); switch (retcode) { case XD3_INPUT: if(data->reachedEOF) return len_done ? len_done : STREAM_EOF; retcode = StreamRead(modified, data->inbuf, BIN_DIFF_WINDOW_SIZE); //fprintf(stderr,"\tXD3_INPUT (%i)\n", retcode); if (retcode == STREAM_EOF) { xd3_set_flags (&data->stream, XD3_FLUSH); data->reachedEOF = 1; retcode = 0; } xd3_avail_input(&data->stream, (uint8_t*)data->inbuf, retcode); continue; case XD3_OUTPUT: //fprintf(stderr,"\tXD3_OUTPUT (%i)\n", data->stream.avail_out); if(data->stream.avail_out >= (size-len_done)) { memcpy (((char *)buffer)+len_done, data->stream.next_out, size-len_done); data->haveData = data->stream.avail_out - size+len_done; return size; } else { memcpy (((char *)buffer)+len_done, data->stream.next_out, data->stream.avail_out); len_done += data->stream.avail_out; data->stream.avail_out = 0; data->haveData = 0; continue; } case XD3_GETSRCBLK: case XD3_GOTHEADER: case XD3_WINSTART: case XD3_WINFINISH: continue; default: //fprintf(stderr,"\terror: %s\n", data->stream.msg); return STREAM_EOF; } } while (1); }