bool GBASavedataExportSharkPort(const struct GBA* gba, struct VFile* vf) { union { char c[0x1C]; int32_t i; } buffer; int32_t size = strlen(SHARKPORT_HEADER); STORE_32(size, 0, &buffer.i); if (vf->write(vf, &buffer.i, 4) < 4) { return false; } if (vf->write(vf, SHARKPORT_HEADER, size) < size) { return false; } size = 0x000F0000; STORE_32(size, 0, &buffer.i); if (vf->write(vf, &buffer.i, 4) < 4) { return false; } const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom; size = sizeof(cart->title); STORE_32(size, 0, &buffer.i); if (vf->write(vf, &buffer.i, 4) < 4) { return false; } if (vf->write(vf, cart->title, size) < 4) { return false; } time_t t = time(0); struct tm* tm = localtime(&t); size = strftime(&buffer.c[4], sizeof(buffer.c) - 4, "%m/%d/%Y %I:%M:%S %p", tm); STORE_32(size, 0, &buffer.i); if (vf->write(vf, buffer.c, size + 4) < size + 4) { return false; } // Last field is blank size = 0; STORE_32(size, 0, &buffer.i); if (vf->write(vf, &buffer.i, 4) < 4) { return false; } // Write payload size = 0x1C; switch (gba->memory.savedata.type) { case SAVEDATA_SRAM: size += SIZE_CART_SRAM; break; case SAVEDATA_FLASH512: size += SIZE_CART_FLASH512; break; case SAVEDATA_FLASH1M: size += SIZE_CART_FLASH1M; break; case SAVEDATA_EEPROM: size += SIZE_CART_EEPROM; break; case SAVEDATA_FORCE_NONE: case SAVEDATA_AUTODETECT: return false; } STORE_32(size, 0, &buffer.i); if (vf->write(vf, &buffer.i, 4) < 4) { return false; } size -= 0x1C; 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 (vf->write(vf, buffer.c, 0x1C) < 0x1C) { return false; } uint32_t checksum = 0; int i; for (i = 0; i < 0x1C; ++i) { checksum += buffer.c[i] << (checksum % 24); } if (vf->write(vf, gba->memory.savedata.data, size) < size) { return false; } for (i = 0; i < size; ++i) { checksum += ((char) gba->memory.savedata.data[i]) << (checksum % 24); } STORE_32(checksum, 0, &buffer.i); if (vf->write(vf, &buffer.i, 4) < 4) { return false; } return true; }
void GBASerialize(struct GBA* gba, struct GBASerializedState* state) { STORE_32(GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION, 0, &state->versionMagic); STORE_32(gba->biosChecksum, 0, &state->biosChecksum); STORE_32(gba->romCrc32, 0, &state->romCrc32); if (gba->memory.rom) { state->id = ((struct GBACartridge*) gba->memory.rom)->id; memcpy(state->title, ((struct GBACartridge*) gba->memory.rom)->title, sizeof(state->title)); } else { state->id = 0; memset(state->title, 0, sizeof(state->title)); } int i; for (i = 0; i < 16; ++i) { STORE_32(gba->cpu->gprs[i], i * sizeof(state->cpu.gprs[0]), state->cpu.gprs); } STORE_32(gba->cpu->cpsr.packed, 0, &state->cpu.cpsr.packed); STORE_32(gba->cpu->spsr.packed, 0, &state->cpu.spsr.packed); STORE_32(gba->cpu->cycles, 0, &state->cpu.cycles); STORE_32(gba->cpu->nextEvent, 0, &state->cpu.nextEvent); for (i = 0; i < 6; ++i) { int j; for (j = 0; j < 7; ++j) { STORE_32(gba->cpu->bankedRegisters[i][j], (i * 7 + j) * sizeof(gba->cpu->bankedRegisters[0][0]), state->cpu.bankedRegisters); } STORE_32(gba->cpu->bankedSPSRs[i], i * sizeof(gba->cpu->bankedSPSRs[0]), state->cpu.bankedSPSRs); } STORE_32(gba->memory.biosPrefetch, 0, &state->biosPrefetch); STORE_32(gba->cpu->prefetch[0], 0, state->cpuPrefetch); STORE_32(gba->cpu->prefetch[1], 4, state->cpuPrefetch); STORE_32(gba->memory.lastPrefetchedPc, 0, &state->lastPrefetchedPc); GBASerializedMiscFlags miscFlags = 0; miscFlags = GBASerializedMiscFlagsSetHalted(miscFlags, gba->cpu->halted); STORE_32(miscFlags, 0, &state->miscFlags); GBAMemorySerialize(&gba->memory, state); GBAIOSerialize(gba, state); GBAVideoSerialize(&gba->video, state); GBAAudioSerialize(&gba->audio, state); GBASavedataSerialize(&gba->memory.savedata, state); #ifndef _MSC_VER struct timeval tv; if (!gettimeofday(&tv, 0)) { uint64_t usec = tv.tv_usec; usec += tv.tv_sec * 1000000LL; STORE_64(usec, 0, &state->creationUsec); } #else struct timespec ts; if (timespec_get(&ts, TIME_UTC)) { uint64_t usec = ts.tv_nsec / 1000; usec += ts.tv_sec * 1000000LL; STORE_64(usec, 0, &state->creationUsec); } #endif else { state->creationUsec = 0; } state->associatedStreamId = 0; if (gba->rr) { gba->rr->stateSaved(gba->rr, state); } }