summaryrefslogtreecommitdiff
path: root/ines2.c
diff options
context:
space:
mode:
Diffstat (limited to 'ines2.c')
-rw-r--r--ines2.c122
1 files changed, 97 insertions, 25 deletions
diff --git a/ines2.c b/ines2.c
index 9fb743d..dc0e57d 100644
--- a/ines2.c
+++ b/ines2.c
@@ -1,5 +1,6 @@
-
+#include <archive.h>
+#include <archive_entry.h>
// iNES header fields
#define INES_HEADER_SIZE 16
@@ -27,14 +28,89 @@
#define MIRROR_FOUR_SCREEN 2
-static int ines2_load(struct nes_state *state, char *path) {
+static uint8_t *ines2_read_entire_file(const char *path, size_t *out_size) {
FILE *f = fopen(path, "rb");
- if(!f) {
+ if(!f) return 0;
+
+ fseek(f, 0, SEEK_END);
+ size_t size = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ uint8_t *buffer = (uint8_t *)malloc(size);
+ size_t read_size = fread(buffer, 1, size, f);
+ fclose(f);
+
+ if(read_size != size) {
+ free(buffer);
+ return 0;
+ }
+
+ *out_size = size;
+ return buffer;
+}
+
+uint8_t *ines2_unzip_file_to_memory(const char *zip_path, size_t *out_size) {
+ struct archive *a = archive_read_new();
+ struct archive_entry *entry;
+ uint8_t *buffer = 0;
+ size_t size = 0;
+
+ archive_read_support_format_zip(a);
+
+ if(archive_read_open_filename(a, zip_path, 10240) != ARCHIVE_OK) {
+ fprintf(stderr, "libarchive: failed to open zip: %s\n", archive_error_string(a));
+ archive_read_free(a);
+ return 0;
+ }
+
+ if(archive_read_next_header(a, &entry) != ARCHIVE_OK) {
+ fprintf(stderr, "libarchive: no valid file found in zip\n");
+ archive_read_free(a);
+ return 0;
+ }
+
+ const char *name = archive_entry_pathname(entry);
+
+ size = archive_entry_size(entry);
+ buffer = (uint8_t*)malloc(size);
+ if(!buffer) {
+ fprintf(stderr, "libarchive: malloc failed\n");
+ archive_read_free(a);
+ return 0;
+ }
+
+ ssize_t read_size = archive_read_data(a, buffer, size);
+ if(read_size != (ssize_t)size) {
+ fprintf(stderr, "libarchive: failed to read full file\n");
+ free(buffer);
+ buffer = 0;
+ }
+
+
+ archive_read_free(a);
+
+ if(buffer && out_size) {
+ *out_size = size;
+ }
+ return buffer;
+}
+
+static int ines2_load(struct nes_state *state, const char *path) {
+ uint8_t *data = 0;
+ size_t size = 0;
+
+ if(strstr(path, ".zip")) {
+ data = ines2_unzip_file_to_memory(path, &size);
+ } else {
+ data = ines2_read_entire_file(path, &size);
+ }
+
+ if(!data || size < INES_HEADER_SIZE) {
return -1;
}
- uint8_t header[INES_HEADER_SIZE];
- fread(header, 1, INES_HEADER_SIZE, f);
+ uint8_t *ptr = data;
+ uint8_t *header = ptr; ptr += INES_HEADER_SIZE;
uint8_t prg_lsb = header[INES_PRG_SIZE_LSB];
uint8_t chr_lsb = header[INES_CHR_SIZE_LSB];
@@ -44,21 +120,18 @@ static int ines2_load(struct nes_state *state, char *path) {
uint32_t prg_size = (prg_msb << 8 | prg_lsb) * PRG_ROM_UNIT;
uint32_t chr_size = (chr_msb << 8 | chr_lsb) * CHR_ROM_UNIT;
- // NES 2.0 exponential format (only if lower byte is 0x0f)
- if(prg_lsb == 0x0f) {
- prg_size = 1 << header[INES_PRG_EXP];
- }
- if(chr_lsb == 0x0f) {
- chr_size = 1 << header[INES_CHR_EXP];
- }
+ if(prg_lsb == 0x0f) prg_size = 1 << header[INES_PRG_EXP];
+ if(chr_lsb == 0x0f) chr_size = 1 << header[INES_CHR_EXP];
+
+ uint8_t mapper_low = (header[INES_FLAGS6] >> 4);
+ uint8_t mapper_high = (header[INES_FLAGS7] & 0xf0);
+ uint8_t mapper_ext = (header[INES_PRG_CHR_MSB] & 0x0f);
+ uint8_t mapper_upper = header[8] & 0x0f;
+ uint8_t submapper = (header[8] >> 4);
- // Extract mapper
- uint8_t mapper_low = (header[INES_FLAGS6] >> 4);
- uint8_t mapper_high = (header[INES_FLAGS7] & 0xf0);
- uint8_t mapper_ext = (header[INES_PRG_CHR_MSB] & 0x0f);
- state->ines.mapper = mapper_low | mapper_high | (mapper_ext << 8);
+ state->ines.mapper = mapper_low | mapper_high | (mapper_upper << 8);
+ state->ines.submapper = submapper;
- // Extract mirroring
if(header[INES_FLAGS6] & FLAG6_FOUR_SCREEN) {
state->ines.mirroring = MIRROR_FOUR_SCREEN;
} else if(header[INES_FLAGS6] & FLAG6_VERTICAL_MIRROR) {
@@ -70,21 +143,20 @@ static int ines2_load(struct nes_state *state, char *path) {
state->ines.prg_size = prg_size;
state->ines.chr_size = chr_size;
- // Skip trainer if present
if(header[INES_FLAGS6] & FLAG6_TRAINER) {
- fseek(f, TRAINER_SIZE, SEEK_CUR);
+ ptr += TRAINER_SIZE;
}
- // Read PRG
- printf("prgsize_read: %ld\n", fread(state->prg_rom, 1, prg_size, f));
+ memcpy(state->prg_rom, ptr, prg_size);
+ ptr += prg_size;
- // Read CHR if present
if(chr_size > 0) {
- printf("chrsize_read: %ld\n", fread(state->chr_rom, 1, chr_size, f));
+ memcpy(state->chr_rom, ptr, chr_size);
}
- fclose(f);
+ free(data);
return 0;
}
+