From 2bb16fd0a8cc7536085bc9172c515a613c2333e1 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 20 Jun 2015 00:49:50 -0700 Subject: [PATCH] GBA: Better savestate error reporting --- src/gba/serialize.c | 46 ++++++++++++++++++------------ src/gba/serialize.h | 2 +- src/platform/qt/GameController.cpp | 7 +++-- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/gba/serialize.c b/src/gba/serialize.c index c7a16f8ba..11a2a67cc 100644 --- a/src/gba/serialize.c +++ b/src/gba/serialize.c @@ -61,67 +61,71 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) { } } -void GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { +bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { + bool error = false; if (state->versionMagic != GBA_SAVESTATE_MAGIC) { GBALog(gba, GBA_LOG_WARN, "Invalid or too new savestate"); - return; + error = true; } if (state->biosChecksum != gba->biosChecksum) { GBALog(gba, GBA_LOG_WARN, "Savestate created using a different version of the BIOS"); if (state->cpu.gprs[ARM_PC] < SIZE_BIOS && state->cpu.gprs[ARM_PC] >= 0x20) { - return; + error = true; } } if (gba->memory.rom && (state->id != ((struct GBACartridge*) gba->memory.rom)->id || memcmp(state->title, ((struct GBACartridge*) gba->memory.rom)->title, sizeof(state->title)))) { GBALog(gba, GBA_LOG_WARN, "Savestate is for a different game"); - return; + error = true; } else if (!gba->memory.rom && state->id != 0) { GBALog(gba, GBA_LOG_WARN, "Savestate is for a game, but no game loaded"); - return; + error = true; } if (state->romCrc32 != gba->romCrc32) { GBALog(gba, GBA_LOG_WARN, "Savestate is for a different version of the game"); } if (state->cpu.cycles < 0) { GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: CPU cycles are negative"); - return; + error = true; } if (state->video.eventDiff < 0) { GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: video eventDiff is negative"); - return; + error = true; } if (state->video.nextHblank - state->video.eventDiff < 0) { GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: nextHblank is negative"); - return; + error = true; } if (state->timers[0].overflowInterval < 0 || state->timers[1].overflowInterval < 0 || state->timers[2].overflowInterval < 0 || state->timers[3].overflowInterval < 0) { GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: overflowInterval is negative"); - return; + error = true; } if (state->audio.eventDiff < 0) { GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: audio eventDiff is negative"); - return; + error = true; } if (state->audio.ch1.envelopeNextStep < 0 || state->audio.ch1.waveNextStep < 0 || state->audio.ch1.sweepNextStep < 0 || state->audio.ch1.nextEvent < 0) { GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: audio channel 1 register is negative"); - return; + error = true; } if (state->audio.ch2.envelopeNextStep < 0 || state->audio.ch2.waveNextStep < 0 || state->audio.ch2.nextEvent < 0) { GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: audio channel 2 register is negative"); - return; + error = true; } if (state->audio.ch3.nextEvent < 0) { GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: audio channel 3 register is negative"); - return; + error = true; } if (state->audio.ch4.envelopeNextStep < 0 || state->audio.ch4.nextEvent < 0) { GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: audio channel 4 register is negative"); - return; + error = true; } int region = (state->cpu.gprs[ARM_PC] >> BASE_OFFSET); if ((region == REGION_CART0 || region == REGION_CART1 || region == REGION_CART2) && ((state->cpu.gprs[ARM_PC] - WORD_SIZE_ARM) & SIZE_CART0) >= gba->memory.romSize - WORD_SIZE_ARM) { GBALog(gba, GBA_LOG_WARN, "Savestate created using a differently sized version of the ROM"); - return; + error = true; + } + if (error) { + return false; } memcpy(gba->cpu->gprs, state->cpu.gprs, sizeof(gba->cpu->gprs)); gba->cpu->cpsr = state->cpu.cpsr; @@ -166,6 +170,7 @@ void GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { if (gba->rr) { gba->rr->stateLoaded(gba->rr, state); } + return true; } struct VFile* GBAGetState(struct GBA* gba, struct VDir* dir, int slot, bool write) { @@ -218,8 +223,7 @@ static int _loadPNGChunkHandler(png_structp png, png_unknown_chunkp chunk) { struct GBASerializedState state; uLongf len = sizeof(state); uncompress((Bytef*) &state, &len, chunk->data, chunk->size); - GBADeserialize(png_get_user_chunk_ptr(png), &state); - return 1; + return GBADeserialize(png_get_user_chunk_ptr(png), &state); } static bool _loadPNGState(struct GBA* gba, struct VFile* vf) { @@ -254,6 +258,8 @@ bool GBASaveState(struct GBAThread* threadContext, struct VDir* dir, int slot, b vf->close(vf); if (success) { GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i saved", slot); + } else { + GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i failed to save", slot); } return success; } @@ -268,6 +274,8 @@ bool GBALoadState(struct GBAThread* threadContext, struct VDir* dir, int slot) { vf->close(vf); if (success) { GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i loaded", slot); + } else { + GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i failed to load", slot); } return success; } @@ -304,9 +312,9 @@ bool GBALoadStateNamed(struct GBA* gba, struct VFile* vf) { if (!state) { return false; } - GBADeserialize(gba, state); + bool success = GBADeserialize(gba, state); vf->unmap(vf, state, sizeof(struct GBASerializedState)); - return true; + return success; } struct GBASerializedState* GBAAllocateState(void) { diff --git a/src/gba/serialize.h b/src/gba/serialize.h index c9d1fd00c..1ccfd123c 100644 --- a/src/gba/serialize.h +++ b/src/gba/serialize.h @@ -321,7 +321,7 @@ struct VDir; struct GBAThread; void GBASerialize(struct GBA* gba, struct GBASerializedState* state); -void GBADeserialize(struct GBA* gba, const struct GBASerializedState* state); +bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state); bool GBASaveState(struct GBAThread* thread, struct VDir* dir, int slot, bool screenshot); bool GBALoadState(struct GBAThread* thread, struct VDir* dir, int slot); diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index abae7a5e2..860a08d66 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -573,9 +573,10 @@ void GameController::loadState(int slot) { } GBARunOnThread(&m_threadContext, [](GBAThread* context) { GameController* controller = static_cast(context->userData); - GBALoadState(context, context->stateDir, controller->m_stateSlot); - controller->stateLoaded(context); - controller->frameAvailable(controller->m_drawContext); + if (GBALoadState(context, context->stateDir, controller->m_stateSlot)) { + controller->stateLoaded(context); + controller->frameAvailable(controller->m_drawContext); + } }); }