Add error messaging

This commit is contained in:
C-3PO 2018-09-14 01:41:35 +02:00
parent 65bb5a98e3
commit 0ce4fcf492
Signed by: c3po
GPG key ID: 62993C4BB4D86F24
8 changed files with 75 additions and 28 deletions

View file

@ -7,7 +7,8 @@
"fileutilities.h": "c", "fileutilities.h": "c",
"stdio.h": "c", "stdio.h": "c",
"stdlib.h": "c", "stdlib.h": "c",
"stdbool.h": "c" "stdbool.h": "c",
"errorandexit.h": "c"
}, },
"cSpell.words": [ "cSpell.words": [
"init", "init",

View file

@ -11,7 +11,7 @@ To compile:
To use: 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 # Dependencies

16
src/errorAndExit.c Normal file
View file

@ -0,0 +1,16 @@
#include <stdio.h>
#include <stdlib.h>
#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);
}

1
src/errorAndExit.h Normal file
View file

@ -0,0 +1 @@
void errorAndExit();

View file

@ -3,6 +3,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "errorAndExit.h"
#include "fileReader.h" #include "fileReader.h"
#include "utils/fileUtilities.h" #include "utils/fileUtilities.h"
#include "utils/min.h" #include "utils/min.h"
@ -13,8 +14,8 @@ void initFileReader(char path[], unsigned long offset) {
file.filePointer = fopen(file.name, "r"); file.filePointer = fopen(file.name, "r");
if (file.filePointer == NULL) { if (file.filePointer == NULL) {
fprintf(stderr, "Could not open file %s for reading: %s\n", file.name, strerror(errno)); fprintf(stderr, "Could not open file \"%s\" for reading: %s\n", file.name, strerror(errno));
exit(1); errorAndExit();
} }
//get file size //get file size

View file

@ -11,6 +11,7 @@
#define MINIZ_NO_MALLOC #define MINIZ_NO_MALLOC
#include "../lib/miniz/miniz.h" #include "../lib/miniz/miniz.h"
#include "errorAndExit.h"
#include "inflate.h" #include "inflate.h"
//The compressed and uncompressed buffer arrays //The compressed and uncompressed buffer arrays
@ -85,7 +86,7 @@ struct InflateOutput inflateInflate(unsigned long numInputBytes, bool hasMoreByt
} else { } else {
// Decompression failed. // Decompression failed.
fprintf(stderr, "tinfl_decompress() failed with status %i!\n", status); fprintf(stderr, "tinfl_decompress() failed with status %i!\n", status);
exit(1); errorAndExit();
} }
} }

View file

@ -6,24 +6,29 @@
//Import our code //Import our code
#include "decrypt.h" #include "decrypt.h"
#include "errorAndExit.h"
#include "fileReader.h" #include "fileReader.h"
#include "inflate.h" #include "inflate.h"
#include "parseArguments.h" #include "parseArguments.h"
#include "utils/min.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 #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 #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 #define LOCAL_FILE_HEADER_MAGIC (uint32_t)0x04034b50
//Convenience functions for reading integers from a char array
uint16_t getUint16(uint8_t* buffer) { uint16_t getUint16(uint8_t* buffer) {
return (uint16_t)buffer[0] | \ return ((uint16_t)buffer[0]) | \
(uint16_t)buffer[1] << 8; ((uint16_t)buffer[1]) << 8;
} }
uint32_t getUint32(uint8_t* buffer) { uint32_t getUint32(uint8_t* buffer) {
return (uint32_t)buffer[0] | \ return ((uint32_t)buffer[0]) | \
(uint32_t)buffer[1] << 8 | \ ((uint32_t)buffer[1]) << 8 | \
(uint32_t)buffer[2] << 16 | \ ((uint32_t)buffer[2]) << 16 | \
(uint32_t)buffer[3] << 24; ((uint32_t)buffer[3]) << 24;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -35,13 +40,13 @@ int main(int argc, char *argv[]) {
uint8_t* compressedChunk = malloc(BUFFER_SIZE); uint8_t* compressedChunk = malloc(BUFFER_SIZE);
if (compressedChunk == NULL) { if (compressedChunk == NULL) {
fprintf(stderr, "Could not allocate %lu bytes for compressed buffer.\n", BUFFER_SIZE); fprintf(stderr, "Could not allocate %lu bytes for compressed buffer.\n", BUFFER_SIZE);
exit(1); errorAndExit();
} }
uint8_t* uncompressedChunk = malloc(BUFFER_SIZE); uint8_t* uncompressedChunk = malloc(BUFFER_SIZE);
if (uncompressedChunk == NULL) { if (uncompressedChunk == NULL) {
fprintf(stderr, "Could not allocate %lu bytes for uncompressed buffer.\n", BUFFER_SIZE); fprintf(stderr, "Could not allocate %lu bytes for uncompressed buffer.\n", BUFFER_SIZE);
exit(1); errorAndExit();
} }
memset(uncompressedChunk, (uint8_t)0, BUFFER_SIZE); memset(uncompressedChunk, (uint8_t)0, BUFFER_SIZE);
@ -55,8 +60,8 @@ int main(int argc, char *argv[]) {
//Check that header is correct //Check that header is correct
const uint32_t magic = getUint32(compressedChunk); const uint32_t magic = getUint32(compressedChunk);
if (magic != LOCAL_FILE_HEADER_MAGIC) { if (magic != LOCAL_FILE_HEADER_MAGIC) {
fprintf(stderr, "Wrong magic in local file header, expected %#010x but found %#010x.", LOCAL_FILE_HEADER_MAGIC, magic); fprintf(stderr, "Wrong magic in local file header, expected %#010x but found %#010x.\n", LOCAL_FILE_HEADER_MAGIC, magic);
exit(1); errorAndExit();
} }
//Read additional length //Read additional length
const unsigned long additionalLength = getUint16(compressedChunk + 26) + getUint16(compressedChunk + 28); 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 //Decrypt file if it is encrypted
if (state.isEncrypted) { if (state.isEncrypted) {
//TODO: For highest performance, we need to move if condition outside of while loop
decrypt(compressedChunk, chunkSize); decrypt(compressedChunk, chunkSize);
} }
} }

View file

@ -3,8 +3,11 @@
#include <stdlib.h> #include <stdlib.h>
#include "decrypt.h" #include "decrypt.h"
#include "errorAndExit.h"
#include "parseArguments.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[] = { static struct option long_options[] = {
{"disk", required_argument, 0, 'd'}, {"disk", required_argument, 0, 'd'},
{"offset", required_argument, 0, 'o'}, {"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 //Stores current state from command line arguments, initialized to zero
struct arguments state = {}; struct arguments state = {};
int requiredOptions = 0; bool hasDisk = false;
bool hasOffset = false;
bool hasSize = false;
while (1) { while (1) {
//in this variable, getopt_long stores the current position in the command line args array //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 option_index = 0; 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 //end of command line arguments reached
if (curOption == -1) { if (curOption == -1) {
@ -34,15 +39,15 @@ struct arguments parseArguments(int argc, char *argv[]) {
switch (curOption) { switch (curOption) {
case 'd': //disk name case 'd': //disk name
state.diskName = optarg; state.diskName = optarg;
requiredOptions |= 1; hasDisk = true;
break; break;
case 'o': //offset case 'o': //offset
state.diskOffset = atol(optarg); state.diskOffset = atol(optarg);
requiredOptions |= 2; hasOffset = true;
break; break;
case 's': //size case 's': //size
state.fileSize = atol(optarg); state.fileSize = atol(optarg);
requiredOptions |= 4; hasSize = true;
break; break;
case 'k': { //decryption keys case 'k': { //decryption keys
//TODO: parse from optarg //TODO: parse from optarg
@ -57,15 +62,33 @@ struct arguments parseArguments(int argc, char *argv[]) {
case 'p': //prev file for xdelta3 case 'p': //prev file for xdelta3
//TODO //TODO
break; break;
case '?':
errorAndExit();
break;
default: default:
fprintf(stderr, "Unknown option '%c'.", (char)curOption); fprintf(stderr, "Unknown option '%c'.\n", (char)curOption);
exit(1); errorAndExit();
} }
} }
if (requiredOptions != 7) { if (!hasDisk) {
fprintf(stderr, "Missing arguments, received %i.", requiredOptions); fprintf(stderr, "Missing required argument --disk.\n");
exit(1); 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; return state;