From 0ee4adcb096ea502067e91961109fe67543d54a8 Mon Sep 17 00:00:00 2001 From: Connor Olding Date: Sat, 11 Aug 2018 14:33:52 +0200 Subject: [PATCH] exhaustively check for errors --- compressor.c | 146 ++++++++++++++++++++++++++++----------------------- 1 file changed, 79 insertions(+), 67 deletions(-) diff --git a/compressor.c b/compressor.c index deb8f9d..651233d 100644 --- a/compressor.c +++ b/compressor.c @@ -1,7 +1,8 @@ +//#include +#include #include #include #include -//#include typedef unsigned char u8; typedef unsigned int u32; @@ -10,6 +11,21 @@ typedef unsigned int u32; #define MAX(a, b) ((a) >= (b) ? (a) : (b)) #define PMOD(a, b) (((a) + (b)) % (b)) +#ifdef _WIN32 +#define FMT_SIZE "%Iu" +#else +#define FMT_SIZE "%zu" +#endif + +#define lament(...) fprintf(stderr, __VA_ARGS__) +#define error_when(cond, ...) do { \ + if ((cond) || errno) { \ + lament(__VA_ARGS__); \ + lament(": %s\n", strerror(errno)); \ + goto error; \ + } \ + } while (0) + #define BUF_LEN 1024 #define MIN_LEN 3 #define MAX_LEN 66 @@ -19,9 +35,9 @@ typedef unsigned int u32; #define RW_OVERLAP 1 #endif -char *program_name; - long compress(const u8 *bufi, long size, u8 *bufo) { + // this function cannot fail. + // just ensure bufo points to enough memory to hold the compressed data. u8 buf[BUF_LEN] = {0}; int buf_i = BUF_START; @@ -48,21 +64,21 @@ long compress(const u8 *bufi, long size, u8 *bufo) { int buf_off = (match_i + match_len) % BUF_LEN; #if RW_OVERLAP if (overlap > 0 || (buf_off == buf_i && j != 0)) { - if (sub[overlap % j] != sub[match_len]) { break; } + if (sub[overlap % j] != sub[match_len]) break; overlap++; } else { - if (buf[buf_off] != sub[match_len]) { break; } + if (buf[buf_off] != sub[match_len]) break; } #else - if (buf_off == buf_i && j != 0) { break; } - if (buf[buf_off] != sub[match_len]) { break; } + if (buf_off == buf_i && j != 0) break; + if (buf[buf_off] != sub[match_len]) break; #endif match_len++; - if (match_len == MAX_LEN) { break; } - if (match_len == sub_len) { break; } + if (match_len == MAX_LEN) break; + if (match_len == sub_len) break; } - if (match_len < MIN_LEN) { continue; } + if (match_len < MIN_LEN) continue; if (match_len > best_len) { best_i = match_i; best_len = match_len; @@ -121,87 +137,83 @@ long compress(const u8 *bufi, long size, u8 *bufo) { } int compress_file(const char *fp) { - // TODO: better error handling. - // functions here that can fail: - // fclose - // fopen - // fseek - // ftell - // fwrite - // malloc - // calloc - // free? + FILE *f = NULL; + u8 *bufi = NULL; + u8 *bufo = NULL; + char fs_buf[4] = {0}; + long size = 0; + long new_size = 0; - FILE *f = fopen(fp, "rb"); - if (f == NULL) { - perror(program_name); - return 1; + errno = 0; + + f = fopen(fp, "rb"); + error_when(f == NULL, "Error opening file: %s", fp); + + error_when(fseek(f, 0, SEEK_END) != 0, "Error seeking in file: %s", fp); + size = ftell(f); + error_when(size < 0, "Error telling in file: %s", fp); + error_when(fseek(f, 0, SEEK_SET) != 0, "Error seeking in file: %s", fp); + + if (size > 0) { + bufi = (u8 *)malloc(size); + error_when(bufi == NULL, "Error allocating %li bytes", size); + error_when(fread(bufi, 1, size, f) != (size_t)size, "Error reading %li bytes from file: %s", size, fp); } - fseek(f, 0, SEEK_END); - long size = ftell(f); - fseek(f, 0, SEEK_SET); + error_when(fclose(f) != 0, "Error closing file: %s", fp); - if (size == 0) { - return 0; + if (size > 0) { + // allocate enough for the worst case scenario. + size_t bufo_size = size * 9 / 8 + 8; + bufo = (u8 *)malloc(bufo_size); + error_when(bufo == NULL, "Error allocating " FMT_SIZE " bytes", bufo_size); + + new_size = compress(bufi, size, bufo); + //assert(new_size > 0 && (size_t)new_size < bufo_size); } - u8 *bufi = (u8 *)malloc(size); - if (bufi == NULL) { - fprintf(stderr, "failed to malloc %li bytes\n", size); - free(bufi); - return 2; - } - fread(bufi, 1, size, f); - fclose(f); - - // allocate enough for the worst case scenario. - size_t bufo_size = size * 9 / 8 + 8; - u8 *bufo = (u8 *)malloc(bufo_size); - - long new_size = compress(bufi, size, bufo); - free(bufi); - //assert(new_size > 0 && (size_t)new_size < bufo_size); - f = fopen(fp, "wb"); - if (f == NULL) { - perror(program_name); - free(bufo); - return 3; - } + error_when(f == NULL, "Error opening file: %s", fp); - char fs_buf[4] = {0}; fs_buf[0] = (size >> 24) & 0xFF; fs_buf[1] = (size >> 16) & 0xFF; fs_buf[2] = (size >> 8) & 0xFF; fs_buf[3] = size & 0xFF; - fwrite(fs_buf, 1, 4, f); + error_when(fwrite(fs_buf, 1, 4, f) != 4, "Error writing %i bytes to file: %s", 4, fp); - fwrite(bufo, 1, new_size, f); - fclose(f); + if (new_size > 0) { + error_when(fwrite(bufo, 1, new_size, f) != (size_t)new_size, "Error writing %i bytes to file: %s", 4, fp); + } + + error_when(fclose(f) != 0, "Error closing file: %s", fp); + + free(bufi); free(bufo); - return 0; + +error: + free(bufi); + free(bufo); + return 1; } int main(int argc, char *argv[]) { if (argc <= 0 || argv == NULL || argv[0] == NULL) { - fprintf(stderr, "You've met with a terrible fate.\n"); - exit(1); + lament("You've met with a terrible fate.\n"); + return 1; } - program_name = argv[0]; - + const char *name = argv[0]; if (argc == 1) { - fprintf(stderr, "usage: %s {file}\n", program_name); - exit(2); + lament("compressor: compress files in-place for Bomberman 64.\n"); + lament("usage: %s {file}\n", name); + return 1; } else if (argc == 2) { const char *fp = argv[1]; int ret = compress_file(fp); - if (ret != 0) { - exit(ret + 3); - } + return ret; } else { - fprintf(stderr, "too many arguments\n"); - exit(3); + lament("Error: too many arguments\n"); + lament("usage: %s {file}\n", name); + return 1; } }