void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf, bool writeback) { enum SavedataType type = savedata->type; GBASavedataDeinit(savedata); savedata->vf = vf; savedata->mapMode = MAP_READ; savedata->maskWriteback = writeback; GBASavedataForceType(savedata, type, savedata->realisticTiming); }
void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf, bool writeback) { enum SavedataType type = savedata->type; struct VFile* oldVf = savedata->vf; GBASavedataDeinit(savedata); if (oldVf && oldVf != savedata->realVf) { oldVf->close(oldVf); } savedata->vf = vf; savedata->mapMode = MAP_READ; savedata->maskWriteback = writeback; GBASavedataForceType(savedata, type); }
void GBASavedataUnmask(struct GBASavedata* savedata) { if (!savedata->realVf || savedata->vf == savedata->realVf) { return; } enum SavedataType type = savedata->type; struct VFile* vf = savedata->vf; GBASavedataDeinit(savedata); savedata->vf = savedata->realVf; savedata->mapMode = MAP_WRITE; GBASavedataForceType(savedata, type); if (savedata->maskWriteback) { GBASavedataLoad(savedata, vf); savedata->maskWriteback = false; } vf->close(vf); }
bool GBASavedataImportSharkPort(struct GBA* gba, struct VFile* vf, bool testChecksum) { union { char c[0x1C]; int32_t i; } buffer; if (vf->read(vf, &buffer.i, 4) < 4) { return false; } int32_t size; LOAD_32(size, 0, &buffer.i); if (size != (int32_t) strlen(SHARKPORT_HEADER)) { return false; } if (vf->read(vf, buffer.c, size) < size) { return false; } if (memcmp(SHARKPORT_HEADER, buffer.c, size) != 0) { return false; } if (vf->read(vf, &buffer.i, 4) < 4) { return false; } LOAD_32(size, 0, &buffer.i); if (size != 0x000F0000) { // What is this value? return false; } // Skip first three fields if (vf->read(vf, &buffer.i, 4) < 4) { return false; } LOAD_32(size, 0, &buffer.i); if (vf->seek(vf, size, SEEK_CUR) < 0) { return false; } if (vf->read(vf, &buffer.i, 4) < 4) { return false; } LOAD_32(size, 0, &buffer.i); if (vf->seek(vf, size, SEEK_CUR) < 0) { return false; } if (vf->read(vf, &buffer.i, 4) < 4) { return false; } LOAD_32(size, 0, &buffer.i); if (vf->seek(vf, size, SEEK_CUR) < 0) { return false; } // Read payload if (vf->read(vf, &buffer.i, 4) < 4) { return false; } LOAD_32(size, 0, &buffer.i); if (size < 0x1C || size > SIZE_CART_FLASH1M + 0x1C) { return false; } char* payload = malloc(size); if (vf->read(vf, payload, size) < size) { goto cleanup; } struct GBACartridge* cart = (struct GBACartridge*) gba->memory.rom; memcpy(buffer.c, &cart->title, 16); buffer.c[0x10] = 0; buffer.c[0x11] = 0; buffer.c[0x12] = cart->checksum; buffer.c[0x13] = cart->maker; buffer.c[0x14] = 1; buffer.c[0x15] = 0; buffer.c[0x16] = 0; buffer.c[0x17] = 0; buffer.c[0x18] = 0; buffer.c[0x19] = 0; buffer.c[0x1A] = 0; buffer.c[0x1B] = 0; if (memcmp(buffer.c, payload, 0x1C) != 0) { goto cleanup; } uint32_t checksum; if (vf->read(vf, &buffer.i, 4) < 4) { goto cleanup; } LOAD_32(checksum, 0, &buffer.i); if (testChecksum) { uint32_t calcChecksum = 0; int i; for (i = 0; i < size; ++i) { calcChecksum += ((int32_t) payload[i]) << (calcChecksum % 24); } if (calcChecksum != checksum) { goto cleanup; } } uint32_t copySize = size - 0x1C; switch (gba->memory.savedata.type) { case SAVEDATA_SRAM: if (copySize > SIZE_CART_SRAM) { copySize = SIZE_CART_SRAM; } break; case SAVEDATA_FLASH512: if (copySize > SIZE_CART_FLASH512) { GBASavedataForceType(&gba->memory.savedata, SAVEDATA_FLASH1M, gba->memory.savedata.realisticTiming); } // Fall through case SAVEDATA_FLASH1M: if (copySize > SIZE_CART_FLASH1M) { copySize = SIZE_CART_FLASH1M; } break; case SAVEDATA_EEPROM: if (copySize > SIZE_CART_EEPROM) { copySize = SAVEDATA_EEPROM; } break; case SAVEDATA_FORCE_NONE: case SAVEDATA_AUTODETECT: goto cleanup; } memcpy(gba->memory.savedata.data, &payload[0x1C], copySize); free(payload); return true; cleanup: free(payload); return false; }