1 /*****************************************************************************
2 ** $Source: /cvsroot/bluemsx/blueMSX/Src/Utils/SaveState.c,v $
3 **
4 ** $Revision: 1.5 $
5 **
6 ** $Date: 2008/06/25 22:26:17 $
7 **
8 ** More info: http://www.bluemsx.com
9 **
10 ** Copyright (C) 2003-2006 Daniel Vik
11 **
12 ** This program is free software; you can redistribute it and/or modify
13 ** it under the terms of the GNU General Public License as published by
14 ** the Free Software Foundation; either version 2 of the License, or
15 ** (at your option) any later version.
16 **
17 ** This program is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ** GNU General Public License for more details.
21 **
22 ** You should have received a copy of the GNU General Public License
23 ** along with this program; if not, write to the Free Software
24 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 **
26 ******************************************************************************
27 */
28 #include "SaveState.h"
29 #include "ziphelper.h"
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdio.h>
33
34 // Must be power of 2
35 #define ALLOC_BLOCK_SIZE 256
36
37 struct SaveState {
38 UInt32 allocSize;
39 UInt32 size;
40 UInt32 offset;
41 UInt32 *buffer;
42 char fileName[64];
43 };
44
45 static char stateFile[512];
46
tagFromName(const char * tagName)47 static UInt32 tagFromName(const char* tagName)
48 {
49 UInt32 tag = 0;
50 UInt32 mod = 1;
51
52 while (*tagName) {
53 mod *= 19219;
54 tag += mod * *tagName++;
55 }
56
57 return tag;
58 }
59
60 #if 0
61 static void checkTag(SaveState* state, const char* tagName)
62 {
63 UInt32 tag = tagFromName(tagName);
64 UInt32 offset = 0;
65
66 while (offset < state->offset) {
67 UInt32 elemTag = state->buffer[offset++];
68 UInt32 elemLen = state->buffer[offset++];
69 if (elemTag == tag) {
70 printf("Tag duplicated: %s : %d\n", state->fileName, tagName);
71 }
72 offset += (elemLen + sizeof(UInt32) - 1) / sizeof(UInt32);
73 }
74 }
75 #else
76 #define checkTag(state, tagName)
77 #endif
78
79 static struct {
80 char fileName[64];
81 int count;
82 } saveFileTable[128];
83
84 static int tableCount;
85
getIndexedFilename(const char * fileName)86 static char* getIndexedFilename(const char* fileName)
87 {
88 static char indexedFileName[64];
89 int i;
90
91 for (i = 0; i < tableCount; i++) {
92 if (0 == strcmp(fileName, saveFileTable[i].fileName)) {
93 sprintf(indexedFileName, "%s_%.2d", fileName, ++saveFileTable[i].count);
94 return indexedFileName;
95 }
96 }
97 strcpy(saveFileTable[tableCount].fileName, fileName);
98 saveFileTable[tableCount++].count = 0;
99
100 strcpy(indexedFileName, fileName);
101 strcat(indexedFileName, "_00");
102
103 return indexedFileName;
104 }
105
saveStateCreateForRead(const char * fileName)106 void saveStateCreateForRead(const char* fileName)
107 {
108 tableCount = 0;
109 strcpy(stateFile, fileName);
110 zipCacheReadOnlyZip(fileName);
111 }
112
saveStateCreateForWrite(const char * fileName)113 void saveStateCreateForWrite(const char* fileName)
114 {
115 tableCount = 0;
116 strcpy(stateFile, fileName);
117 }
118
saveStateDestroy(void)119 void saveStateDestroy(void)
120 {
121 zipCacheReadOnlyZip(NULL);
122 }
123
saveStateOpenForRead(const char * fileName)124 SaveState* saveStateOpenForRead(const char* fileName) {
125 SaveState* state = (SaveState*)malloc(sizeof(SaveState));
126 Int32 size = 0;
127 void* buffer = zipLoadFile(stateFile, getIndexedFilename(fileName), &size);
128
129 state->allocSize = size;
130 state->buffer = buffer;
131 state->size = size / sizeof(UInt32);
132 state->offset = 0;
133 state->fileName[0] = 0;
134
135 return state;
136 }
137
saveStateOpenForWrite(const char * fileName)138 SaveState* saveStateOpenForWrite(const char* fileName) {
139 SaveState* state = (SaveState*)malloc(sizeof(SaveState));
140
141 state->size = 0;
142 state->offset = 0;
143 state->buffer = NULL;
144 state->allocSize = 0;
145
146 strcpy(state->fileName, getIndexedFilename(fileName));
147
148 return state;
149 }
150
saveStateClose(SaveState * state)151 void saveStateClose(SaveState* state) {
152 if (state->fileName[0]) {
153 zipSaveFile(stateFile, state->fileName, 1, state->buffer, state->offset * sizeof(UInt32));
154 }
155 if (state->buffer != NULL) {
156 free(state->buffer);
157 }
158 state->allocSize = 0;
159 free(state);
160 }
161
stateExtendBuffer(SaveState * state,UInt32 extend)162 static void stateExtendBuffer(SaveState* state, UInt32 extend) {
163 state->size += extend;
164 if (state->size > state->allocSize)
165 {
166 state->allocSize = (state->size + ALLOC_BLOCK_SIZE - 1) & ~(ALLOC_BLOCK_SIZE - 1);
167 state->buffer = realloc(state->buffer, state->allocSize * sizeof(UInt32));
168 }
169 }
170
saveStateSet(SaveState * state,const char * tagName,UInt32 value)171 void saveStateSet(SaveState* state, const char* tagName, UInt32 value)
172 {
173 checkTag(state, tagName);
174
175 stateExtendBuffer(state, 3);
176 state->buffer[state->offset++] = tagFromName(tagName);
177 state->buffer[state->offset++] = sizeof(UInt32);
178 state->buffer[state->offset++] = value;
179 }
180
saveStateSetBuffer(SaveState * state,const char * tagName,void * buffer,UInt32 length)181 void saveStateSetBuffer(SaveState* state, const char* tagName, void* buffer, UInt32 length)
182 {
183 checkTag(state, tagName);
184
185 stateExtendBuffer(state, 2 + (length + sizeof(UInt32) - 1) / sizeof(UInt32));
186 state->buffer[state->offset++] = tagFromName(tagName);
187 state->buffer[state->offset++] = length;
188 memcpy(state->buffer + state->offset, buffer, length);
189 state->offset += (length + sizeof(UInt32) - 1) / sizeof(UInt32);
190 }
191
saveStateGet(SaveState * state,const char * tagName,UInt32 defValue)192 UInt32 saveStateGet(SaveState* state, const char* tagName, UInt32 defValue)
193 {
194 UInt32 tag = tagFromName(tagName);
195 UInt32 startOffset = state->offset;
196 UInt32 offset = state->offset;
197 UInt32 value = defValue;
198 UInt32 wrapAround = 0;
199 UInt32 elemTag;
200 UInt32 elemLen;
201
202 if (state->size == 0) {
203 return value;
204 }
205
206 do {
207 elemTag = state->buffer[offset++];
208 elemLen = state->buffer[offset++];
209 if (elemTag == tag) {
210 value = state->buffer[offset];
211 }
212 offset += (elemLen + sizeof(UInt32) - 1) / sizeof(UInt32);
213 if (offset >= state->size) {
214 if (++wrapAround > 1) {
215 break;
216 }
217 offset = 0;
218 }
219 } while (offset != startOffset && elemTag != tag);
220
221 return value;
222 }
223
saveStateGetBuffer(SaveState * state,const char * tagName,void * buffer,UInt32 length)224 void saveStateGetBuffer(SaveState* state, const char* tagName, void* buffer, UInt32 length)
225 {
226 UInt32 tag = tagFromName(tagName);
227 UInt32 startOffset = state->offset;
228 UInt32 offset = state->offset;
229 UInt32 wrapAround = 0;
230 UInt32 elemTag;
231 UInt32 elemLen;
232
233 if (state->size == 0) {
234 return;
235 }
236
237 do {
238 elemTag = state->buffer[offset++];
239 elemLen = state->buffer[offset++];
240 if (elemTag == tag) {
241 memcpy(buffer, state->buffer + offset, length < elemLen ? length : elemLen);
242 }
243 offset += (elemLen + sizeof(UInt32) - 1) / sizeof(UInt32);
244 if (offset >= state->size) {
245 if (++wrapAround > 1) {
246 break;
247 }
248 offset = 0;
249 }
250 } while (offset != startOffset && elemTag != tag);
251
252 state->offset = offset;
253 }
254