✨ 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",
|
"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",
|
||||||
|
|
|
@ -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
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 <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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
src/main.c
26
src/main.c
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue