#include #include #include #include typedef unsigned char byte; typedef struct { byte* buffer; long length; } block; const char memoryError[] = "No enough memory\n"; long fileSize(const char *fileName) { FILE *f = fopen(fileName, "rb"); long size; if (f == NULL) { printf("Cannot access file \"%s\" for establishing size\n", fileName); return -1; } if (fseek(f, 0, SEEK_END)) { printf("Cannot set position in file \"%s\" at the end\n", fileName); fclose(f); return -2; } size = ftell(f); if (size == -1) { printf("Cannot establish size of file \"%s\"\n", fileName); fclose(f); return -3; } return size; } int read(const char *fileName, block *buffer) { FILE *f = fopen(fileName, "rb"); long size; byte *buff; if (f == NULL) { printf("Cannot open file \"%s\" for reading\n", fileName); return 1; } size = fileSize(fileName); if (size < 0) { return size; } buff = (byte*) malloc(size); if (buff == NULL) { printf(memoryError); fclose(f); return 4; } if (fseek(f, 0, SEEK_SET)) { printf("Cannot positioning file \"%s\" for reading from begin\n", fileName); fclose(f); free(buff); return 5; } if (fread(buff, 1, size, f) != (size_t) size) { printf("Error in reading from file \"%s\"\n", fileName); fclose(f); free(buff); return 6; } buffer->buffer = buff; buffer->length = size; fclose(f); return 0; } int write(const char *fileName, block *buffer) { FILE *f = fopen(fileName, "wb"); if (f == NULL) { printf("Error in creating file \"%s\"\n", fileName); return 7; } if (fwrite(buffer->buffer, 1, buffer->length, f) != (size_t) buffer->length) { printf("Error in writing in file \"%s\"\n", fileName); fclose(f); return 8; } fclose(f); return 0; } int encode(const char *fileName) { char command[2*strlen(fileName) + 14]; strcpy(command, "lzma e "); strcat(command, fileName); strcat(command, " "); strcat(command, fileName); strcat(command, ".lzma"); return system(command); } int decode(const char *fileName) { char command[2*strlen(fileName) + 14]; strcpy(command, "lzma d "); strcat(command, fileName); strcat(command, ".lzma"); strcat(command, " "); strcat(command, fileName); return system(command); } int truncate(block *destination, const block *source, long position) { byte *buffer; int size = source->length - position; if (size < 0) { printf("Error in block truncating\n"); return 9; } if (size == 0) { return 0; } buffer = (byte*) realloc(destination->buffer, size + destination->length); if (buffer == NULL) { printf(memoryError); return 10; } memcpy(buffer + destination->length, source->buffer + position, size); destination->buffer = buffer; destination->length += size; return 0; } int makePatch(const char *oldFileName, const char *newFileName) { char lzmaName[strlen(oldFileName) + 6]; block tmp, newFile, extendedLzma, patch; char patchFileName[strlen(newFileName) + 7]; int error = EXIT_FAILURE; int i; strcpy(lzmaName, oldFileName); strcat(lzmaName, ".lzma"); strcpy(patchFileName, newFileName); strcat(patchFileName, ".patch"); if (encode(oldFileName) == 0) { if (read(oldFileName, &tmp) == 0) { if (read(newFileName, &newFile) == 0) { if (truncate(&tmp, &newFile, 0) == 0 && write(".tmp", &tmp) == 0) { free(tmp.buffer); tmp.buffer = NULL; free(newFile.buffer); newFile.buffer = NULL; if (encode(".tmp") == 0) { long size = fileSize(lzmaName); if (size >= 0 && read(".tmp.lzma", &extendedLzma) == 0) { patch.buffer = (byte*) malloc(12); patch.length = 12; { block old; read(lzmaName, &old); printf("Diferences"); for (i = 0; i < old.length; ++i) if (old.buffer[i] != extendedLzma.buffer[i]) printf(" %d", i); printf("\n"); } if (patch.buffer) { for (i = 0; i < 4; ++i) { patch.buffer[i] = extendedLzma.buffer[i + 4]; } for (i = 0; i < 8; ++i) { patch.buffer[i + 4] = extendedLzma.buffer[size - 8 + i]; } if (truncate(&patch, &extendedLzma, size) == 0 && write(patchFileName, &patch) == 0) { error = EXIT_SUCCESS; } free(patch.buffer); } free(extendedLzma.buffer); } remove(".tmp.lzma"); } remove(".tmp"); } free(newFile.buffer); } free(tmp.buffer); } remove(lzmaName); } printf("Making patch %s\n", error == EXIT_SUCCESS ? "success" : "failed"); return error; } int applyPatch(const char *fileName, const char *patch) { int error = EXIT_FAILURE; block tmp, patchFile; char patchFileName[strlen(patch) + 7]; char lzmaFileName[strlen(fileName) + 6]; int i; strcpy(patchFileName, patch); strcat(patchFileName, ".patch"); strcpy(lzmaFileName, fileName); strcat(lzmaFileName, ".lzma"); if (encode(fileName) == 0) { if (read(lzmaFileName, &tmp) == 0) { if (read(patchFileName, &patchFile) == 0) { for (i = 0; i < 4; ++i) { tmp.buffer[i + 4] = patchFile.buffer[i]; } for (i = 0; i < 8; ++i) { tmp.buffer[tmp.length - 8 + i] = patchFile.buffer[i + 4]; } if (truncate(&tmp, &patchFile, 12) == 0 && write(".tmp.lzma", &tmp) == 0) { free(tmp.buffer); tmp.buffer = NULL; free(patchFile.buffer); patchFile.buffer = NULL; if (decode(".tmp") == 0) { if (read(".tmp", &patchFile) == 0) { long size = fileSize(fileName); if (size >= 0) { patchFile.buffer += size; patchFile.length -= size; if (write(fileName, &patchFile) == 0) { error = EXIT_SUCCESS; } patchFile.buffer -= size; } free(patchFile.buffer); } remove(".tmp"); } remove(".tmp.lzma"); } free(patchFile.buffer); } free(tmp.buffer); } remove(lzmaFileName); } printf("Applyng patch %s\n", error == EXIT_SUCCESS ? "success" : "failed"); return error; } int main(int argc, const char* argv[]) { char command; int error = 0; if (argc != 4 || strlen(argv[1]) != 1) { error = 1; } else { command = tolower(argv[1][0]); if (command != 'm' && command != 'a') { error = 1; } } if (error) { printf("Error: Invalid command line.\n" "Syntax for making patch: PatchUtility m old_file new_file\n" "Syntax for applyng patch: PatchUtility a file patch\n"); return EXIT_FAILURE; } if (command == 'm') { return makePatch(argv[2], argv[3]); } return applyPatch(argv[2], argv[3]); }