diff options
| author | Peter Fors <peter.fors@mindkiller.com> | 2025-04-05 08:58:12 +0200 |
|---|---|---|
| committer | Peter Fors <peter.fors@mindkiller.com> | 2025-04-05 08:58:12 +0200 |
| commit | f1bd6a7d2f4ffe3e5263e0254bcf7522ab381264 (patch) | |
| tree | e75bde292329f337d619f9a997aab9b17c37e38b /ines2.c | |
| parent | 8c82be43720d9e221a9e2541c9ff6151015838bb (diff) | |
transform to switch case for ppu_tick()
Diffstat (limited to 'ines2.c')
| -rw-r--r-- | ines2.c | 122 |
1 files changed, 97 insertions, 25 deletions
@@ -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; } + |
