#include "io.h" #include #include #include #include #include #include #ifdef __unix__ #include #endif static const char* outfile_name; static FILE* infile; static FILE* outfile; void open_files(const char* infile_name, const char* outfile_name_) { outfile_name = outfile_name_; infile = fopen(infile_name, "rb"); if (infile == NULL) { fprintf(stderr, "failed to open source file: %s\n", strerror(errno)); exit(1); } outfile = fopen(outfile_name, "wb"); if (outfile == NULL) { fprintf(stderr, "failed to open output file: %s\n", strerror(errno)); exit(1); } } void close_files(void) { fclose(infile); if (fclose(outfile) != 0) { fprintf(stderr, "failed to close output file: %s\n", strerror(errno)); // NOTE: ideally we'd do this on any dirty exit if (remove(outfile_name) != 0) { fprintf(stderr, "failed to remove output file; if it exists, it is corrupt: %s\n", strerror(errno)); } exit(1); } #ifdef __unix__ chmod(outfile_name, 0777); #endif } void reserve(size_t len) { if (fseek(outfile, len, SEEK_CUR) != 0) { fprintf(stderr, "failed to reserve space in in output file: %s\n", strerror(errno)); exit(1); } } void emit(const void* restrict ptr, size_t count) { fwrite(ptr, 1, count, outfile); if (ferror(outfile)) { fprintf(stderr, "failed to write to output file\n"); exit(1); } } void emit_u8(uint8_t x) { emit(&x, sizeof(uint8_t)); } void emit_u32(uint32_t x) { emit(&x, sizeof(uint32_t)); } void emit_u64(uint64_t x) { emit(&x, sizeof(uint64_t)); } void patch(size_t off, const void* ptr, size_t count) { fpos_t save; if (fgetpos(outfile, &save) != 0) { fprintf(stderr, "failed to save file position before patch: %s\n", strerror(errno)); exit(1); } if (fseek(outfile, (long) off, SEEK_SET) != 0) { fprintf(stderr, "failed to set file position for patch: %s\n", strerror(errno)); exit(1); } fwrite(ptr, 1, count, outfile); if (ferror(outfile) != 0) { fprintf(stderr, "failed to patch output file: %s\n", strerror(errno)); exit(1); } if (fsetpos(outfile, &save) != 0) { fprintf(stderr, "failed to restore file position after patch: %s\n", strerror(errno)); exit(1); } } void patch_u32(size_t off, uint32_t x) { patch(off, &x, sizeof(uint32_t)); } void patch_i32(size_t off, int32_t x) { patch_u32(off, (uint32_t) x); } static _Bool init = false; static char peek_buf; static char next_(void) { char c = getc(infile); if (c == EOF) { if (ferror(infile)) { fprintf(stderr, "failed to read source file: %s\n", strerror(errno)); exit(1); } c = 0; } return c; } char nextc(void) { if (!init) { init = true; peek_buf = next_(); } int tmp = peek_buf; peek_buf = next_(); return peek_buf; } char peekc(void) { if (!init) { init = true; return nextc(); } return peek_buf; }