#include #include #include #include #include #include //Import our code #include "decrypt.h" #include "fileReader.h" #include "inflate.h" #include "utils/min.h" #define BUFFER_SIZE 512UL * 1024UL //512 KiB #define ENCRYPTION_HEADER_LENGTH 12UL #define LOCAL_FILE_HEADER_MAGIC (uint32_t)0x04034b50 uint16_t getUint16(char* buffer) { return (uint16_t)buffer[0] | \ (uint16_t)buffer[1] << 8; } uint32_t getUint32(char* buffer) { return (uint32_t)buffer[0] | \ (uint32_t)buffer[1] << 8 | \ (uint32_t)buffer[2] << 16 | \ (uint32_t)buffer[3] << 24; } int main(int argc, unsigned char *argv[]) { if (argc != 4 && argc != 7) { fprintf(stderr, "Wrong number of arguments. Usage: patcher-installer [ ]"); exit(1); } //TODO: verify argv and assign it to variables char* archiveName = argv[1]; const unsigned long archiveOffset = atol(argv[2]); const unsigned long fileLength = atol(argv[3]); const bool isEncrypted = argc == 7; if (isEncrypted) { uint32_t key0 = atoi(argv[4]); uint32_t key1 = atoi(argv[5]); uint32_t key2 = atoi(argv[6]); //Initialize decryption (pass decryption keys) initDecryptor(key0, key1, key2); } //------------------------------------------------- char* compressedChunk = malloc(BUFFER_SIZE); if (compressedChunk == NULL) { fprintf(stderr, "Could not allocate %lu bytes for compressed buffer.\n", BUFFER_SIZE); exit(1); } char* uncompressedChunk = malloc(BUFFER_SIZE); if (uncompressedChunk == NULL) { fprintf(stderr, "Could not allocate %lu bytes for uncompressed buffer.\n", BUFFER_SIZE); exit(1); } //------------------------------------------------- //Initialize file reader initFileReader(archiveName, archiveOffset); //Skip local file header (30 bytes + additional length) getBytes(compressedChunk, 30UL); //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); } //Read additional length const unsigned long additionalLength = getUint16(compressedChunk + 26) + getUint16(compressedChunk + 28); getBytes(compressedChunk, additionalLength); //If file is encrypted, skip 12-byte encryption header if (isEncrypted) { getBytes(compressedChunk, ENCRYPTION_HEADER_LENGTH); decrypt(compressedChunk, ENCRYPTION_HEADER_LENGTH); } //------------------------------------------------- struct InflateOutput inflateResult; inflateInit(compressedChunk, uncompressedChunk, BUFFER_SIZE); //Read actual file unsigned long remainingBytes = fileLength; bool needToRead = true; unsigned long chunkSize; while (remainingBytes > 0) { if (needToRead) { chunkSize = min(BUFFER_SIZE, remainingBytes); getBytes(compressedChunk, chunkSize); remainingBytes -= chunkSize; //Decrypt file if it is encrypted if (isEncrypted) { //TODO: For highest performance, we need to move if condition outside of while loop decrypt(compressedChunk, chunkSize); } } //Decompress file //bytes are contained in uncompressedChunk from [0, inflateResult.numBytesWrittenToOutput - 1] inflateResult = inflateInflate(needToRead ? chunkSize : 0, remainingBytes > 0); needToRead = inflateResult.needMoreInput; write(1, uncompressedChunk, inflateResult.numBytesWrittenToOutput); //Optionally perform xdelta3 //TODO } //release memory free(compressedChunk); free(uncompressedChunk); return 0; }