shithub: pokecrystal

Download patch

ref: 313deab55253ee49ef3872491f6805a03b5ea36b
parent: 8f88e04401083d847d8f234645a91067c9c70e1b
author: Rangi <[email protected]>
date: Wed Sep 1 20:21:10 EDT 2021

Rewrite tool png_dimensions.c, and start using common.h more

--- 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <getopt.h>
 
-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
--- a/tools/gfx.c
+++ b/tools/gfx.c
@@ -104,7 +104,7 @@
 }
 
 struct Graphic {
-	int size;
+	long size;
 	uint8_t *data;
 };
 
@@ -270,31 +270,6 @@
 	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 @@
 			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) {
--- a/tools/png_dimensions.c
+++ b/tools/png_dimensions.c
@@ -1,57 +1,25 @@
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
+#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;
 }
--- a/tools/stadium.c
+++ b/tools/stadium.c
@@ -1,10 +1,3 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <getopt.h>
-
 #include "common.h"
 
 // The Game Boy cartridge header stores a global checksum at 0x014E-0x014F
@@ -160,7 +153,7 @@
 	}
 
 	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);