Allow extracted file to be output to file instead of stdout

This commit is contained in:
C-3PO 2018-09-16 02:33:30 +02:00
parent 1897ab3813
commit 3f5a52a070
Signed by: c3po
GPG key ID: 62993C4BB4D86F24
7 changed files with 36 additions and 9 deletions

View file

@ -2,7 +2,7 @@
If this is not a ```-1to0``` patch, the disk file may only contain the differences to the previous release. In this case, you can supply the location of this file's previous version, and this tool will generate the new version using VCDIFF/xdelta3. If this is not a ```-1to0``` patch, the disk file may only contain the differences to the previous release. In this case, you can supply the location of this file's previous version, and this tool will generate the new version using VCDIFF/xdelta3.
In all cases, the extracted file is written to stdout. From there, you can either dump it to disk or process it in memory. If a target location is specified, the extracted file is saved to that location, otherwise it is written to stdout. From there, you can either dump it to disk or process it in memory.
# Usage # Usage

View file

@ -12,5 +12,6 @@ void errorAndExit() {
fprintf(stderr, " -s, --size: The stored size of the file we want to extract (= the compressed size). After inflation, the file will likely be bigger than this.\n"); fprintf(stderr, " -s, --size: The stored size of the file we want to extract (= the compressed size). After inflation, the file will likely be bigger than this.\n");
fprintf(stderr, " -k, --keys: Optionally, the three decryption keys used to decrypt the file before inflation.\n"); fprintf(stderr, " -k, --keys: Optionally, the three decryption keys used to decrypt the file before inflation.\n");
fprintf(stderr, " -p, --previous: Optionally, the location of the previous version of this file, in case this disk only contains the xdelta3 differences and not an actual file.\n"); fprintf(stderr, " -p, --previous: Optionally, the location of the previous version of this file, in case this disk only contains the xdelta3 differences and not an actual file.\n");
fprintf(stderr, " -t, --target: The path where the extracted file is saved to. If not specified, the file is outputted to stdout.\n");
exit(1); exit(1);
} }

View file

@ -1,3 +1,4 @@
#include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -84,6 +85,16 @@ int main(int argc, char *argv[]) {
xdelta3Init(state.prevFile); xdelta3Init(state.prevFile);
} }
//If a target path is specified, create a file write stream
FILE* targetFile;
if (state.target) {
targetFile = fopen(state.target, "wb");
if (!targetFile) {
fprintf(stderr, "Could not open the target file \"%s\" for writing: %s\n", state.target, strerror(errno));
errorAndExit();
}
}
//------------------------------------------------- //-------------------------------------------------
struct InflateOutput inflateResult; struct InflateOutput inflateResult;
@ -116,10 +127,14 @@ int main(int argc, char *argv[]) {
//Optionally perform xdelta3 //Optionally perform xdelta3
if (state.prevFile) { if (state.prevFile) {
xdelta3AddInput(uncompressedChunk + uncompressedPosition, inflateResult.numBytesWrittenToOutput, remainingBytes == 0 && hasReachedEnd); xdelta3AddInput(uncompressedChunk + uncompressedPosition, inflateResult.numBytesWrittenToOutput, remainingBytes == 0 && hasReachedEnd, targetFile);
} else { //otherwise write to stdout } else { //otherwise write to target file or stdout
if (state.target) {
fwrite(uncompressedChunk + uncompressedPosition, 1, inflateResult.numBytesWrittenToOutput, targetFile);
} else {
write(1, uncompressedChunk + uncompressedPosition, inflateResult.numBytesWrittenToOutput); write(1, uncompressedChunk + uncompressedPosition, inflateResult.numBytesWrittenToOutput);
} }
}
uncompressedPosition += inflateResult.numBytesWrittenToOutput; uncompressedPosition += inflateResult.numBytesWrittenToOutput;
while (uncompressedPosition >= BUFFER_SIZE) { while (uncompressedPosition >= BUFFER_SIZE) {

View file

@ -15,6 +15,7 @@ static struct option long_options[] = {
{"size", required_argument, 0, 's'}, {"size", required_argument, 0, 's'},
{"keys", required_argument, 0, 'k'}, {"keys", required_argument, 0, 'k'},
{"previous", required_argument, 0, 'p'}, {"previous", required_argument, 0, 'p'},
{"target", required_argument, 0, 't'},
{NULL, 0, 0, 0}, {NULL, 0, 0, 0},
}; };
@ -31,7 +32,7 @@ struct arguments parseArguments(int argc, char *argv[]) {
//In this variable, getopt_long stores the current long option that was found. Unused since we don't use flags in our long options //In this variable, getopt_long stores the current long option that was found. Unused since we don't use flags in our long options
int optionIndex = 0; int optionIndex = 0;
int curOption = getopt_long_only(argc, argv, "d:o:s:k:p:", long_options, &optionIndex); int curOption = getopt_long_only(argc, argv, "d:o:s:k:p:t:", long_options, &optionIndex);
//end of command line arguments reached //end of command line arguments reached
if (curOption == -1) { if (curOption == -1) {
@ -77,6 +78,9 @@ struct arguments parseArguments(int argc, char *argv[]) {
case 'p': //previous file for xdelta3 case 'p': //previous file for xdelta3
state.prevFile = optarg; state.prevFile = optarg;
break; break;
case 't': //target file path where extracted file is saved to
state.target = optarg;
break;
case '?': case '?':
errorAndExit(); errorAndExit();
break; break;

View file

@ -15,6 +15,8 @@ struct arguments {
bool isEncrypted; bool isEncrypted;
//For xdelta3, the location of the old file //For xdelta3, the location of the old file
char* prevFile; char* prevFile;
//Target file location where the extracted file is saved to
char* target;
}; };

View file

@ -9,6 +9,7 @@ typedef unsigned long long xoff_t;
#include "../lib/xdelta3/xdelta3.c" #include "../lib/xdelta3/xdelta3.c"
//Include other libraries //Include other libraries
#include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h> #include <unistd.h>
@ -29,7 +30,7 @@ unsigned long totalOut = 0UL;
void xdelta3Init(char* prevFile) { void xdelta3Init(char* prevFile) {
srcFile = fopen(prevFile, "rb"); srcFile = fopen(prevFile, "rb");
if (srcFile == NULL) { if (srcFile == NULL) {
fprintf(stderr, "Could not open previous file %s for reading during xdelta3.\n", prevFile); fprintf(stderr, "Could not open previous file %s for reading during xdelta3: %s\n", prevFile, strerror(errno));
errorAndExit(); errorAndExit();
} }
@ -54,7 +55,7 @@ void xdelta3Init(char* prevFile) {
/** Supplies the given input buffer to xdelta3 and undiffs the data. */ /** Supplies the given input buffer to xdelta3 and undiffs the data. */
void xdelta3AddInput(unsigned char* inputBuffer, unsigned int inputLength, bool isLastPart) { void xdelta3AddInput(unsigned char* inputBuffer, unsigned int inputLength, bool isLastPart, FILE* targetFile) {
xd3_avail_input(&stream, inputBuffer, inputLength); xd3_avail_input(&stream, inputBuffer, inputLength);
int returnValue; int returnValue;
@ -69,7 +70,11 @@ process:
case XD3_OUTPUT: { case XD3_OUTPUT: {
//fprintf(stderr, "XD3_OUTPUT\n"); //fprintf(stderr, "XD3_OUTPUT\n");
totalOut += stream.avail_out; totalOut += stream.avail_out;
if (targetFile) {
fwrite(stream.next_out, 1, stream.avail_out, targetFile);
} else {
write(1, stream.next_out, stream.avail_out); write(1, stream.next_out, stream.avail_out);
}
xd3_consume_output(&stream); xd3_consume_output(&stream);
goto process; goto process;
} }

View file

@ -4,4 +4,4 @@
void xdelta3Init(char* prevFile); void xdelta3Init(char* prevFile);
/** Supplies the given input buffer to xdelta3 and undiffs the data. */ /** Supplies the given input buffer to xdelta3 and undiffs the data. */
void xdelta3AddInput(unsigned char* inputBuffer, unsigned int inputLength, bool isLastPart); void xdelta3AddInput(unsigned char* inputBuffer, unsigned int inputLength, bool isLastPart, FILE* targetFile);