From 313deab55253ee49ef3872491f6805a03b5ea36b Mon Sep 17 00:00:00 2001 From: Rangi Date: Thu, 2 Sep 2021 00:21:10 -0400 Subject: [PATCH] Rewrite tool png_dimensions.c, and start using common.h more --- tools/common.h | 96 ++++++++++++++++++++++++++++++++++-------- tools/gfx.c | 29 +------------ tools/png_dimensions.c | 58 ++++++------------------- tools/stadium.c | 9 +--- 4 files changed, 95 insertions(+), 97 deletions(-) diff --git a/tools/common.h b/tools/common.h index 4da0b2ef1..46b319919 100644 --- a/tools/common.h +++ b/tools/common.h @@ -1,40 +1,102 @@ #ifndef GUARD_COMMON_H #define GUARD_COMMON_H -int __getopt_long_i__; -#define getopt_long(c, v, s, l) getopt_long(c, v, s, l, &__getopt_long_i__) +#include +#include +#include +#include +#include +#include +#include +#include +#include -FILE *fopen_verbose(char *filename, char *mode) { +int getopt_long_index; +#define getopt_long(c, v, s, l) getopt_long(c, v, s, l, &getopt_long_index) + +void *malloc_verbose(size_t size) { + void *m = malloc(size); + if (!m) { + fprintf(stderr, "Could not allocate %zu bytes: %s\n", size, strerror(errno)); + exit(1); + } + return m; +} + +FILE *fopen_verbose(const char *filename, char rw) { + char mode[3] = {rw, 'b', '\0'}; FILE *f = fopen(filename, mode); if (!f) { - fprintf(stderr, "Could not open file: \"%s\"\n", filename); + fprintf(stderr, "Could not open file \"%s\": %s\n", filename, strerror(errno)); + exit(1); } return f; } -uint8_t *read_u8(char *filename, int *size) { - FILE *f = fopen_verbose(filename, "rb"); - if (!f) { +void fread_verbose(uint8_t *data, size_t size, const char *filename, FILE *f) { + if (fread(data, 1, size, f) != size) { + fprintf(stderr, "Could not read from file \"%s\": %s\n", filename, strerror(errno)); + fclose(f); exit(1); } - fseek(f, 0, SEEK_END); - *size = ftell(f); - rewind(f); - uint8_t *data = malloc(*size); - if (*size != (int)fread(data, 1, *size, f)) { - fprintf(stderr, "Could not read file: \"%s\"\n", filename); +} + +void fwrite_verbose(const uint8_t *data, size_t size, const char *filename, FILE *f) { + if (fwrite(data, 1, size, f) != size) { + fprintf(stderr, "Could not write to file \"%s\": %s\n", filename, strerror(errno)); + fclose(f); exit(1); } +} + +long file_size(const char *filename, FILE *f) { + long size = 0; + if (!fseek(f, 0, SEEK_END)) { + size = ftell(f); + if (size != -1) { + rewind(f); + } + } + if (errno) { + fprintf(stderr, "Could not measure file \"%s\": %s\n", filename, strerror(errno)); + exit(1); + } + return size; +} + +uint8_t *read_u8(const char *filename, long *size) { + FILE *f = fopen_verbose(filename, 'r'); + *size = file_size(filename, f); + uint8_t *data = malloc_verbose(*size); + fread_verbose(data, *size, filename, f); fclose(f); return data; } -void write_u8(char *filename, uint8_t *data, int size) { - FILE *f = fopen_verbose(filename, "wb"); - if (f) { - fwrite(data, 1, size, f); +void write_u8(const char *filename, uint8_t *data, size_t size) { + FILE *f = fopen_verbose(filename, 'w'); + fwrite_verbose(data, size, filename, f); + fclose(f); +} + +uint32_t read_png_width_verbose(const char *filename) { + FILE *f = fopen_verbose(filename, 'r'); + uint8_t header[16] = {0}; + fread_verbose(header, sizeof(header), filename, f); + static uint8_t expected_header[16] = { + 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n', // signature + 0, 0, 0, 13, // IHDR chunk length + 'I', 'H', 'D', 'R', // IHDR chunk type + }; + if (memcmp(header, expected_header, sizeof(header))) { + fprintf(stderr, "Not a valid PNG file: \"%s\"\n", filename); fclose(f); + exit(1); } + uint8_t bytes[4] = {0}; + fread_verbose(bytes, sizeof(bytes), filename, f); + fclose(f); + return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; } #endif // GUARD_COMMON_H diff --git a/tools/gfx.c b/tools/gfx.c index 7d6dd0ee8..8b5d3150d 100644 --- a/tools/gfx.c +++ b/tools/gfx.c @@ -104,7 +104,7 @@ void shift_preserved(int removed_index) { } struct Graphic { - int size; + long size; uint8_t *data; }; @@ -270,31 +270,6 @@ void interleave(struct Graphic *graphic, int width) { free(interleaved); } -int png_get_width(char *filename) { - FILE *f = fopen_verbose(filename, "rb"); - if (!f) { - exit(1); - } - - const int OFFSET_WIDTH = 16; - uint8_t bytes[4]; - fseek(f, OFFSET_WIDTH, SEEK_SET); - size_t size = 4; - size_t result = fread(bytes, 1, size, f); - fclose(f); - if (result != size) { - fprintf(stderr, "Could not read file at offset 0x%x: \"%s\"\n", OFFSET_WIDTH, filename); - exit(1); - } - - int width = 0; - for (int i = 0; i < 4; i++) { - width |= bytes[i] << (8 * (3 - i)); - } - return width; -} - - int main(int argc, char *argv[]) { get_args(argc, argv); argc -= optind; @@ -319,7 +294,7 @@ int main(int argc, char *argv[]) { usage(); exit(1); } - int width = png_get_width(Options.png_file); + int width = read_png_width_verbose(Options.png_file); interleave(&graphic, width); } if (Options.remove_duplicates) { diff --git a/tools/png_dimensions.c b/tools/png_dimensions.c index 900485bdf..f46f42b8b 100644 --- a/tools/png_dimensions.c +++ b/tools/png_dimensions.c @@ -1,57 +1,25 @@ -#include -#include -#include +#include "common.h" -void usage(void) { - fprintf(stderr, "Usage: png_dimensions infile outfile\n"); - exit(1); +void usage() { + fprintf(stderr, "Usage: png_dimensions in.png out.dimensions\n"); } -void output_dimensions(char* png_filename, char* out_filename) { - FILE* f; - int width, height; - int i; - uint8_t bytes[4]; - uint8_t output; - - f = fopen(png_filename, "rb"); - if (f == NULL) { - fprintf(stderr, "failed to open file %s\n", png_filename); +uint8_t read_dimensions(const char *filename) { + uint32_t width_px = read_png_width_verbose(filename); + if (width_px != 40 && width_px != 48 && width_px != 56) { + fprintf(stderr, "Not a valid width for \"%s\": %" PRIu32 " px\n", filename, width_px); exit(1); } - - // width - fseek(f, 16, SEEK_SET); - int size = fread(bytes, 1, 4, f); - fclose(f); - if (size != 4) { - fprintf(stderr, "failed to read at offset 0x10 in file %s\n", png_filename); - exit(1); - } - - width = 0; - for (i = 0; i < 4; i++) { - width |= bytes[i] << (8 * (3 - i)); - } - width >>= 3; - height = width; - - output = width & 0xf; - output |= (height & 0xf) << 4; - - f = fopen(out_filename, "wb"); - if (f == NULL) { - fprintf(stderr, "failed to open file %s\n", out_filename); - exit(1); - } - fwrite(&output, 1, 1, f); - fclose(f); + uint8_t width_tiles = (uint8_t)(width_px / 8); + return (width_tiles << 4) | width_tiles; } -int main(int argc, char* argv[]) { +int main(int argc, char *argv[]) { if (argc < 3) { usage(); + exit(1); } - output_dimensions(argv[1], argv[2]); + uint8_t output_byte = read_dimensions(argv[1]); + write_u8(argv[2], &output_byte, 1); return 0; } diff --git a/tools/stadium.c b/tools/stadium.c index 479cccdfa..51b671f20 100644 --- a/tools/stadium.c +++ b/tools/stadium.c @@ -1,10 +1,3 @@ -#include -#include -#include -#include -#include -#include - #include "common.h" // The Game Boy cartridge header stores a global checksum at 0x014E-0x014F @@ -160,7 +153,7 @@ int main(int argc, char *argv[]) { } char *filename = argv[0]; - int filesize; + long filesize; uint8_t *file = read_u8(filename, &filesize); calculate_checksums(file, filesize, base); write_u8(filename, file, filesize);