✨ Add error messaging
This commit is contained in:
parent
65bb5a98e3
commit
0ce4fcf492
8 changed files with 75 additions and 28 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
16
src/errorAndExit.c
Normal file
16
src/errorAndExit.c
Normal 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
1
src/errorAndExit.h
Normal file
|
@ -0,0 +1 @@
|
|||
void errorAndExit();
|
|
@ -3,6 +3,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
26
src/main.c
26
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
|
|
Loading…
Reference in a new issue