diff --git a/lib/xdelta3/xdelta3-internal.h b/lib/xdelta3/xdelta3-internal.h index 0c6a1bb..f2cf6e2 100644 --- a/lib/xdelta3/xdelta3-internal.h +++ b/lib/xdelta3/xdelta3-internal.h @@ -37,7 +37,7 @@ int main_file_read (main_file *ifile, size_t size, size_t *nread, const char *msg); -int main_file_write (main_file *ofile, uint8_t *buf, +int main_file_write (main_file *ofile, uint8_t *buf, usize_t size, const char *msg); void* main_malloc (size_t size); void main_free (void *ptr); diff --git a/src/errorAndExit.c b/src/errorAndExit.c index f0493a3..1af7287 100644 --- a/src/errorAndExit.c +++ b/src/errorAndExit.c @@ -5,7 +5,7 @@ void errorAndExit() { fprintf(stderr, "\nUsage:\n"); - fprintf(stderr, " ./patcher-installer --disk main.z01 --offset 456z --size 1000 [--keys 123,123,123] [--prev oldfile.tor]\n"); + fprintf(stderr, " ./patcher-installer --disk main.z01 --offset 456z --size 1000 [--keys 123,456,789] [--previous oldfile.tor]\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -d, --disk: The path to the disk file that contains the file we want to extract.\n"); fprintf(stderr, " -o, --offset: The offset into the disk, given in bytes, where the local file header of the file we want to extract starts.\n"); diff --git a/src/main.c b/src/main.c index 7ab3627..eff7cf8 100644 --- a/src/main.c +++ b/src/main.c @@ -5,12 +5,13 @@ #include //Import our code +#include "utils/min.h" #include "decrypt.h" #include "errorAndExit.h" #include "fileReader.h" #include "inflate.h" #include "parseArguments.h" -#include "utils/min.h" +#include "xdelta3.h" //The size of the buffers where the compressed and uncompressed data is stored #define BUFFER_SIZE 512UL * 1024UL //512 KiB @@ -75,6 +76,11 @@ int main(int argc, char *argv[]) { decrypt(compressedChunk, ENCRYPTION_HEADER_LENGTH); } + //Initialize xdelta3 + if (state.prevFile) { + xdelta3Init(state.prevFile); + } + //------------------------------------------------- struct InflateOutput inflateResult; @@ -106,19 +112,17 @@ int main(int argc, char *argv[]) { //important: we must not modify uncompressedChunk since miniz may use it as dictionary and read from it during the next invocation of inflateInflate() - //Write to stdout - write(1, uncompressedChunk + uncompressedPosition, inflateResult.numBytesWrittenToOutput); + //Optionally perform xdelta3 + if (state.prevFile) { + xdelta3AddInput(uncompressedChunk + uncompressedPosition, inflateResult.numBytesWrittenToOutput, remainingBytes == 0 && hasReachedEnd); + } else { //otherwise write to stdout + write(1, uncompressedChunk + uncompressedPosition, inflateResult.numBytesWrittenToOutput); + } + uncompressedPosition += inflateResult.numBytesWrittenToOutput; while (uncompressedPosition >= BUFFER_SIZE) { uncompressedPosition -= BUFFER_SIZE; } - - //Optionally perform xdelta3 - if (state.prevFile) { - //TODO - fprintf(stderr, "xdelta3 is not yet implemented.\n"); - errorAndExit(); - } } //release memory diff --git a/src/xdelta3.c b/src/xdelta3.c index 9a8a2f7..b66cde8 100644 --- a/src/xdelta3.c +++ b/src/xdelta3.c @@ -2,7 +2,107 @@ #define SIZEOF_SIZE_T 4 #define static_assert(e,m) /* do nothing */ #define XD3_ENCODER 0 +#define XD3_USE_LARGESIZET 0 typedef unsigned int usize_t; typedef unsigned long long xoff_t; +//Include xdelta3 +#include "../lib/xdelta3/xdelta3.c" -#include "../lib/xdelta3/xdelta3.h" +//Include other libraries +#include +#include + +//Include our own files +#include "errorAndExit.h" +#include "xdelta3.h" + +//Various variables for Xdelta3 +xd3_stream stream; +xd3_config config; +xd3_source source; +//The previous version of the file we want to extract +FILE* srcFile; +//Total number of bytes written to output +unsigned long totalOut = 0UL; + +/** Initializes xdelta3 with the given previous file */ +void xdelta3Init(char* prevFile) { + srcFile = fopen(prevFile, "rb"); + if (srcFile == NULL) { + fprintf(stderr, "Could not open previous file %s for reading during xdelta3.\n", prevFile); + errorAndExit(); + } + + xd3_init_config(&config, XD3_ADLER32); + config.winsize = XD3_ALLOCSIZE; + xd3_config_stream(&stream, &config); + //Set source (= old file from previous release) + source.blksize = XD3_ALLOCSIZE; + source.curblk = malloc(source.blksize); + if (source.curblk == NULL) { + fprintf(stderr, "ERROR: Could not allocate source.blksize in VCDIFF.\n"); + errorAndExit(); + } + + fseek(srcFile, 0, SEEK_SET); + source.onblk = fread((void*)source.curblk, 1, source.blksize, srcFile); + source.curblkno = 0; + xd3_set_source(&stream, &source); + //Set input (= xdelta file from current release) + xd3_set_flags(&stream, XD3_FLUSH | stream.flags); +} + + +/** Supplies the given input buffer to xdelta3 and undiffs the data. */ +void xdelta3AddInput(unsigned char* inputBuffer, unsigned int inputLength, bool isLastPart) { + xd3_avail_input(&stream, inputBuffer, inputLength); + + int returnValue; + +process: + returnValue = xd3_decode_input(&stream); + switch (returnValue) { + case XD3_INPUT: { + //fprintf(stderr, "XD3_INPUT\n"); + break; + } + case XD3_OUTPUT: { + //fprintf(stderr, "XD3_OUTPUT\n"); + totalOut += stream.avail_out; + write(1, stream.next_out, stream.avail_out); + xd3_consume_output(&stream); + goto process; + } + case XD3_GETSRCBLK: { + //fprintf(stderr, "XD3_GETSRCBLK\n"); + fseek(srcFile, source.blksize * source.getblkno, SEEK_SET); + source.onblk = fread((void*)source.curblk, 1, source.blksize, srcFile); + source.curblkno = source.getblkno; + goto process; + } + case XD3_GOTHEADER: { + //fprintf(stderr, "XD3_GOTHEADER\n"); + goto process; + } + case XD3_WINSTART: { + //fprintf(stderr, "XD3_WINSTART\n"); + goto process; + } + case XD3_WINFINISH: { + //fprintf(stderr, "XD3_WINFINISH\n"); + goto process; + } + default: { + fprintf(stderr, "ERROR: !!! INVALID %s %d !!!\n", stream.msg, returnValue); + errorAndExit(); + } + } + + //If we are done, free up memory + if (isLastPart) { + free((void*)source.curblk); + xd3_close_stream(&stream); + xd3_free_stream(&stream); + fclose(srcFile); + } +} diff --git a/src/xdelta3.h b/src/xdelta3.h new file mode 100644 index 0000000..20e7014 --- /dev/null +++ b/src/xdelta3.h @@ -0,0 +1,7 @@ +#pragma once + +/** Initializes xdelta3 with the given previous file */ +void xdelta3Init(char* prevFile); + +/** Supplies the given input buffer to xdelta3 and undiffs the data. */ +void xdelta3AddInput(unsigned char* inputBuffer, unsigned int inputLength, bool isLastPart);