git.y1.nz

SameBoy

Accurate GB/GBC emulator
download: https://git.y1.nz/archives/sameboy.tar.gz
README | Files | Log | Refs | LICENSE

Core/save_state.c

      1 #include "gb.h"
      2 #include <stdio.h>
      3 #include <errno.h>
      4 #include <assert.h>
      5 #include <string.h>
      6 #include <stdlib.h>
      7 
      8 #ifdef GB_BIG_ENDIAN
      9 #define BESS_NAME "SameBoy v" GB_VERSION " (Big Endian)"
     10 #else
     11 #define BESS_NAME "SameBoy v" GB_VERSION
     12 #endif
     13 
     14 _Static_assert((GB_SECTION_OFFSET(core_state) & 7) == 0, "Section core_state is not aligned");
     15 _Static_assert((GB_SECTION_OFFSET(dma) & 7) == 0, "Section dma is not aligned");
     16 _Static_assert((GB_SECTION_OFFSET(mbc) & 7) == 0, "Section mbc is not aligned");
     17 _Static_assert((GB_SECTION_OFFSET(hram) & 7) == 0, "Section hram is not aligned");
     18 _Static_assert((GB_SECTION_OFFSET(timing) & 7) == 0, "Section timing is not aligned");
     19 _Static_assert((GB_SECTION_OFFSET(apu) & 7) == 0, "Section apu is not aligned");
     20 _Static_assert((GB_SECTION_OFFSET(rtc) & 7) == 0, "Section rtc is not aligned");
     21 _Static_assert((GB_SECTION_OFFSET(video) & 7) == 0, "Section video is not aligned");
     22 _Static_assert((GB_SECTION_OFFSET(accessory) & 7) == 0, "Section accessory is not aligned");
     23 
     24 typedef struct __attribute__((packed)) {
     25     uint32_t magic;
     26     uint32_t size;
     27 } BESS_block_t;
     28 
     29 typedef struct __attribute__((packed)) {
     30     uint32_t size;
     31     uint32_t offset;
     32 } BESS_buffer_t;
     33 
     34 typedef struct __attribute__((packed)) {
     35     uint32_t start_offset;
     36     uint32_t magic;
     37 } BESS_footer_t;
     38 
     39 typedef struct __attribute__((packed)) {
     40     BESS_block_t header;
     41     uint16_t  major;
     42     uint16_t  minor;
     43     union {
     44         struct {
     45             char family;
     46             char model;
     47             char revision;
     48             char padding;
     49         };
     50         uint32_t full_model;
     51     };
     52     
     53     uint16_t pc;
     54     uint16_t af;
     55     uint16_t bc;
     56     uint16_t de;
     57     uint16_t hl;
     58     uint16_t sp;
     59     
     60     uint8_t ime;
     61     uint8_t ie;
     62     uint8_t execution_mode; // 0 = running; 1 = halted; 2 = stopped
     63     uint8_t _padding;
     64     
     65     uint8_t io_registers[0x80];
     66     
     67     BESS_buffer_t ram;
     68     BESS_buffer_t vram;
     69     BESS_buffer_t mbc_ram;
     70     BESS_buffer_t oam;
     71     BESS_buffer_t hram;
     72     BESS_buffer_t background_palettes;
     73     BESS_buffer_t object_palettes;
     74 } BESS_CORE_t;
     75 
     76 typedef struct __attribute__((packed)) {
     77     BESS_block_t header;
     78     uint8_t extra_oam[96];
     79 } BESS_XOAM_t;
     80 
     81 typedef struct __attribute__((packed)) {
     82     BESS_block_t header;
     83     BESS_buffer_t border_tiles;
     84     BESS_buffer_t border_tilemap;
     85     BESS_buffer_t border_palettes;
     86     
     87     BESS_buffer_t active_palettes;
     88     BESS_buffer_t ram_palettes;
     89     BESS_buffer_t attribute_map;
     90     BESS_buffer_t attribute_files;
     91     
     92     uint8_t multiplayer_state;
     93 } BESS_SGB_t;
     94 
     95 typedef struct __attribute__((packed)){
     96     BESS_block_t header;
     97     char title[0x10];
     98     uint8_t checksum[2];
     99 } BESS_INFO_t;
    100 
    101 /* Same RTC format as used by VBA, BGB and SameBoy in battery saves*/
    102 typedef struct __attribute__((packed)){
    103     BESS_block_t header;
    104     struct {
    105         uint8_t seconds;
    106         uint8_t padding1[3];
    107         uint8_t minutes;
    108         uint8_t padding2[3];
    109         uint8_t hours;
    110         uint8_t padding3[3];
    111         uint8_t days;
    112         uint8_t padding4[3];
    113         uint8_t high;
    114         uint8_t padding5[3];
    115     } real, latched;
    116     uint64_t last_rtc_second;
    117 } BESS_RTC_t;
    118 
    119 /* Same HuC3 RTC format as used by SameBoy and BGB in battery saves */
    120 typedef struct __attribute__((packed)){
    121     BESS_block_t header;
    122     GB_huc3_rtc_time_t data;
    123 } BESS_HUC3_t;
    124 
    125 typedef struct __attribute__((packed)) {
    126     BESS_block_t header;
    127 
    128     // Flags
    129     bool latch_ready:1;
    130     bool eeprom_do:1;
    131     bool eeprom_di:1;
    132     bool eeprom_clk:1;
    133     bool eeprom_cs:1;
    134     bool eeprom_write_enabled:1;
    135     uint8_t padding:2;
    136     
    137     uint8_t argument_bits_left;
    138     
    139     uint16_t eeprom_command;
    140     uint16_t read_bits;
    141     
    142     uint16_t x_latch;
    143     uint16_t y_latch;
    144 
    145 } BESS_MBC7_t;
    146 
    147 typedef struct __attribute__((packed)){
    148     BESS_block_t header;
    149     uint64_t last_rtc_second;
    150     uint8_t real_rtc_data[4];
    151     uint8_t latched_rtc_data[4];
    152     uint8_t mr4;
    153 } BESS_TPP1_t;
    154 
    155 typedef struct  __attribute__((packed)) {
    156     uint16_t address;
    157     uint8_t value;
    158 } BESS_MBC_pair_t;
    159 
    160 typedef struct virtual_file_s virtual_file_t;
    161 struct virtual_file_s
    162 {
    163     size_t (*read)(virtual_file_t *file, void *dest, size_t length);
    164     size_t (*write)(virtual_file_t *file, const void *dest, size_t length);
    165     void (*seek)(virtual_file_t *file, ssize_t ammount, int origin);
    166     size_t (*tell)(virtual_file_t *file);
    167     union {
    168         FILE *file;
    169         struct {
    170             uint8_t *buffer;
    171             size_t position;
    172             size_t size;
    173         };
    174     };
    175 };
    176 
    177 static size_t file_read(virtual_file_t *file, void *dest, size_t length)
    178 {
    179     return fread(dest, 1, length, file->file);
    180 }
    181 
    182 static void file_seek(virtual_file_t *file, ssize_t ammount, int origin)
    183 {
    184     fseek(file->file, ammount, origin);
    185 }
    186 
    187 static size_t file_write(virtual_file_t *file, const void *src, size_t length)
    188 {
    189     return fwrite(src, 1, length, file->file);
    190 }
    191 
    192 static size_t file_tell(virtual_file_t *file)
    193 {
    194     return ftell(file->file);
    195 }
    196 
    197 static size_t buffer_read(virtual_file_t *file, void *dest, size_t length)
    198 {
    199     if (length & 0x80000000) {
    200         return 0;
    201     }
    202     errno = 0;
    203     if (length > file->size - file->position) {
    204         errno = EIO;
    205         length = file->size - file->position;
    206     }
    207     
    208     memcpy(dest, file->buffer + file->position, length);
    209     file->position += length;
    210     
    211     return length;
    212 }
    213 
    214 static void buffer_seek(virtual_file_t *file, ssize_t ammount, int origin)
    215 {
    216     switch (origin) {
    217         case SEEK_SET:
    218             file->position = ammount;
    219             break;
    220         case SEEK_CUR:
    221             file->position += ammount;
    222             break;
    223         case SEEK_END:
    224             file->position = file->size + ammount;
    225             break;
    226         default:
    227             break;
    228     }
    229     
    230     if (file->position > file->size) {
    231         file->position = file->size;
    232     }
    233 }
    234 
    235 static size_t buffer_write(virtual_file_t *file, const void *src, size_t size)
    236 {
    237     memcpy(file->buffer + file->position, src, size);
    238     file->position += size;
    239     return size;
    240 }
    241 
    242 static size_t buffer_tell(virtual_file_t *file)
    243 {
    244     return file->position;
    245 }
    246 
    247 static size_t bess_size_for_cartridge(const GB_cartridge_t *cart)
    248 {
    249     switch (cart->mbc_type) {
    250         default:
    251         case GB_NO_MBC: return 0;
    252         case GB_MBC1:
    253             return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t);
    254         case GB_MBC2:
    255             return sizeof(BESS_block_t) + 2 * sizeof(BESS_MBC_pair_t);
    256         case GB_MBC3:
    257             return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t) + (cart->has_rtc? sizeof(BESS_RTC_t) : 0);
    258         case GB_MBC5:
    259             return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t);
    260         case GB_CAMERA:
    261             return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t);
    262         case GB_MBC7:
    263             return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t) + sizeof(BESS_MBC7_t);
    264         case GB_MMM01:
    265             return sizeof(BESS_block_t) + 8 * sizeof(BESS_MBC_pair_t);
    266         case GB_HUC1:
    267             return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t);
    268         case GB_HUC3:
    269             return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t) + sizeof(BESS_HUC3_t);
    270         case GB_TPP1:
    271             return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t) + sizeof(BESS_TPP1_t);
    272     }
    273 }
    274 
    275 size_t GB_get_save_state_size_no_bess(GB_gameboy_t *gb)
    276 {
    277     return GB_SECTION_SIZE(header)
    278     + GB_SECTION_SIZE(core_state) + sizeof(uint32_t)
    279     + GB_SECTION_SIZE(dma       ) + sizeof(uint32_t)
    280     + GB_SECTION_SIZE(mbc       ) + sizeof(uint32_t)
    281     + GB_SECTION_SIZE(hram      ) + sizeof(uint32_t)
    282     + GB_SECTION_SIZE(timing    ) + sizeof(uint32_t)
    283     + GB_SECTION_SIZE(apu       ) + sizeof(uint32_t)
    284     + GB_SECTION_SIZE(rtc       ) + sizeof(uint32_t)
    285     + GB_SECTION_SIZE(video     ) + sizeof(uint32_t)
    286     + GB_SECTION_SIZE(accessory ) + sizeof(uint32_t)
    287     + (GB_is_hle_sgb(gb)? sizeof(*gb->sgb) + sizeof(uint32_t) : 0)
    288     + gb->mbc_ram_size
    289     + gb->ram_size
    290     + gb->vram_size;
    291 }
    292 
    293 size_t GB_get_save_state_size(GB_gameboy_t *gb)
    294 {
    295     return GB_get_save_state_size_no_bess(gb) +
    296     // BESS
    297     + sizeof(BESS_block_t) // NAME
    298     + sizeof(BESS_NAME) - 1
    299     + sizeof(BESS_INFO_t) // INFO
    300     + sizeof(BESS_CORE_t)
    301     + sizeof(BESS_XOAM_t)
    302     + (gb->sgb? sizeof(BESS_SGB_t) : 0)
    303     + bess_size_for_cartridge(gb->cartridge_type) // MBC & RTC/HUC3/TPP1/MBC7 block
    304     + sizeof(BESS_block_t) // END block
    305     + sizeof(BESS_footer_t);
    306 }
    307 
    308 static bool verify_and_update_state_compatibility(GB_gameboy_t *gb, GB_gameboy_t *save, bool *attempt_bess)
    309 {
    310     *attempt_bess = false;
    311     
    312     if (gb->version != save->version) {
    313         GB_log(gb, "The save state is for a different version of SameBoy.\n");
    314         *attempt_bess = true;
    315         return false;
    316     }
    317     
    318     if (GB_is_cgb(gb) != GB_is_cgb(save) || GB_is_hle_sgb(gb) != GB_is_hle_sgb(save)) {
    319         GB_log(gb, "The save state is for a different Game Boy model. Try changing the emulated model.\n");
    320         return false;
    321     }
    322     
    323     if (gb->mbc_ram_size < save->mbc_ram_size) {
    324         GB_log(gb, "The save state has non-matching MBC RAM size.\n");
    325         return false;
    326     }
    327     
    328     if (gb->vram_size != save->vram_size) {
    329         GB_log(gb, "The save state has non-matching VRAM size. Try changing the emulated model.\n");
    330         return false;
    331     }
    332     
    333     if (GB_is_hle_sgb(gb) != GB_is_hle_sgb(save)) {
    334         GB_log(gb, "The save state is %sfor a Super Game Boy. Try changing the emulated model.\n", GB_is_hle_sgb(save)? "" : "not ");
    335         return false;
    336     }
    337     
    338     if (gb->ram_size != save->ram_size) {
    339         GB_log(gb, "The save state has non-matching RAM size. Try changing the emulated model.\n");
    340         return false;
    341     }
    342     
    343     if (gb->accessory != save->accessory) {
    344         memset(GB_GET_SECTION(save, accessory), 0, GB_SECTION_SIZE(accessory));
    345     }
    346     
    347     switch (save->model) {
    348         case GB_MODEL_DMG_B: return true;
    349         case GB_MODEL_SGB_NTSC: return true;
    350         case GB_MODEL_SGB_PAL: return true;
    351         case GB_MODEL_SGB_NTSC_NO_SFC: return true;
    352         case GB_MODEL_SGB_PAL_NO_SFC: return true;
    353         case GB_MODEL_MGB: return true;
    354         case GB_MODEL_SGB2: return true;
    355         case GB_MODEL_SGB2_NO_SFC: return true;
    356         case GB_MODEL_CGB_0: return true;
    357         case GB_MODEL_CGB_A: return true;
    358         case GB_MODEL_CGB_B: return true;
    359         case GB_MODEL_CGB_C: return true;
    360         case GB_MODEL_CGB_D: return true;
    361         case GB_MODEL_CGB_E: return true;
    362         case GB_MODEL_AGB_A: return true;
    363         case GB_MODEL_GBP_A: return true;
    364     }
    365     if ((gb->model & GB_MODEL_FAMILY_MASK) == (save->model & GB_MODEL_FAMILY_MASK)) {
    366         save->model = gb->model;
    367         return true;
    368     }
    369     
    370     GB_log(gb, "This save state is for an unknown Game Boy model\n");
    371     return false;
    372 }
    373 
    374 static void sanitize_state(GB_gameboy_t *gb)
    375 {
    376     for (unsigned i = 0; i < 32; i++) {
    377         GB_palette_changed(gb, false, i * 2);
    378         GB_palette_changed(gb, true, i * 2);
    379     }
    380     
    381     gb->bg_fifo.read_end &= GB_FIFO_LENGTH - 1;
    382     gb->oam_fifo.read_end &= GB_FIFO_LENGTH - 1;
    383     gb->last_tile_index_address &= 0x1FFF;
    384     gb->window_tile_x &= 0x1F;
    385     
    386     /* These are kind of DOS-ish if too large */
    387     if (abs(gb->display_cycles) > 0x80000) {
    388         gb->display_cycles = 0;
    389     }
    390     
    391     if (abs(gb->div_cycles) > 0x8000) {
    392         gb->div_cycles = 0;
    393     }
    394     
    395     if (!GB_is_cgb(gb)) {
    396         gb->cgb_mode = false;
    397     }
    398     
    399     if (gb->ram_size == 0x8000) {
    400         gb->cgb_ram_bank &= 0x7;
    401     }
    402     else {
    403         gb->cgb_ram_bank = 1;
    404     }
    405     if (gb->vram_size != 0x4000) {
    406         gb->cgb_vram_bank = 0;
    407     }
    408     if (!GB_is_cgb(gb)) {
    409         gb->current_tile_attributes = 0;
    410     }
    411 
    412     gb->object_low_line_address &= (gb->vram_size - 1) & ~1;
    413     if (gb->lcd_x > gb->position_in_line) {
    414         gb->lcd_x = gb->position_in_line;
    415     }
    416     
    417     if (gb->sgb) {
    418         if (gb->sgb->player_count != 1 && gb->sgb->player_count != 2 && gb->sgb->player_count != 4) {
    419             gb->sgb->player_count = 1;
    420         }
    421         gb->sgb->current_player &= gb->sgb->player_count - 1;
    422     }
    423     GB_update_clock_rate(gb);
    424     
    425     if (gb->camera_update_request_callback) {
    426         GB_camera_updated(gb);
    427     }
    428     
    429     if (!gb->apu.apu_cycles_in_2mhz) {
    430         gb->apu.apu_cycles >>= 2;
    431         gb->apu.apu_cycles_in_2mhz = true;
    432     }
    433     
    434     if (gb->n_visible_objs > 10) {
    435         gb->n_visible_objs = 10;
    436     }
    437 }
    438 
    439 static bool dump_section(virtual_file_t *file, const void *src, uint32_t size)
    440 {
    441     if (file->write(file, &size, sizeof(size)) != sizeof(size)) {
    442         return false;
    443     }
    444     
    445     if (file->write(file, src, size) != size) {
    446         return false;
    447     }
    448     
    449     return true;
    450 }
    451 
    452 #define DUMP_SECTION(gb, f, section) dump_section(f, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section))
    453 
    454 static int save_bess_mbc_block(GB_gameboy_t *gb, virtual_file_t *file)
    455 {
    456     
    457     BESS_block_t mbc_block = {BE32('MBC '), 0};
    458     BESS_MBC_pair_t pairs[8];
    459     switch (gb->cartridge_type->mbc_type) {
    460         default:
    461         case GB_NO_MBC: return 0;
    462         case GB_MBC1:
    463             pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
    464             pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc1.bank_low};
    465             pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc1.bank_high};
    466             pairs[3] = (BESS_MBC_pair_t){LE16(0x6000), gb->mbc1.mode};
    467             mbc_block.size = 4 * sizeof(pairs[0]);
    468             break;
    469         case GB_MBC2:
    470             pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
    471             pairs[1] = (BESS_MBC_pair_t){LE16(0x0100), gb->mbc2.rom_bank};
    472             mbc_block.size = 2 * sizeof(pairs[0]);
    473             break;
    474         case GB_MBC3:
    475             pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
    476             pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc3.rom_bank};
    477             pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc3.ram_bank | (gb->mbc3.rtc_mapped? 8 : 0)};
    478             mbc_block.size = 3 * sizeof(pairs[0]);
    479             break;
    480         case GB_MBC5:
    481             pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
    482             pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc5.rom_bank_low};
    483             pairs[2] = (BESS_MBC_pair_t){LE16(0x3000), gb->mbc5.rom_bank_high};
    484             pairs[3] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc5.ram_bank};
    485             mbc_block.size = 4 * sizeof(pairs[0]);
    486             break;
    487         case GB_CAMERA:
    488             pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
    489             pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc5.rom_bank_low};
    490             pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc5.ram_bank};
    491             mbc_block.size = 3 * sizeof(pairs[0]);
    492             break;
    493         case GB_MBC7:
    494             pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
    495             pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc7.rom_bank};
    496             pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc7.secondary_ram_enable? 0x40 : 0};
    497             mbc_block.size = 3 * sizeof(pairs[0]);
    498             break;
    499         case GB_MMM01:
    500             pairs[0] = (BESS_MBC_pair_t){LE16(0x2000), (gb->mmm01.rom_bank_low & (gb->mmm01.rom_bank_mask << 1)) | (gb->mmm01.rom_bank_mid << 5)};
    501             pairs[1] = (BESS_MBC_pair_t){LE16(0x6000), gb->mmm01.mbc1_mode | (gb->mmm01.rom_bank_mask << 2) | (gb->mmm01.multiplex_mode << 6)};
    502             pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->mmm01.ram_bank_low | (gb->mmm01.ram_bank_high << 2) | (gb->mmm01.rom_bank_high << 4) | (gb->mmm01.mbc1_mode_disable << 6)};
    503             pairs[3] = (BESS_MBC_pair_t){LE16(0x0000), (gb->mbc_ram_enable? 0xA : 0x0) | (gb->mmm01.ram_bank_mask << 4) | (gb->mmm01.locked << 6)};
    504             /* For compatibility with emulators that inaccurately emulate MMM01, and also require two writes per register */
    505             pairs[4] = (BESS_MBC_pair_t){LE16(0x2000), (gb->mmm01.rom_bank_low & ~(gb->mmm01.rom_bank_mask << 1))};
    506             pairs[5] = pairs[1];
    507             pairs[6] = pairs[2];
    508             pairs[7] = pairs[3];
    509             mbc_block.size = 8 * sizeof(pairs[0]);
    510             break;
    511         case GB_HUC1:
    512             pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->huc1.ir_mode? 0xE : 0x0};
    513             pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->huc1.bank_low};
    514             pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->huc1.bank_high};
    515             mbc_block.size = 3 * sizeof(pairs[0]);
    516         case GB_HUC3:
    517             pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->huc3.mode};
    518             pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->huc3.rom_bank};
    519             pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->huc3.ram_bank};
    520             mbc_block.size = 3 * sizeof(pairs[0]);
    521             break;
    522         case GB_TPP1:
    523             pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->tpp1.rom_bank};
    524             pairs[1] = (BESS_MBC_pair_t){LE16(0x0001), gb->tpp1.rom_bank >> 8};
    525             pairs[2] = (BESS_MBC_pair_t){LE16(0x0002), gb->tpp1.rom_bank};
    526             pairs[3] = (BESS_MBC_pair_t){LE16(0x0003), gb->tpp1.mode};
    527             mbc_block.size = 4 * sizeof(pairs[0]);
    528             break;
    529     }
    530     
    531     mbc_block.size = LE32(mbc_block.size);
    532     
    533     if (file->write(file, &mbc_block, sizeof(mbc_block)) != sizeof(mbc_block)) {
    534         return errno;
    535     }
    536     
    537     if (file->write(file, &pairs, LE32(mbc_block.size)) != LE32(mbc_block.size)) {
    538         return errno;
    539     }
    540     
    541     return 0;
    542 }
    543 
    544 static const uint8_t *get_header_bank(GB_gameboy_t *gb)
    545 {
    546     if (gb->cartridge_type->mbc_type == GB_MMM01) {
    547         return gb->rom + gb->rom_size - 0x8000;
    548     }
    549     return gb->rom;
    550 }
    551 
    552 static int save_state_internal(GB_gameboy_t *gb, virtual_file_t *file, bool append_bess)
    553 {
    554     errno = 0;
    555     if (file->write(file, GB_GET_SECTION(gb, header), GB_SECTION_SIZE(header)) != GB_SECTION_SIZE(header)) goto error;
    556     if (!DUMP_SECTION(gb, file, core_state)) goto error;
    557     if (!DUMP_SECTION(gb, file, dma       )) goto error;
    558     if (!DUMP_SECTION(gb, file, mbc       )) goto error;
    559     uint32_t hram_offset = file->tell(file) + 4;
    560     if (!DUMP_SECTION(gb, file, hram      )) goto error;
    561     if (!DUMP_SECTION(gb, file, timing    )) goto error;
    562     if (!DUMP_SECTION(gb, file, apu       )) goto error;
    563     if (!DUMP_SECTION(gb, file, rtc       )) goto error;
    564     uint32_t video_offset = file->tell(file) + 4;
    565     if (!DUMP_SECTION(gb, file, video     )) goto error;
    566     if (!DUMP_SECTION(gb, file, accessory )) goto error;
    567 
    568     uint32_t sgb_offset = 0;
    569     
    570     if (GB_is_hle_sgb(gb)) {
    571         sgb_offset = file->tell(file) + 4;
    572         if (!dump_section(file, gb->sgb, sizeof(*gb->sgb))) goto error;
    573     }
    574     
    575     
    576     BESS_CORE_t bess_core = {0,};
    577     
    578     bess_core.mbc_ram.offset = LE32(file->tell(file));
    579     bess_core.mbc_ram.size = LE32(gb->mbc_ram_size);
    580     if (file->write(file, gb->mbc_ram, gb->mbc_ram_size) != gb->mbc_ram_size) {
    581         goto error;
    582     }
    583     
    584     bess_core.ram.offset = LE32(file->tell(file));
    585     bess_core.ram.size = LE32(gb->ram_size);
    586     if (file->write(file, gb->ram, gb->ram_size) != gb->ram_size) {
    587         goto error;
    588     }
    589     
    590     bess_core.vram.offset = LE32(file->tell(file));
    591     bess_core.vram.size = LE32(gb->vram_size);
    592     if (file->write(file, gb->vram, gb->vram_size) != gb->vram_size) {
    593         goto error;
    594     }
    595     
    596     if (!append_bess) return 0;
    597     
    598     BESS_footer_t bess_footer = {
    599         .start_offset = LE32(file->tell(file)),
    600         .magic = BE32('BESS'),
    601     };
    602     
    603     /* BESS NAME */
    604     
    605     static const BESS_block_t bess_name = {BE32('NAME'), LE32(sizeof(BESS_NAME) - 1)};
    606     
    607     if (file->write(file, &bess_name, sizeof(bess_name)) != sizeof(bess_name)) {
    608         goto error;
    609     }
    610     
    611     if (file->write(file, BESS_NAME, sizeof(BESS_NAME) - 1) != sizeof(BESS_NAME) - 1) {
    612         goto error;
    613     }
    614     
    615     /* BESS INFO */
    616     
    617     static const BESS_block_t bess_info = {BE32('INFO'), LE32(sizeof(BESS_INFO_t) - sizeof(BESS_block_t))};
    618     
    619     if (file->write(file, &bess_info, sizeof(bess_info)) != sizeof(bess_info)) {
    620         goto error;
    621     }
    622     
    623     const uint8_t *bank = get_header_bank(gb);
    624     
    625     if (file->write(file, bank + 0x134, 0x10) != 0x10) {
    626         goto error;
    627     }
    628     
    629     if (file->write(file, bank + 0x14E, 2) != 2) {
    630         goto error;
    631     }
    632     
    633     /* BESS CORE */
    634     
    635     bess_core.header = (BESS_block_t){BE32('CORE'), LE32(sizeof(bess_core) - sizeof(bess_core.header))};
    636     bess_core.major = LE16(1);
    637     bess_core.minor = LE16(1);
    638     switch (gb->model) {
    639 
    640         case GB_MODEL_DMG_B: bess_core.full_model = BE32('GDB '); break;
    641         case GB_MODEL_MGB: bess_core.full_model = BE32('GM  '); break;
    642             
    643         case GB_MODEL_SGB_NTSC:
    644         case GB_MODEL_SGB_NTSC_NO_SFC:
    645             bess_core.full_model = BE32('SN  '); break;
    646             
    647         case GB_MODEL_SGB_PAL_NO_SFC:
    648         case GB_MODEL_SGB_PAL:
    649             bess_core.full_model = BE32('SP  '); break;
    650         
    651         case GB_MODEL_SGB2_NO_SFC:
    652         case GB_MODEL_SGB2:
    653             bess_core.full_model = BE32('S2  '); break;
    654  
    655         case GB_MODEL_CGB_0: bess_core.full_model = BE32('CC0 '); break;
    656         case GB_MODEL_CGB_A: bess_core.full_model = BE32('CCA '); break;
    657         case GB_MODEL_CGB_B: bess_core.full_model = BE32('CCB '); break;
    658         case GB_MODEL_CGB_C: bess_core.full_model = BE32('CCC '); break;
    659         case GB_MODEL_CGB_D: bess_core.full_model = BE32('CCD '); break;
    660         case GB_MODEL_CGB_E: bess_core.full_model = BE32('CCE '); break;
    661         case GB_MODEL_AGB_A:
    662         case GB_MODEL_GBP_A:
    663             bess_core.full_model = BE32('CAA '); break;
    664     }
    665     
    666     bess_core.pc = LE16(gb->pc);
    667     bess_core.af = LE16(gb->af);
    668     bess_core.bc = LE16(gb->bc);
    669     bess_core.de = LE16(gb->de);
    670     bess_core.hl = LE16(gb->hl);
    671     bess_core.sp = LE16(gb->sp);
    672     
    673     bess_core.ime = gb->ime;
    674     bess_core.ie = gb->interrupt_enable;
    675     bess_core.execution_mode = 0;
    676     if (gb->halted) {
    677         bess_core.execution_mode = 1;
    678     }
    679     else if (gb->stopped) {
    680         bess_core.execution_mode = 2;
    681     }
    682     
    683     memcpy(bess_core.io_registers, gb->io_registers, sizeof(gb->io_registers));
    684     bess_core.io_registers[GB_IO_DIV] = gb->div_counter >> 8;
    685     bess_core.io_registers[GB_IO_BANK] = gb->boot_rom_finished;
    686     bess_core.io_registers[GB_IO_KEY1] |= gb->cgb_double_speed? 0x80 : 0;
    687     bess_core.hram.size = LE32(sizeof(gb->hram));
    688     bess_core.hram.offset = LE32(hram_offset + offsetof(GB_gameboy_t, hram) - GB_SECTION_OFFSET(hram));
    689     bess_core.oam.size = LE32(sizeof(gb->oam));
    690     bess_core.oam.offset = LE32(video_offset + offsetof(GB_gameboy_t, oam) - GB_SECTION_OFFSET(video));
    691     if (GB_is_cgb(gb)) {
    692         bess_core.background_palettes.size = LE32(sizeof(gb->background_palettes_data));
    693         bess_core.background_palettes.offset = LE32(video_offset + offsetof(GB_gameboy_t, background_palettes_data) - GB_SECTION_OFFSET(video));
    694         bess_core.object_palettes.size = LE32(sizeof(gb->object_palettes_data));
    695         bess_core.object_palettes.offset = LE32(video_offset + offsetof(GB_gameboy_t, object_palettes_data) - GB_SECTION_OFFSET(video));
    696     }
    697     
    698     if (file->write(file, &bess_core, sizeof(bess_core)) != sizeof(bess_core)) {
    699         goto error;
    700     }
    701         
    702     /* BESS XOAM */
    703     
    704     BESS_XOAM_t bess_xoam = {0,};
    705     bess_xoam.header = (BESS_block_t){BE32('XOAM'), LE32(sizeof(bess_xoam) - sizeof(bess_xoam.header))};
    706     if (GB_is_cgb(gb)) {
    707         memcpy(bess_xoam.extra_oam, gb->extra_oam, sizeof(bess_xoam.extra_oam));
    708     }
    709     
    710     if (file->write(file, &bess_xoam, sizeof(bess_xoam)) != sizeof(bess_xoam)) {
    711         goto error;
    712     }
    713     
    714     save_bess_mbc_block(gb, file);
    715     if (gb->cartridge_type->has_rtc) {
    716         if (gb->cartridge_type ->mbc_type == GB_TPP1) {
    717             BESS_TPP1_t bess_tpp1 = {0,};
    718             bess_tpp1.header = (BESS_block_t){BE32('TPP1'), LE32(sizeof(bess_tpp1) - sizeof(bess_tpp1.header))};
    719             
    720             bess_tpp1.last_rtc_second = LE64(gb->last_rtc_second);
    721             unrolled for (unsigned i = 4; i--;) {
    722                 bess_tpp1.real_rtc_data[i] = gb->rtc_real.data[i ^ 3];
    723                 bess_tpp1.latched_rtc_data[i] = gb->rtc_latched.data[i ^ 3];
    724             }
    725             bess_tpp1.mr4 = gb->tpp1_mr4;
    726 
    727             if (file->write(file, &bess_tpp1, sizeof(bess_tpp1)) != sizeof(bess_tpp1)) {
    728                 goto error;
    729             }
    730         }
    731         else if (gb->cartridge_type ->mbc_type != GB_HUC3) {
    732             BESS_RTC_t bess_rtc = {0,};
    733             bess_rtc.header = (BESS_block_t){BE32('RTC '), LE32(sizeof(bess_rtc) - sizeof(bess_rtc.header))};
    734             bess_rtc.real.seconds = gb->rtc_real.seconds;
    735             bess_rtc.real.minutes = gb->rtc_real.minutes;
    736             bess_rtc.real.hours = gb->rtc_real.hours;
    737             bess_rtc.real.days = gb->rtc_real.days;
    738             bess_rtc.real.high = gb->rtc_real.high;
    739             bess_rtc.latched.seconds = gb->rtc_latched.seconds;
    740             bess_rtc.latched.minutes = gb->rtc_latched.minutes;
    741             bess_rtc.latched.hours = gb->rtc_latched.hours;
    742             bess_rtc.latched.days = gb->rtc_latched.days;
    743             bess_rtc.latched.high = gb->rtc_latched.high;
    744             bess_rtc.last_rtc_second = LE64(gb->last_rtc_second);
    745             if (file->write(file, &bess_rtc, sizeof(bess_rtc)) != sizeof(bess_rtc)) {
    746                 goto error;
    747             }
    748         }
    749         else {
    750             BESS_HUC3_t bess_huc3 = {0,};
    751             bess_huc3.header = (BESS_block_t){BE32('HUC3'), LE32(sizeof(bess_huc3) - sizeof(bess_huc3.header))};
    752 
    753             bess_huc3.data = (GB_huc3_rtc_time_t) {
    754                 LE64(gb->last_rtc_second),
    755                 LE16(gb->huc3.minutes),
    756                 LE16(gb->huc3.days),
    757                 LE16(gb->huc3.alarm_minutes),
    758                 LE16(gb->huc3.alarm_days),
    759                 gb->huc3.alarm_enabled,
    760             };
    761             if (file->write(file, &bess_huc3, sizeof(bess_huc3)) != sizeof(bess_huc3)) {
    762                 goto error;
    763             }
    764         }
    765     }
    766     
    767     if (gb->cartridge_type ->mbc_type == GB_MBC7) {
    768         BESS_MBC7_t bess_mbc7 = {
    769             .latch_ready = gb->mbc7.latch_ready,
    770             .eeprom_do = gb->mbc7.eeprom_do,
    771             .eeprom_di = gb->mbc7.eeprom_di,
    772             .eeprom_clk = gb->mbc7.eeprom_clk,
    773             .eeprom_cs = gb->mbc7.eeprom_cs,
    774             .eeprom_write_enabled = gb->mbc7.eeprom_write_enabled,
    775             
    776             .argument_bits_left = gb->mbc7.argument_bits_left,
    777             
    778             .eeprom_command = LE16(gb->mbc7.eeprom_command),
    779             .read_bits = LE16(gb->mbc7.read_bits),
    780             
    781             .x_latch = LE16(gb->mbc7.x_latch),
    782             .y_latch = LE16(gb->mbc7.y_latch),
    783         };
    784         bess_mbc7.header = (BESS_block_t){BE32('MBC7'), LE32(sizeof(bess_mbc7) - sizeof(bess_mbc7.header))};
    785         
    786         if (file->write(file, &bess_mbc7, sizeof(bess_mbc7)) != sizeof(bess_mbc7)) {
    787             goto error;
    788         }
    789     }
    790     
    791     bool needs_sgb_padding = false;
    792     if (gb->sgb) {
    793         /* BESS SGB */
    794         if (gb->sgb->disable_commands) {
    795             needs_sgb_padding = true;
    796         }
    797         else {
    798             BESS_SGB_t bess_sgb = {{BE32('SGB '), LE32(sizeof(bess_sgb) - sizeof(bess_sgb.header))}, };
    799             
    800             bess_sgb.border_tiles    = (BESS_buffer_t){LE32(sizeof(gb->sgb->pending_border.tiles)),
    801                                                        LE32(sgb_offset + offsetof(GB_sgb_t, pending_border.tiles))};
    802             bess_sgb.border_tilemap  = (BESS_buffer_t){LE32(sizeof(gb->sgb->pending_border.map)),
    803                                                        LE32(sgb_offset + offsetof(GB_sgb_t, pending_border.map))};
    804             bess_sgb.border_palettes = (BESS_buffer_t){LE32(sizeof(gb->sgb->pending_border.palette)),
    805                                                        LE32(sgb_offset + offsetof(GB_sgb_t, pending_border.palette))};
    806             
    807             bess_sgb.active_palettes = (BESS_buffer_t){LE32(sizeof(gb->sgb->effective_palettes)),
    808                                                        LE32(sgb_offset + offsetof(GB_sgb_t, effective_palettes))};
    809             bess_sgb.ram_palettes    = (BESS_buffer_t){LE32(sizeof(gb->sgb->ram_palettes)),
    810                                                        LE32(sgb_offset + offsetof(GB_sgb_t, ram_palettes))};
    811             bess_sgb.attribute_map   = (BESS_buffer_t){LE32(sizeof(gb->sgb->attribute_map)),
    812                                                        LE32(sgb_offset + offsetof(GB_sgb_t, attribute_map))};
    813             bess_sgb.attribute_files = (BESS_buffer_t){LE32(sizeof(gb->sgb->attribute_files)),
    814                                                        LE32(sgb_offset + offsetof(GB_sgb_t, attribute_files))};
    815             
    816             bess_sgb.multiplayer_state = (gb->sgb->player_count << 4) | gb->sgb->current_player;
    817             if (file->write(file, &bess_sgb, sizeof(bess_sgb)) != sizeof(bess_sgb)) {
    818                 goto error;
    819             }
    820         }
    821     }
    822     
    823     /* BESS END */
    824     
    825     static const BESS_block_t bess_end = {BE32('END '), 0};
    826 
    827     if (file->write(file, &bess_end, sizeof(bess_end)) != sizeof(bess_end)) {
    828         goto error;
    829     }
    830     
    831     if (needs_sgb_padding) {
    832         static const uint8_t sgb_padding[sizeof(BESS_SGB_t)] = {0,};
    833         file->write(file, sgb_padding, sizeof(sgb_padding));
    834     }
    835     
    836     /* BESS Footer */
    837     
    838     if (file->write(file, &bess_footer, sizeof(bess_footer)) != sizeof(bess_footer)) {
    839         goto error;
    840     }
    841     
    842     return 0;;
    843 error:
    844     if (errno == 0) return EIO;
    845     return errno;
    846 }
    847 
    848 int GB_save_state(GB_gameboy_t *gb, const char *path)
    849 {
    850     GB_ASSERT_NOT_RUNNING(gb)
    851     FILE *f = fopen(path, "wb");
    852     if (!f) {
    853         GB_log(gb, "Could not open save state: %s.\n", strerror(errno));
    854         return errno;
    855     }
    856     virtual_file_t file = {
    857         .write = file_write,
    858         .seek = file_seek,
    859         .tell = file_tell,
    860         .file = f,
    861     };
    862     int ret = save_state_internal(gb, &file, true);
    863     fclose(f);
    864     return ret;
    865 }
    866 
    867 void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer)
    868 {
    869     GB_ASSERT_NOT_RUNNING(gb)
    870     virtual_file_t file = {
    871         .write = buffer_write,
    872         .seek = buffer_seek,
    873         .tell = buffer_tell,
    874         .buffer = (uint8_t *)buffer,
    875         .position = 0,
    876     };
    877     
    878     save_state_internal(gb, &file, true);
    879     assert(file.position == GB_get_save_state_size(gb));
    880 }
    881 
    882 void GB_save_state_to_buffer_no_bess(GB_gameboy_t *gb, uint8_t *buffer)
    883 {
    884     virtual_file_t file = {
    885         .write = buffer_write,
    886         .seek = buffer_seek,
    887         .tell = buffer_tell,
    888         .buffer = (uint8_t *)buffer,
    889         .position = 0,
    890     };
    891     
    892     save_state_internal(gb, &file, false);
    893     assert(file.position == GB_get_save_state_size_no_bess(gb));
    894 }
    895 
    896 static bool read_section(virtual_file_t *file, void *dest, uint32_t size)
    897 {
    898     uint32_t saved_size = 0;
    899     if (file->read(file, &saved_size, sizeof(size)) != sizeof(size)) {
    900         return false;
    901     }
    902     
    903     if (saved_size <= size) {
    904         if (file->read(file, dest, saved_size) != saved_size) {
    905             return false;
    906         }
    907     }
    908     else {
    909         if (file->read(file, dest, size) != size) {
    910             return false;
    911         }
    912         file->seek(file, saved_size - size, SEEK_CUR);
    913     }
    914     
    915     return true;
    916 }
    917 
    918 static void read_bess_buffer(const BESS_buffer_t *buffer, virtual_file_t *file, uint8_t *dest, size_t max_size)
    919 {
    920     size_t pos = file->tell(file);
    921     file->seek(file, LE32(buffer->offset), SEEK_SET);
    922     file->read(file, dest, MIN(LE32(buffer->size), max_size));
    923     file->seek(file, pos, SEEK_SET);
    924     
    925     if (LE32(buffer->size) < max_size) {
    926         memset(dest + LE32(buffer->size), 0, max_size - LE32(buffer->size));
    927     }
    928 }
    929 
    930 static int load_bess_save(GB_gameboy_t *gb, virtual_file_t *file, bool is_sameboy)
    931 {
    932     char emulator_name[65] = {0,};
    933     file->seek(file, -sizeof(BESS_footer_t), SEEK_END);
    934     BESS_footer_t footer = {0, };
    935     file->read(file, &footer, sizeof(footer));
    936     if (footer.magic != BE32('BESS')) {
    937         // Not a BESS file
    938         if (!is_sameboy) {
    939             GB_log(gb, "The file is not a save state, or is from an incompatible operating system.\n");
    940         }
    941         return -1;
    942     }
    943     
    944     GB_gameboy_t save;
    945     GB_init(&save, gb->model);
    946     save.cartridge_type = gb->cartridge_type;
    947     
    948     file->seek(file, LE32(footer.start_offset), SEEK_SET);
    949     bool found_core = false;
    950     BESS_CORE_t core = {0,};
    951     bool found_sgb = false;
    952     BESS_SGB_t sgb = {0,};
    953     while (true) {
    954         BESS_block_t block;
    955         if (file->read(file, &block, sizeof(block)) != sizeof(block)) goto error;
    956         switch (block.magic) {
    957             case BE32('CORE'):
    958                 if (found_core) goto parse_error;
    959                 found_core = true;
    960                 if (LE32(block.size) > sizeof(core) - sizeof(block)) {
    961                     if (file->read(file, &core.header + 1, sizeof(core) - sizeof(block)) != sizeof(core) - sizeof(block)) goto error;
    962                     file->seek(file, LE32(block.size) - (sizeof(core) - sizeof(block)), SEEK_CUR);
    963                 }
    964                 else {
    965                     if (file->read(file, &core.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
    966                 }
    967                 
    968                 if (core.major != LE16(1)) {
    969                     GB_log(gb, "This save state uses an incompatible version of the BESS specification");
    970                     GB_free(&save);
    971                     return -1;
    972                 }
    973                 
    974                 switch (core.family) {
    975                     case 'C':
    976                         if (!GB_is_cgb(&save)) goto wrong_model;
    977                         break;
    978                     case 'S':
    979                         if (!GB_is_sgb(&save)) goto wrong_model;
    980                         break;
    981                     case 'G':
    982                         if (GB_is_cgb(&save) || GB_is_sgb(&save)) goto wrong_model;
    983                         break;
    984                     default:
    985                     wrong_model:
    986                         GB_log(gb, "The save state is for a different model. Try changing the emulated model.\n");
    987                         GB_free(&save);
    988                         return -1;
    989                 }
    990 
    991                 
    992                 save.pc = LE16(core.pc);
    993                 save.af = LE16(core.af);
    994                 save.bc = LE16(core.bc);
    995                 save.de = LE16(core.de);
    996                 save.hl = LE16(core.hl);
    997                 save.sp = LE16(core.sp);
    998                 
    999                 save.ime = core.ime;
   1000                 save.interrupt_enable = core.ie;
   1001                 
   1002                 save.halted = core.execution_mode == 1;
   1003                 save.stopped = core.execution_mode == 2;
   1004                               
   1005                 // Done early for compatibility with 0.14.x
   1006                 GB_write_memory(&save, 0xFF00 + GB_IO_SVBK, core.io_registers[GB_IO_SVBK]);
   1007                 // CPU related
   1008                 
   1009                 // Determines DMG mode
   1010                 GB_write_memory(&save, 0xFF00 + GB_IO_KEY0, core.io_registers[GB_IO_KEY0]);
   1011                 save.boot_rom_finished = core.io_registers[GB_IO_BANK];
   1012                 GB_write_memory(&save, 0xFF00 + GB_IO_KEY1, core.io_registers[GB_IO_KEY1]);
   1013                 if (save.cgb_mode) {
   1014                     save.cgb_double_speed = core.io_registers[GB_IO_KEY1] & 0x80;
   1015                     save.object_priority = GB_OBJECT_PRIORITY_INDEX;
   1016                 }
   1017                 else {
   1018                     save.object_priority = GB_OBJECT_PRIORITY_X;
   1019                 }
   1020                 
   1021                 // Timers, Joypad and Serial
   1022                 GB_write_memory(&save, 0xFF00 + GB_IO_JOYP, core.io_registers[GB_IO_JOYP]);
   1023                 GB_write_memory(&save, 0xFF00 + GB_IO_SB, core.io_registers[GB_IO_SB]);
   1024                 save.io_registers[GB_IO_SC] = core.io_registers[GB_IO_SC];
   1025                 save.div_counter = core.io_registers[GB_IO_DIV] << 8;
   1026                 GB_write_memory(&save, 0xFF00 + GB_IO_TIMA, core.io_registers[GB_IO_TIMA]);
   1027                 GB_write_memory(&save, 0xFF00 + GB_IO_TMA, core.io_registers[GB_IO_TMA]);
   1028                 GB_write_memory(&save, 0xFF00 + GB_IO_TAC, core.io_registers[GB_IO_TAC]);
   1029                 
   1030                 // APU
   1031                 GB_write_memory(&save, 0xFF00 + GB_IO_NR52, core.io_registers[GB_IO_NR52]);
   1032                 for (unsigned i = GB_IO_NR10; i < GB_IO_NR52; i++) {
   1033                     uint8_t value = core.io_registers[i];
   1034                     if (i == GB_IO_NR14 || i == GB_IO_NR24 || i == GB_IO_NR34 || i == GB_IO_NR44) {
   1035                         value &= ~0x80;
   1036                     }
   1037                     GB_write_memory(&save, 0xFF00 + i, value);
   1038                 }
   1039                 
   1040                 for (unsigned i = GB_IO_WAV_START; i <= GB_IO_WAV_END; i++) {
   1041                     GB_write_memory(&save, 0xFF00 + i, core.io_registers[i]);
   1042                 }
   1043                 
   1044                 // PPU
   1045                 GB_write_memory(&save, 0xFF00 + GB_IO_LCDC, core.io_registers[GB_IO_LCDC]);
   1046                 GB_write_memory(&save, 0xFF00 + GB_IO_STAT, core.io_registers[GB_IO_STAT]);
   1047                 GB_write_memory(&save, 0xFF00 + GB_IO_SCY, core.io_registers[GB_IO_SCY]);
   1048                 GB_write_memory(&save, 0xFF00 + GB_IO_SCX, core.io_registers[GB_IO_SCX]);
   1049                 GB_write_memory(&save, 0xFF00 + GB_IO_LYC, core.io_registers[GB_IO_LYC]);
   1050                 save.io_registers[GB_IO_DMA] = core.io_registers[GB_IO_DMA];
   1051                 GB_write_memory(&save, 0xFF00 + GB_IO_BGP, core.io_registers[GB_IO_BGP]);
   1052                 GB_write_memory(&save, 0xFF00 + GB_IO_OBP0, core.io_registers[GB_IO_OBP0]);
   1053                 GB_write_memory(&save, 0xFF00 + GB_IO_OBP1, core.io_registers[GB_IO_OBP1]);
   1054                 GB_write_memory(&save, 0xFF00 + GB_IO_WX, core.io_registers[GB_IO_WX]);
   1055                 GB_write_memory(&save, 0xFF00 + GB_IO_WY, core.io_registers[GB_IO_WY]);
   1056                 
   1057                 // Other registers
   1058                 GB_write_memory(&save, 0xFF00 + GB_IO_VBK, core.io_registers[GB_IO_VBK]);
   1059                 GB_write_memory(&save, 0xFF00 + GB_IO_HDMA1, core.io_registers[GB_IO_HDMA1]);
   1060                 GB_write_memory(&save, 0xFF00 + GB_IO_HDMA2, core.io_registers[GB_IO_HDMA2]);
   1061                 GB_write_memory(&save, 0xFF00 + GB_IO_HDMA3, core.io_registers[GB_IO_HDMA3]);
   1062                 GB_write_memory(&save, 0xFF00 + GB_IO_HDMA4, core.io_registers[GB_IO_HDMA4]);
   1063                 GB_write_memory(&save, 0xFF00 + GB_IO_RP, core.io_registers[GB_IO_RP]);
   1064                 GB_write_memory(&save, 0xFF00 + GB_IO_BGPI, core.io_registers[GB_IO_BGPI]);
   1065                 GB_write_memory(&save, 0xFF00 + GB_IO_OBPI, core.io_registers[GB_IO_OBPI]);
   1066                 GB_write_memory(&save, 0xFF00 + GB_IO_OPRI, core.io_registers[GB_IO_OPRI]);
   1067 
   1068                 // Interrupts
   1069                 GB_write_memory(&save, 0xFF00 + GB_IO_IF, core.io_registers[GB_IO_IF]);
   1070                 
   1071                 /* Required to be compatible with both SameBoy 0.14.x AND BGB */
   1072                 if (GB_is_cgb(&save) && !save.cgb_mode && save.cgb_ram_bank == 7) {
   1073                     save.cgb_ram_bank = 1;
   1074                 }
   1075                 
   1076                 break;
   1077             case BE32('NAME'):
   1078                 if (LE32(block.size) > sizeof(emulator_name) - 1) {
   1079                     file->seek(file, LE32(block.size), SEEK_CUR);
   1080                 }
   1081                 else {
   1082                     file->read(file, emulator_name, LE32(block.size));
   1083                 }
   1084                 break;
   1085             case BE32('INFO'): {
   1086                 BESS_INFO_t bess_info = {0,};
   1087                 if (LE32(block.size) != sizeof(bess_info) - sizeof(block)) goto parse_error;
   1088                 if (file->read(file, &bess_info.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
   1089                 const uint8_t *bank = get_header_bank(gb);
   1090                 if (memcmp(bess_info.title, bank + 0x134, sizeof(bess_info.title))) {
   1091                     char ascii_title[0x11] = {0,};
   1092                     for (unsigned i = 0; i < 0x10; i++) {
   1093                         if (bess_info.title[i] < 0x20 || bess_info.title[i] > 0x7E) break;
   1094                         ascii_title[i] = bess_info.title[i];
   1095                     }
   1096                     GB_log(gb, "Save state was made on another ROM: '%s'\n", ascii_title);
   1097                 }
   1098                 else if (memcmp(bess_info.checksum, bank + 0x14E, 2)) {
   1099                     GB_log(gb, "Save state was potentially made on another revision of the same ROM.\n");
   1100                 }
   1101                 break;
   1102             }
   1103             case BE32('XOAM'):
   1104                 if (!found_core) goto parse_error;
   1105                 if (LE32(block.size) != 96) goto parse_error;
   1106                 file->read(file, save.extra_oam, sizeof(save.extra_oam));
   1107                 break;
   1108             case BE32('MBC '):
   1109                 if (!found_core) goto parse_error;
   1110                 if (LE32(block.size) % 3 != 0) goto parse_error;
   1111                 if (LE32(block.size) > 0x1000) goto parse_error;
   1112                 /* Inject some default writes, as some emulators omit them */
   1113                 if (gb->cartridge_type->mbc_type == GB_MMM01) {
   1114                     GB_write_memory(&save, 0x6000, 0x30);
   1115                     GB_write_memory(&save, 0x4000, 0x70);
   1116                 }
   1117                 for (unsigned i = LE32(block.size); i > 0;  i -= 3) {
   1118                     BESS_MBC_pair_t pair;
   1119                     file->read(file, &pair, sizeof(pair));
   1120                     if (LE16(pair.address) >= 0x8000 && LE16(pair.address) < 0xA000) goto parse_error;
   1121                     if (LE16(pair.address) >= 0xC000) goto parse_error;
   1122                     GB_write_memory(&save, LE16(pair.address), pair.value);
   1123                 }
   1124                 break;
   1125             case BE32('RTC '):
   1126                 if (!found_core) goto parse_error;
   1127                 BESS_RTC_t bess_rtc;
   1128                 if (LE32(block.size) != sizeof(bess_rtc) - sizeof(block)) goto parse_error;
   1129                 if (file->read(file, &bess_rtc.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
   1130                 if (!gb->cartridge_type->has_rtc || gb->cartridge_type->mbc_type != GB_MBC3) break;
   1131                 save.rtc_real.seconds = bess_rtc.real.seconds;
   1132                 save.rtc_real.minutes = bess_rtc.real.minutes;
   1133                 save.rtc_real.hours = bess_rtc.real.hours;
   1134                 save.rtc_real.days = bess_rtc.real.days;
   1135                 save.rtc_real.high = bess_rtc.real.high;
   1136                 save.rtc_latched.seconds = bess_rtc.latched.seconds;
   1137                 save.rtc_latched.minutes = bess_rtc.latched.minutes;
   1138                 save.rtc_latched.hours = bess_rtc.latched.hours;
   1139                 save.rtc_latched.days = bess_rtc.latched.days;
   1140                 save.rtc_latched.high = bess_rtc.latched.high;
   1141                 if (gb->rtc_mode == GB_RTC_MODE_SYNC_TO_HOST) {
   1142                     save.last_rtc_second = MIN(LE64(bess_rtc.last_rtc_second), time(NULL));
   1143                 }
   1144                 
   1145                 break;
   1146             case BE32('HUC3'):
   1147                 if (!found_core) goto parse_error;
   1148                 BESS_HUC3_t bess_huc3;
   1149                 if (LE32(block.size) != sizeof(bess_huc3) - sizeof(block)) goto parse_error;
   1150                 if (file->read(file, &bess_huc3.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
   1151                 if (gb->cartridge_type->mbc_type != GB_HUC3) break;
   1152                 if (gb->rtc_mode == GB_RTC_MODE_SYNC_TO_HOST) {
   1153                     save.last_rtc_second = MIN(LE64(bess_huc3.data.last_rtc_second), time(NULL));
   1154                 }
   1155                 save.huc3.minutes = LE16(bess_huc3.data.minutes);
   1156                 save.huc3.days = LE16(bess_huc3.data.days);
   1157                 save.huc3.alarm_minutes = LE16(bess_huc3.data.alarm_minutes);
   1158                 save.huc3.alarm_days = LE16(bess_huc3.data.alarm_days);
   1159                 save.huc3.alarm_enabled = bess_huc3.data.alarm_enabled;
   1160                 break;
   1161             case BE32('TPP1'):
   1162                 if (!found_core) goto parse_error;
   1163                 BESS_TPP1_t bess_tpp1;
   1164                 if (LE32(block.size) != sizeof(bess_tpp1) - sizeof(block)) goto parse_error;
   1165                 if (file->read(file, &bess_tpp1.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
   1166                 if (gb->cartridge_type->mbc_type != GB_TPP1) break;
   1167                 if (gb->rtc_mode == GB_RTC_MODE_SYNC_TO_HOST) {
   1168                     save.last_rtc_second = MIN(LE64(bess_tpp1.last_rtc_second), time(NULL));
   1169                 }
   1170                 unrolled for (unsigned i = 4; i--;) {
   1171                     save.rtc_real.data[i ^ 3] = bess_tpp1.real_rtc_data[i];
   1172                     save.rtc_latched.data[i ^ 3] = bess_tpp1.latched_rtc_data[i];
   1173                 }
   1174                 save.tpp1_mr4 = bess_tpp1.mr4;
   1175                 break;
   1176             case BE32('MBC7'):
   1177                 if (!found_core) goto parse_error;
   1178                 BESS_MBC7_t bess_mbc7;
   1179                 if (LE32(block.size) != sizeof(bess_mbc7) - sizeof(block)) goto parse_error;
   1180                 if (file->read(file, &bess_mbc7.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
   1181                 if (gb->cartridge_type->mbc_type != GB_MBC7) break;
   1182                 
   1183                 save.mbc7.latch_ready = bess_mbc7.latch_ready;
   1184                 save.mbc7.eeprom_do = bess_mbc7.eeprom_do;
   1185                 save.mbc7.eeprom_di = bess_mbc7.eeprom_di;
   1186                 save.mbc7.eeprom_clk = bess_mbc7.eeprom_clk;
   1187                 save.mbc7.eeprom_cs = bess_mbc7.eeprom_cs;
   1188                 save.mbc7.eeprom_write_enabled = bess_mbc7.eeprom_write_enabled;
   1189                 
   1190                 save.mbc7.argument_bits_left = bess_mbc7.argument_bits_left;
   1191                 
   1192                 save.mbc7.eeprom_command = LE16(bess_mbc7.eeprom_command);
   1193                 save.mbc7.read_bits = LE16(bess_mbc7.read_bits);
   1194                 
   1195                 save.mbc7.x_latch = LE16(bess_mbc7.x_latch);
   1196                 save.mbc7.y_latch = LE16(bess_mbc7.y_latch);
   1197                 
   1198                 break;
   1199             case BE32('SGB '):
   1200                 if (!found_core) goto parse_error;
   1201                 if (!gb->sgb) goto parse_error;
   1202                 if (LE32(block.size) > sizeof(sgb) - sizeof(block)) {
   1203                     if (file->read(file, &sgb.header + 1, sizeof(sgb) - sizeof(block)) != sizeof(sgb) - sizeof(block)) goto error;
   1204                     file->seek(file, LE32(block.size) - (sizeof(sgb) - sizeof(block)), SEEK_CUR);
   1205                 }
   1206                 else {
   1207                     if (file->read(file, &sgb.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
   1208                 }
   1209                 found_sgb = true;
   1210                 break;
   1211             case BE32('END '):
   1212                 if (!found_core) goto parse_error;
   1213                 if (LE32(block.size) != 0) goto parse_error;
   1214                 goto done;
   1215             default:
   1216                 file->seek(file, LE32(block.size), SEEK_CUR);
   1217                 break;
   1218         }
   1219     }
   1220 done:
   1221     save.mbc_ram_size = gb->mbc_ram_size;
   1222     memcpy(gb, &save, GB_SECTION_OFFSET(unsaved));
   1223     assert(GB_get_save_state_size(gb) == GB_get_save_state_size(&save));
   1224     GB_free(&save);
   1225     read_bess_buffer(&core.ram, file, gb->ram, gb->ram_size);
   1226     read_bess_buffer(&core.vram, file, gb->vram, gb->vram_size);
   1227     read_bess_buffer(&core.mbc_ram, file, gb->mbc_ram, gb->mbc_ram_size);
   1228     read_bess_buffer(&core.oam, file, gb->oam, sizeof(gb->oam));
   1229     read_bess_buffer(&core.hram, file, gb->hram, sizeof(gb->hram));
   1230     read_bess_buffer(&core.background_palettes, file, gb->background_palettes_data, sizeof(gb->background_palettes_data));
   1231     read_bess_buffer(&core.object_palettes, file, gb->object_palettes_data, sizeof(gb->object_palettes_data));
   1232     if (gb->sgb) {
   1233         memset(gb->sgb, 0, sizeof(*gb->sgb));
   1234         GB_sgb_load_default_data(gb);
   1235         if (gb->boot_rom_finished) {
   1236             gb->sgb->intro_animation = GB_SGB_INTRO_ANIMATION_LENGTH;
   1237             if (!found_sgb) {
   1238                 gb->sgb->disable_commands = true;
   1239             }
   1240             else {
   1241                 read_bess_buffer(&sgb.border_tiles, file, gb->sgb->border.tiles, sizeof(gb->sgb->border.tiles));
   1242                 read_bess_buffer(&sgb.border_tilemap, file, (void *)gb->sgb->border.map, sizeof(gb->sgb->border.map));
   1243                 read_bess_buffer(&sgb.border_palettes, file, (void *)gb->sgb->border.palette, sizeof(gb->sgb->border.palette));
   1244                 
   1245                 read_bess_buffer(&sgb.active_palettes, file, (void *)gb->sgb->effective_palettes, sizeof(gb->sgb->effective_palettes));
   1246                 read_bess_buffer(&sgb.ram_palettes, file, (void *)gb->sgb->ram_palettes, sizeof(gb->sgb->ram_palettes));
   1247                 read_bess_buffer(&sgb.attribute_map, file, (void *)gb->sgb->attribute_map, sizeof(gb->sgb->attribute_map));
   1248                 read_bess_buffer(&sgb.attribute_files, file, (void *)gb->sgb->attribute_files, sizeof(gb->sgb->attribute_files));
   1249                 
   1250                 gb->sgb->effective_palettes[12] = gb->sgb->effective_palettes[8] =
   1251                 gb->sgb->effective_palettes[4] = gb->sgb->effective_palettes[0];
   1252                 
   1253                 gb->sgb->player_count = sgb.multiplayer_state >> 4;
   1254                 gb->sgb->current_player = sgb.multiplayer_state & 0xF;
   1255                 if (gb->sgb->player_count > 4 || gb->sgb->player_count == 3 || gb->sgb->player_count == 0) {
   1256                     gb->sgb->player_count = 1;
   1257                     gb->sgb->current_player = 0;
   1258                 }
   1259             }
   1260         }
   1261         else {
   1262             // Effectively reset if didn't finish the boot ROM
   1263             gb->pc = 0;
   1264         }
   1265     }
   1266     if (emulator_name[0]) {
   1267         GB_log(gb, "Save state imported from %s.\n", emulator_name);
   1268     }
   1269     else {
   1270         GB_log(gb, "Save state imported from another emulator.\n"); // SameBoy always contains a NAME block
   1271     }
   1272     for (unsigned i = 0; i < 32; i++) {
   1273         GB_palette_changed(gb, false, i * 2);
   1274         GB_palette_changed(gb, true, i * 2);
   1275     }
   1276     gb->apu_output.sample_fraction = 0;
   1277     return 0;
   1278 parse_error:
   1279     errno = -1;
   1280 error:
   1281     if (emulator_name[0]) {
   1282         GB_log(gb, "Attempted to import a save state from %s, but the save state is invalid.\n", emulator_name);
   1283     }
   1284     else {
   1285         GB_log(gb, "Attempted to import a save state from a different emulator or incompatible version, but the save state is invalid.\n");
   1286     }
   1287     GB_free(&save);
   1288     sanitize_state(gb);
   1289     return errno;
   1290 }
   1291 
   1292 static int load_state_internal(GB_gameboy_t *gb, virtual_file_t *file)
   1293 {
   1294     GB_gameboy_t save;
   1295     
   1296     /* Every unread value should be kept the same. */
   1297     memcpy(&save, gb, sizeof(save));
   1298     /* ...Except ram size, we use it to detect old saves with incorrect ram sizes */
   1299     save.ram_size = 0;
   1300     
   1301     
   1302     if (file->read(file, GB_GET_SECTION(&save, header), GB_SECTION_SIZE(header)) != GB_SECTION_SIZE(header)) return errno;
   1303     if (gb->magic != save.magic) {
   1304         return load_bess_save(gb, file, false);
   1305     }
   1306 #define READ_SECTION(gb, file, section) read_section(file, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section))
   1307     if (!READ_SECTION(&save, file, core_state)) return errno ?: EIO;
   1308     if (!READ_SECTION(&save, file, dma       )) return errno ?: EIO;
   1309     if (!READ_SECTION(&save, file, mbc       )) return errno ?: EIO;
   1310     if (!READ_SECTION(&save, file, hram      )) return errno ?: EIO;
   1311     if (!READ_SECTION(&save, file, timing    )) return errno ?: EIO;
   1312     if (!READ_SECTION(&save, file, apu       )) return errno ?: EIO;
   1313     if (!READ_SECTION(&save, file, rtc       )) return errno ?: EIO;
   1314     if (!READ_SECTION(&save, file, video     )) return errno ?: EIO;
   1315     if (!READ_SECTION(&save, file, accessory )) return errno ?: EIO;
   1316 
   1317     
   1318     bool attempt_bess = false;
   1319     if (!verify_and_update_state_compatibility(gb, &save, &attempt_bess)) {
   1320         if (attempt_bess) {
   1321             return load_bess_save(gb, file, true);
   1322         }
   1323         return errno;
   1324     }
   1325     
   1326     if (GB_is_hle_sgb(gb)) {
   1327         if (!read_section(file, gb->sgb, sizeof(*gb->sgb))) return errno ?: EIO;
   1328     }
   1329     
   1330     memset(gb->mbc_ram + save.mbc_ram_size, 0xFF, gb->mbc_ram_size - save.mbc_ram_size);
   1331     if (file->read(file, gb->mbc_ram, save.mbc_ram_size) != save.mbc_ram_size) {
   1332         return errno ?: EIO;
   1333     }
   1334     
   1335     if (file->read(file, gb->ram, gb->ram_size) != gb->ram_size) {
   1336         return errno ?: EIO;
   1337     }
   1338     
   1339     /* Fix for 0.11 save states that allocate twice the amount of RAM in CGB instances */
   1340     file->seek(file, save.ram_size - gb->ram_size, SEEK_CUR);
   1341     
   1342     if (file->read(file, gb->vram, gb->vram_size) != gb->vram_size) {
   1343         return errno ?: EIO;
   1344     }
   1345     
   1346     uint32_t ram_size = gb->ram_size;
   1347     uint32_t mbc_ram_size = gb->mbc_ram_size;
   1348     memcpy(gb, &save, sizeof(save));
   1349     gb->ram_size = ram_size;
   1350     gb->mbc_ram_size = mbc_ram_size;
   1351 
   1352     sanitize_state(gb);
   1353     GB_rewind_invalidate_for_backstepping(gb);
   1354     gb->apu_output.sample_fraction = 0;
   1355     return 0;
   1356 }
   1357 
   1358 int GB_load_state(GB_gameboy_t *gb, const char *path)
   1359 {
   1360     GB_ASSERT_NOT_RUNNING(gb)
   1361     FILE *f = fopen(path, "rb");
   1362     if (!f) {
   1363         GB_log(gb, "Could not open save state: %s.\n", strerror(errno));
   1364         return errno;
   1365     }
   1366     virtual_file_t file = {
   1367         .read = file_read,
   1368         .seek = file_seek,
   1369         .tell = file_tell,
   1370         .file = f,
   1371     };
   1372     int ret = load_state_internal(gb, &file);
   1373     fclose(f);
   1374     return ret;
   1375 }
   1376 
   1377 int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t length)
   1378 {
   1379     GB_ASSERT_NOT_RUNNING(gb)
   1380     virtual_file_t file = {
   1381         .read = buffer_read,
   1382         .seek = buffer_seek,
   1383         .tell = buffer_tell,
   1384         .buffer = (uint8_t *)buffer,
   1385         .position = 0,
   1386         .size = length,
   1387     };
   1388     
   1389     return load_state_internal(gb, &file);
   1390 }
   1391 
   1392 static int get_state_model_bess(virtual_file_t *file, GB_model_t *model)
   1393 {
   1394     file->seek(file, -sizeof(BESS_footer_t), SEEK_END);
   1395     BESS_footer_t footer = {0, };
   1396     file->read(file, &footer, sizeof(footer));
   1397     if (footer.magic != BE32('BESS')) {
   1398         return -1;
   1399     }
   1400 
   1401     file->seek(file, LE32(footer.start_offset), SEEK_SET);
   1402     while (true) {
   1403         BESS_block_t block;
   1404         if (file->read(file, &block, sizeof(block)) != sizeof(block)) return errno;
   1405         switch (block.magic) {
   1406             case BE32('CORE'): {
   1407                 BESS_CORE_t core = {0,};
   1408                 if (LE32(block.size) > sizeof(core) - sizeof(block)) {
   1409                     if (file->read(file, &core.header + 1, sizeof(core) - sizeof(block)) != sizeof(core) - sizeof(block)) return errno;
   1410                     file->seek(file, LE32(block.size) - (sizeof(core) - sizeof(block)), SEEK_CUR);
   1411                 }
   1412                 else {
   1413                     if (file->read(file, &core.header + 1, LE32(block.size)) != LE32(block.size)) return errno;
   1414                 }
   1415                 
   1416                 switch (core.full_model) {
   1417                     case BE32('GDB '): *model = GB_MODEL_DMG_B; return 0;
   1418                     case BE32('GM  '): *model = GB_MODEL_MGB; return 0;
   1419                     case BE32('SN  '): *model = GB_MODEL_SGB_NTSC_NO_SFC; return 0;
   1420                     case BE32('SP  '): *model = GB_MODEL_SGB_PAL; return 0;
   1421                     case BE32('S2  '): *model = GB_MODEL_SGB2; return 0;
   1422                     case BE32('CC0 '): *model = GB_MODEL_CGB_0; return 0;
   1423                     case BE32('CCA '): *model = GB_MODEL_CGB_A; return 0;
   1424                     case BE32('CCB '): *model = GB_MODEL_CGB_B; return 0;
   1425                     case BE32('CCC '): *model = GB_MODEL_CGB_C; return 0;
   1426                     case BE32('CCD '): *model = GB_MODEL_CGB_D; return 0;
   1427                     case BE32('CCE '): *model = GB_MODEL_CGB_E; return 0;
   1428                     case BE32('CAA '): *model = GB_MODEL_AGB_A; return 0;
   1429                 }
   1430                 return -1;
   1431                 
   1432             default:
   1433                 file->seek(file, LE32(block.size), SEEK_CUR);
   1434                 break;
   1435             }
   1436         }
   1437     }
   1438     return -1;
   1439 }
   1440 
   1441 
   1442 static int get_state_model_internal(virtual_file_t *file, GB_model_t *model)
   1443 {
   1444     GB_gameboy_t save;
   1445     
   1446     
   1447     if (file->read(file, GB_GET_SECTION(&save, header), GB_SECTION_SIZE(header)) != GB_SECTION_SIZE(header)) return errno;
   1448     if (save.magic != GB_state_magic()) {
   1449         return get_state_model_bess(file, model);
   1450     }
   1451     if (!READ_SECTION(&save, file, core_state)) return errno ?: EIO;
   1452     *model = save.model;
   1453     return 0;
   1454 }
   1455 
   1456 int GB_get_state_model(const char *path, GB_model_t *model)
   1457 {
   1458     FILE *f = fopen(path, "rb");
   1459     if (!f) {
   1460         return errno;
   1461     }
   1462     virtual_file_t file = {
   1463         .read = file_read,
   1464         .seek = file_seek,
   1465         .tell = file_tell,
   1466         .file = f,
   1467     };
   1468     int ret = get_state_model_internal(&file, model);
   1469     fclose(f);
   1470     return ret;
   1471 }
   1472 
   1473 int GB_get_state_model_from_buffer(const uint8_t *buffer, size_t length, GB_model_t *model)
   1474 {
   1475     virtual_file_t file = {
   1476         .read = buffer_read,
   1477         .seek = buffer_seek,
   1478         .tell = buffer_tell,
   1479         .buffer = (uint8_t *)buffer,
   1480         .position = 0,
   1481         .size = length,
   1482     };
   1483     
   1484     return get_state_model_internal(&file, model);
   1485 }
   1486 
   1487 
   1488 bool GB_is_save_state(const char *path)
   1489 {
   1490     bool ret = false;
   1491     FILE *f = fopen(path, "rb");
   1492     if (!f) return false;
   1493     uint32_t magic = 0;
   1494     fread(&magic, sizeof(magic), 1, f);
   1495     if (magic == GB_state_magic()) {
   1496         ret = true;
   1497         goto exit;
   1498     }
   1499     
   1500     fseek(f, -sizeof(magic), SEEK_END);
   1501     fread(&magic, sizeof(magic), 1, f);
   1502     if (magic == BE32('BESS')) {
   1503         ret = true;
   1504     }
   1505     
   1506 exit:
   1507     fclose(f);
   1508     return ret;
   1509 }

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.