src/core/rewind.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/core/rewind.h>
7
8#include <mgba/core/core.h>
9#include <mgba-util/patch/fast.h>
10#include <mgba-util/vfs.h>
11
12DEFINE_VECTOR(mCoreRewindPatches, struct PatchFast);
13
14void mCoreRewindContextInit(struct mCoreRewindContext* context, size_t entries) {
15 mCoreRewindPatchesInit(&context->patchMemory, entries);
16 size_t e;
17 for (e = 0; e < entries; ++e) {
18 initPatchFast(mCoreRewindPatchesAppend(&context->patchMemory));
19 }
20 context->previousState = VFileMemChunk(0, 0);
21 context->currentState = VFileMemChunk(0, 0);
22 context->size = 0;
23}
24
25void mCoreRewindContextDeinit(struct mCoreRewindContext* context) {
26 context->previousState->close(context->previousState);
27 context->currentState->close(context->currentState);
28 size_t s;
29 for (s = 0; s < mCoreRewindPatchesSize(&context->patchMemory); ++s) {
30 deinitPatchFast(mCoreRewindPatchesGetPointer(&context->patchMemory, s));
31 }
32 mCoreRewindPatchesDeinit(&context->patchMemory);
33}
34
35void mCoreRewindAppend(struct mCoreRewindContext* context, struct mCore* core) {
36 struct VFile* nextState = context->previousState;
37 ++context->current;
38 if (context->size < mCoreRewindPatchesSize(&context->patchMemory)) {
39 ++context->size;
40 }
41 if (context->current >= mCoreRewindPatchesSize(&context->patchMemory)) {
42 context->current = 0;
43 }
44 mCoreSaveStateNamed(core, nextState, 0);
45 struct PatchFast* patch = mCoreRewindPatchesGetPointer(&context->patchMemory, context->current);
46 size_t size2 = nextState->size(nextState);
47 size_t size = context->currentState->size(context->currentState);
48 if (size2 > size) {
49 context->currentState->truncate(context->currentState, size2);
50 size = size2;
51 }
52 void* current = context->currentState->map(context->currentState, size, MAP_READ);
53 void* next = nextState->map(nextState, size, MAP_READ);
54 diffPatchFast(patch, current, next, size);
55 context->currentState->unmap(context->currentState, current, size);
56 nextState->unmap(next, nextState, size);
57 context->previousState = context->currentState;
58 context->currentState = nextState;
59}
60
61bool mCoreRewindRestore(struct mCoreRewindContext* context, struct mCore* core) {
62 if (!context->size) {
63 return false;
64 }
65 --context->size;
66
67 struct PatchFast* patch = mCoreRewindPatchesGetPointer(&context->patchMemory, context->current);
68 size_t size2 = context->previousState->size(context->previousState);
69 size_t size = context->currentState->size(context->currentState);
70 if (size2 < size) {
71 size = size2;
72 }
73 void* current = context->currentState->map(context->currentState, size, MAP_READ);
74 void* previous = context->previousState->map(context->previousState, size, MAP_WRITE);
75 patch->d.applyPatch(&patch->d, current, size, previous, size);
76 context->currentState->unmap(context->currentState, current, size);
77 context->previousState->unmap(context->previousState, previous, size);
78 mCoreLoadStateNamed(core, context->previousState, 0);
79 struct VFile* nextState = context->previousState;
80 context->previousState = context->currentState;
81 context->currentState = nextState;
82
83 if (context->current == 0) {
84 context->current = mCoreRewindPatchesSize(&context->patchMemory);
85 }
86 --context->current;
87 return true;
88}