From 0ce4fcf492c68a5e8e680db1a497df0ddaaabb29 Mon Sep 17 00:00:00 2001 From: C-3PO Date: Fri, 14 Sep 2018 01:41:35 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20error=20messaging?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 ++- README.md | 2 +- src/errorAndExit.c | 16 +++++++++++++++ src/errorAndExit.h | 1 + src/fileReader.c | 5 +++-- src/inflate.c | 3 ++- src/main.c | 26 ++++++++++++++---------- src/parseArguments.c | 47 ++++++++++++++++++++++++++++++++----------- 8 files changed, 75 insertions(+), 28 deletions(-) create mode 100644 src/errorAndExit.c create mode 100644 src/errorAndExit.h diff --git a/.vscode/settings.json b/.vscode/settings.json index 505d4d4..2e280e6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,7 +7,8 @@ "fileutilities.h": "c", "stdio.h": "c", "stdlib.h": "c", - "stdbool.h": "c" + "stdbool.h": "c", + "errorandexit.h": "c" }, "cSpell.words": [ "init", diff --git a/README.md b/README.md index 8cdbd41..5e8b9d5 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ To compile: To use: ``` -./patcher-installer --disk /tmp/patcher/cdn-patch.swtor.com/patch/assets_swtor_main/assets_swtor_main_-1to0/assets_swtor_main_-1to0.z08 --offset 267071107 --size 165738618 --keys 3393608425 2820264972 3930508185 > ../swtor_main_gfx_1.tor +./patcher-installer --disk /tmp/patcher/cdn-patch.swtor.com/patch/assets_swtor_main/assets_swtor_main_-1to0/assets_swtor_main_-1to0.z08 --offset 267071107 --size 165738618 --keys 3393608425,2820264972,3930508185 > ../swtor_main_gfx_1.tor ``` # Dependencies diff --git a/src/errorAndExit.c b/src/errorAndExit.c new file mode 100644 index 0000000..2430ab2 --- /dev/null +++ b/src/errorAndExit.c @@ -0,0 +1,16 @@ +#include +#include + +#include "errorAndExit.h" + +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, "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"); + 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, " -p, --prev: 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"); + exit(1); +} diff --git a/src/errorAndExit.h b/src/errorAndExit.h new file mode 100644 index 0000000..106e68b --- /dev/null +++ b/src/errorAndExit.h @@ -0,0 +1 @@ +void errorAndExit(); diff --git a/src/fileReader.c b/src/fileReader.c index 3491db5..fcff997 100644 --- a/src/fileReader.c +++ b/src/fileReader.c @@ -3,6 +3,7 @@ #include #include +#include "errorAndExit.h" #include "fileReader.h" #include "utils/fileUtilities.h" #include "utils/min.h" @@ -13,8 +14,8 @@ void initFileReader(char path[], unsigned long offset) { file.filePointer = fopen(file.name, "r"); if (file.filePointer == NULL) { - fprintf(stderr, "Could not open file %s for reading: %s\n", file.name, strerror(errno)); - exit(1); + fprintf(stderr, "Could not open file \"%s\" for reading: %s\n", file.name, strerror(errno)); + errorAndExit(); } //get file size diff --git a/src/inflate.c b/src/inflate.c index 72f75b3..b1f7c4a 100644 --- a/src/inflate.c +++ b/src/inflate.c @@ -11,6 +11,7 @@ #define MINIZ_NO_MALLOC #include "../lib/miniz/miniz.h" +#include "errorAndExit.h" #include "inflate.h" //The compressed and uncompressed buffer arrays @@ -85,7 +86,7 @@ struct InflateOutput inflateInflate(unsigned long numInputBytes, bool hasMoreByt } else { // Decompression failed. fprintf(stderr, "tinfl_decompress() failed with status %i!\n", status); - exit(1); + errorAndExit(); } } diff --git a/src/main.c b/src/main.c index b2744ff..07a9a9c 100644 --- a/src/main.c +++ b/src/main.c @@ -6,24 +6,29 @@ //Import our code #include "decrypt.h" +#include "errorAndExit.h" #include "fileReader.h" #include "inflate.h" #include "parseArguments.h" #include "utils/min.h" +//The size of the buffers where the compressed and uncompressed data is stored #define BUFFER_SIZE 512UL * 1024UL //512 KiB +//If a file is encrypted, there are 12 random bytes before the start of the file contents #define ENCRYPTION_HEADER_LENGTH 12UL +//Each local file header in a .zip file has the magic bytes "50 4b 03 04" at the beginning #define LOCAL_FILE_HEADER_MAGIC (uint32_t)0x04034b50 +//Convenience functions for reading integers from a char array uint16_t getUint16(uint8_t* buffer) { - return (uint16_t)buffer[0] | \ - (uint16_t)buffer[1] << 8; + return ((uint16_t)buffer[0]) | \ + ((uint16_t)buffer[1]) << 8; } uint32_t getUint32(uint8_t* buffer) { - return (uint32_t)buffer[0] | \ - (uint32_t)buffer[1] << 8 | \ - (uint32_t)buffer[2] << 16 | \ - (uint32_t)buffer[3] << 24; + return ((uint32_t)buffer[0]) | \ + ((uint32_t)buffer[1]) << 8 | \ + ((uint32_t)buffer[2]) << 16 | \ + ((uint32_t)buffer[3]) << 24; } int main(int argc, char *argv[]) { @@ -35,13 +40,13 @@ int main(int argc, char *argv[]) { uint8_t* compressedChunk = malloc(BUFFER_SIZE); if (compressedChunk == NULL) { fprintf(stderr, "Could not allocate %lu bytes for compressed buffer.\n", BUFFER_SIZE); - exit(1); + errorAndExit(); } uint8_t* uncompressedChunk = malloc(BUFFER_SIZE); if (uncompressedChunk == NULL) { fprintf(stderr, "Could not allocate %lu bytes for uncompressed buffer.\n", BUFFER_SIZE); - exit(1); + errorAndExit(); } memset(uncompressedChunk, (uint8_t)0, BUFFER_SIZE); @@ -55,8 +60,8 @@ int main(int argc, char *argv[]) { //Check that header is correct const uint32_t magic = getUint32(compressedChunk); if (magic != LOCAL_FILE_HEADER_MAGIC) { - fprintf(stderr, "Wrong magic in local file header, expected %#010x but found %#010x.", LOCAL_FILE_HEADER_MAGIC, magic); - exit(1); + fprintf(stderr, "Wrong magic in local file header, expected %#010x but found %#010x.\n", LOCAL_FILE_HEADER_MAGIC, magic); + errorAndExit(); } //Read additional length const unsigned long additionalLength = getUint16(compressedChunk + 26) + getUint16(compressedChunk + 28); @@ -89,7 +94,6 @@ int main(int argc, char *argv[]) { //Decrypt file if it is encrypted if (state.isEncrypted) { - //TODO: For highest performance, we need to move if condition outside of while loop decrypt(compressedChunk, chunkSize); } } diff --git a/src/parseArguments.c b/src/parseArguments.c index 04942c1..1597ee6 100644 --- a/src/parseArguments.c +++ b/src/parseArguments.c @@ -3,8 +3,11 @@ #include #include "decrypt.h" +#include "errorAndExit.h" #include "parseArguments.h" +//Uses GNU's getopt_long_only(), see https://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Options.html + static struct option long_options[] = { {"disk", required_argument, 0, 'd'}, {"offset", required_argument, 0, 'o'}, @@ -18,13 +21,15 @@ struct arguments parseArguments(int argc, char *argv[]) { //Stores current state from command line arguments, initialized to zero struct arguments state = {}; - int requiredOptions = 0; + bool hasDisk = false; + bool hasOffset = false; + bool hasSize = false; while (1) { - //in this variable, getopt_long stores the current position in the command line args array - int option_index = 0; + //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 curOption = getopt_long(argc, argv, "d:o:s:k:p:", long_options, &option_index); + int curOption = getopt_long_only(argc, argv, "d:o:s:k:p:", long_options, &optionIndex); //end of command line arguments reached if (curOption == -1) { @@ -34,15 +39,15 @@ struct arguments parseArguments(int argc, char *argv[]) { switch (curOption) { case 'd': //disk name state.diskName = optarg; - requiredOptions |= 1; + hasDisk = true; break; case 'o': //offset state.diskOffset = atol(optarg); - requiredOptions |= 2; + hasOffset = true; break; case 's': //size state.fileSize = atol(optarg); - requiredOptions |= 4; + hasSize = true; break; case 'k': { //decryption keys //TODO: parse from optarg @@ -57,15 +62,33 @@ struct arguments parseArguments(int argc, char *argv[]) { case 'p': //prev file for xdelta3 //TODO break; + case '?': + errorAndExit(); + break; default: - fprintf(stderr, "Unknown option '%c'.", (char)curOption); - exit(1); + fprintf(stderr, "Unknown option '%c'.\n", (char)curOption); + errorAndExit(); } } - if (requiredOptions != 7) { - fprintf(stderr, "Missing arguments, received %i.", requiredOptions); - exit(1); + if (!hasDisk) { + fprintf(stderr, "Missing required argument --disk.\n"); + errorAndExit(); + } + + if (!hasOffset) { + fprintf(stderr, "Missing required argument --offset.\n"); + errorAndExit(); + } + + if (!hasSize) { + fprintf(stderr, "Missing required argument --size.\n"); + errorAndExit(); + } + + if (optind < argc) { + fprintf(stderr, "Found %i arguments without an option. All arguments must be preceded by an option.\n", argc - optind); + errorAndExit(); } return state;