Develop and Download Open Source Software

Browse CVS Repository

Contents of /mame32jp/mame32jp/src/state.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.5 - (show annotations) (download) (as text)
Wed Apr 24 03:53:20 2002 UTC (21 years, 11 months ago) by zero
Branch: MAIN
CVS Tags: ver_0_60_1, ver0_59_13, ver0_59_14, ver0_60_2, ver0_60_3, ver0_60_4, ver0_60_5, HEAD
Changes since 1.4: +0 -0 lines
File MIME type: text/x-csrc
*** empty log message ***

1 /* State save/load functions */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include <stdarg.h>
7 #include "driver.h"
8 #include "zlib.h"
9
10 /* Save state file format:
11 *
12 * 0.. 7 'MAMESAVE"
13 * 8 Format version (this is format 1)
14 * 9 Flags
15 * a..13 Game name padded with \0
16 * 14..17 Signature
17 * 18..end Save game data
18 */
19
20 /* Available flags */
21 enum {
22 SS_NO_SOUND = 0x01,
23 SS_MSB_FIRST = 0x02
24 };
25
26 //#define VERBOSE
27
28 #ifdef VERBOSE
29 #define TRACE(x) do {x;} while(0)
30 #else
31 #define TRACE(x)
32 #endif
33
34 enum {MAX_INSTANCES = 25};
35
36 enum {
37 SS_INT8,
38 SS_UINT8,
39 SS_INT16,
40 SS_UINT16,
41 SS_INT32,
42 SS_UINT32,
43 SS_INT,
44 SS_DOUBLE
45 };
46
47 #ifdef VERBOSE
48 static const char *ss_type[] = { "i8", "u8", "i16", "u16", "i32", "u32", "int", "dbl" };
49 #endif
50 static int ss_size[] = { 1, 1, 2, 2, 4, 4, 4, 8 };
51
52 static void ss_c2(unsigned char *, unsigned);
53 static void ss_c4(unsigned char *, unsigned);
54 static void ss_c8(unsigned char *, unsigned);
55
56 static void (*ss_conv[])(unsigned char *, unsigned) = {
57 0, 0, ss_c2, ss_c2, ss_c4, ss_c4, 0, ss_c8
58 };
59
60
61 typedef struct ss_entry {
62 struct ss_entry *next;
63 char *name;
64 int type;
65 void *data;
66 unsigned size;
67 int tag;
68 unsigned offset;
69 } ss_entry;
70
71 typedef struct ss_module {
72 struct ss_module *next;
73 char *name;
74 ss_entry *instances[MAX_INSTANCES];
75 } ss_module;
76
77 static ss_module *ss_registry;
78
79 typedef struct ss_func {
80 struct ss_func *next;
81 void (*func)(void);
82 int tag;
83 } ss_func;
84
85 static ss_func *ss_prefunc_reg;
86 static ss_func *ss_postfunc_reg;
87 static int ss_current_tag;
88
89 static unsigned char *ss_dump_array;
90 static void *ss_dump_file;
91 static unsigned int ss_dump_size;
92
93
94 static UINT32 ss_get_signature(void)
95 {
96 ss_module *m;
97 unsigned int size = 0, pos = 0;
98 char *info;
99 UINT32 signature;
100
101 // Pass 1 : compute size
102
103 for(m = ss_registry; m; m=m->next) {
104 int i;
105 size += strlen(m->name) + 1;
106 for(i=0; i<MAX_INSTANCES; i++) {
107 ss_entry *e;
108 size++;
109 for(e = m->instances[i]; e; e=e->next)
110 size += strlen(e->name) + 1 + 1 + 4;
111 }
112 }
113
114 info = malloc(size);
115
116 // Pass 2 : write signature info
117
118 for(m = ss_registry; m; m=m->next) {
119 int i;
120 strcpy(info+pos, m->name);
121 pos += strlen(m->name) + 1;
122 for(i=0; i<MAX_INSTANCES; i++) {
123 ss_entry *e;
124 info[pos++] = i;
125 for(e = m->instances[i]; e; e=e->next) {
126 strcpy(info+pos, e->name);
127 pos += strlen(e->name) + 1;
128 info[pos++] = e->type;
129 info[pos++] = e->size;
130 info[pos++] = e->size >> 8;
131 info[pos++] = e->size >> 16;
132 info[pos++] = e->size >> 24;
133 }
134 }
135 }
136
137 // Pass 3 : Compute the crc32
138 signature = crc32(0, (unsigned char *)info, size);
139
140 free(info);
141 return signature;
142 }
143
144 void state_save_reset(void)
145 {
146 ss_func *f;
147 ss_module *m = ss_registry;
148 while(m) {
149 ss_module *mn = m->next;
150 int i;
151 for(i=0; i<MAX_INSTANCES; i++) {
152 ss_entry *e = m->instances[i];
153 while(e) {
154 ss_entry *en = e->next;
155 free(e->name);
156 free(e);
157 e = en;
158 }
159 }
160 free(m->name);
161 m = mn;
162 }
163 ss_registry = 0;
164
165 f = ss_prefunc_reg;
166 while(f) {
167 ss_func *fn = f->next;
168 free(f);
169 f = fn;
170 }
171 ss_prefunc_reg = 0;
172
173 f = ss_postfunc_reg;
174 while(f) {
175 ss_func *fn = f->next;
176 free(f);
177 f = fn;
178 }
179 ss_postfunc_reg = 0;
180
181 ss_current_tag = 0;
182 ss_dump_array = 0;
183 ss_dump_file = 0;
184 ss_dump_size = 0;
185 }
186
187 static ss_module *ss_get_module(const char *name)
188 {
189 int i;
190 ss_module **mp = &ss_registry;
191 ss_module *m;
192 while((m = *mp) != 0) {
193 int pos = strcmp(m->name, name);
194 if(!pos)
195 return m;
196 if(pos>0)
197 break;
198 mp = &((*mp)->next);
199 }
200 *mp = malloc(sizeof(ss_module));
201 if (*mp == NULL) return NULL;
202 (*mp)->name = malloc (strlen (name) + 1);
203 if ((*mp)->name == NULL) return NULL;
204 strcpy ((*mp)->name, name);
205 (*mp)->next = m;
206 for(i=0; i<MAX_INSTANCES; i++)
207 (*mp)->instances[i] = 0;
208 return *mp;
209 }
210
211 static ss_entry *ss_register_entry(const char *module, int instance, const char *name, int type, void *data, unsigned size)
212 {
213 ss_module *m = ss_get_module(module);
214 ss_entry **ep = &(m->instances[instance]);
215 ss_entry *e = *ep;
216 while((e = *ep) != 0) {
217 int pos = strcmp(e->name, name);
218 if(!pos) {
219 logerror("Duplicate save state registration entry (%s, %d, %s)\n", module, instance, name);
220 return NULL;
221 }
222 if(pos>0)
223 break;
224 ep = &((*ep)->next);
225 }
226 *ep = malloc(sizeof(ss_entry));
227 if (*ep == NULL) return NULL;
228 (*ep)->name = malloc (strlen (name) + 1);
229 if ((*ep)->name == NULL) return NULL;
230 strcpy ((*ep)->name, name);
231 (*ep)->next = e;
232 (*ep)->type = type;
233 (*ep)->data = data;
234 (*ep)->size = size;
235 (*ep)->offset = 0;
236 (*ep)->tag = ss_current_tag;
237 return *ep;
238 }
239
240 void state_save_register_UINT8 (const char *module, int instance,
241 const char *name, UINT8 *val, unsigned size)
242 {
243 ss_register_entry(module, instance, name, SS_UINT8, val, size);
244 }
245
246 void state_save_register_INT8 (const char *module, int instance,
247 const char *name, INT8 *val, unsigned size)
248 {
249 ss_register_entry(module, instance, name, SS_INT8, val, size);
250 }
251
252 void state_save_register_UINT16(const char *module, int instance,
253 const char *name, UINT16 *val, unsigned size)
254 {
255 ss_register_entry(module, instance, name, SS_UINT16, val, size);
256 }
257
258 void state_save_register_INT16 (const char *module, int instance,
259 const char *name, INT16 *val, unsigned size)
260 {
261 ss_register_entry(module, instance, name, SS_INT16, val, size);
262 }
263
264 void state_save_register_UINT32(const char *module, int instance,
265 const char *name, UINT32 *val, unsigned size)
266 {
267 ss_register_entry(module, instance, name, SS_UINT32, val, size);
268 }
269
270 void state_save_register_INT32 (const char *module, int instance,
271 const char *name, INT32 *val, unsigned size)
272 {
273 ss_register_entry(module, instance, name, SS_INT32, val, size);
274 }
275
276 void state_save_register_int (const char *module, int instance,
277 const char *name, int *val)
278 {
279 ss_register_entry(module, instance, name, SS_INT, val, 1);
280 }
281
282 void state_save_register_double(const char *module, int instance,
283 const char *name, double *val, unsigned size)
284 {
285 ss_register_entry(module, instance, name, SS_DOUBLE, val, size);
286 }
287
288
289
290 static void ss_register_func(ss_func **root, void (*func)(void))
291 {
292 ss_func *next = *root;
293 while (next)
294 {
295 if (next->func == func && next->tag == ss_current_tag)
296 {
297 logerror("Duplicate save state function (%d, 0x%x)\n", ss_current_tag, func);
298 exit(1);
299 }
300 next = next->next;
301 }
302 next = *root;
303 *root = malloc(sizeof(ss_func));
304 if (*root == NULL)
305 {
306 logerror ("malloc failed in ss_register_func\n");
307 return;
308 }
309 (*root)->next = next;
310 (*root)->func = func;
311 (*root)->tag = ss_current_tag;
312 }
313
314 void state_save_register_func_presave(void (*func)(void))
315 {
316 ss_register_func(&ss_prefunc_reg, func);
317 }
318
319 void state_save_register_func_postload(void (*func)(void))
320 {
321 ss_register_func(&ss_postfunc_reg, func);
322 }
323
324 void state_save_set_current_tag(int tag)
325 {
326 ss_current_tag = tag;
327 }
328
329 static void ss_c2(unsigned char *data, unsigned size)
330 {
331 unsigned i;
332 for(i=0; i<size; i++) {
333 unsigned char v;
334 v = data[0];
335 data[0] = data[1];
336 data[1] = v;
337 data += 2;
338 }
339 }
340
341 static void ss_c4(unsigned char *data, unsigned size)
342 {
343 unsigned i;
344 for(i=0; i<size; i++) {
345 unsigned char v;
346 v = data[0];
347 data[0] = data[3];
348 data[3] = v;
349 v = data[1];
350 data[1] = data[2];
351 data[2] = v;
352 data += 4;
353 }
354 }
355
356 static void ss_c8(unsigned char *data, unsigned size)
357 {
358 unsigned i;
359 for(i=0; i<size; i++) {
360 unsigned char v;
361 v = data[0];
362 data[0] = data[7];
363 data[7] = v;
364 v = data[1];
365 data[1] = data[6];
366 data[6] = v;
367 v = data[2];
368 data[2] = data[5];
369 data[5] = v;
370 v = data[3];
371 data[3] = data[4];
372 data[4] = v;
373 data += 8;
374 }
375 }
376
377
378 void state_save_save_begin(void *file)
379 {
380 ss_module *m;
381 TRACE(logerror("Beginning save\n"));
382 ss_dump_size = 0x18;
383 ss_dump_file = file;
384 for(m = ss_registry; m; m=m->next) {
385 int i;
386 for(i=0; i<MAX_INSTANCES; i++) {
387 ss_entry *e;
388 for(e = m->instances[i]; e; e=e->next) {
389 e->offset = ss_dump_size;
390 ss_dump_size += ss_size[e->type]*e->size;
391 }
392 }
393 }
394
395 TRACE(logerror(" total size %u\n", ss_dump_size));
396 ss_dump_array = malloc(ss_dump_size);
397 if (ss_dump_array == NULL)
398 {
399 logerror ("malloc failed in state_save_save_begin\n");
400 }
401 }
402
403 void state_save_save_continue(void)
404 {
405 ss_module *m;
406 ss_func * f;
407 int count = 0;
408 TRACE(logerror("Saving tag %d\n", ss_current_tag));
409 TRACE(logerror(" calling pre-save functions\n"));
410 f = ss_prefunc_reg;
411 while(f) {
412 if(f->tag == ss_current_tag) {
413 count++;
414 (f->func)();
415 }
416 f = f->next;
417 }
418 TRACE(logerror(" %d functions called\n", count));
419 TRACE(logerror(" copying data\n"));
420 for(m = ss_registry; m; m=m->next) {
421 int i;
422 for(i=0; i<MAX_INSTANCES; i++) {
423 ss_entry *e;
424 for(e = m->instances[i]; e; e=e->next)
425 if(e->tag == ss_current_tag) {
426 if(e->type == SS_INT) {
427 int v = *(int *)(e->data);
428 ss_dump_array[e->offset] = v ;
429 ss_dump_array[e->offset+1] = v >> 8;
430 ss_dump_array[e->offset+2] = v >> 16;
431 ss_dump_array[e->offset+3] = v >> 24;
432 TRACE(logerror(" %s.%d.%s: %x..%x\n", m->name, i, e->name, e->offset, e->offset+3));
433 } else {
434 memcpy(ss_dump_array + e->offset, e->data, ss_size[e->type]*e->size);
435 TRACE(logerror(" %s.%d.%s: %x..%x\n", m->name, i, e->name, e->offset, e->offset+ss_size[e->type]*e->size-1));
436 }
437 }
438 }
439 }
440 }
441
442 void state_save_save_finish(void)
443 {
444 UINT32 signature;
445 unsigned char flags = 0;
446
447 TRACE(logerror("Finishing save\n"));
448
449 signature = ss_get_signature();
450 if(!Machine->sample_rate)
451 flags |= SS_NO_SOUND;
452
453 #ifndef LSB_FIRST
454 flags |= SS_MSB_FIRST;
455 #endif
456
457 memcpy(ss_dump_array, "MAMESAVE", 8);
458 ss_dump_array[8] = 1;
459 ss_dump_array[9] = flags;
460 memset(ss_dump_array+0xa, 0, 10);
461 strcpy((char *)ss_dump_array+0xa, Machine->gamedrv->name);
462
463 ss_dump_array[0x14] = signature;
464 ss_dump_array[0x15] = signature >> 8;
465 ss_dump_array[0x16] = signature >> 16;
466 ss_dump_array[0x17] = signature >> 24;
467
468 osd_fwrite(ss_dump_file, ss_dump_array, ss_dump_size);
469 free(ss_dump_array);
470 ss_dump_array = 0;
471 ss_dump_size = 0;
472 ss_dump_file = 0;
473 }
474
475 int state_save_load_begin(void *file)
476 {
477 ss_module *m;
478 unsigned int offset = 0;
479 UINT32 signature, file_sig;
480
481 TRACE(logerror("Beginning load\n"));
482
483 signature = ss_get_signature();
484
485 ss_dump_size = osd_fsize(file);
486 ss_dump_array = malloc(ss_dump_size);
487 ss_dump_file = file;
488 osd_fread(ss_dump_file, ss_dump_array, ss_dump_size);
489
490 if(memcmp(ss_dump_array, "MAMESAVE", 8)) {
491 usrintf_showmessage("Error: This is not a mame save file");
492 goto bad;
493 }
494
495 if(ss_dump_array[8] != 1) {
496 usrintf_showmessage("Error: Wrong version in save file (%d, 1 expected)",
497 ss_dump_array[8]);
498 goto bad;
499 }
500
501 file_sig = ss_dump_array[0x14]
502 | (ss_dump_array[0x15] << 8)
503 | (ss_dump_array[0x16] << 16)
504 | (ss_dump_array[0x17] << 24);
505
506 if(file_sig != signature) {
507 usrintf_showmessage("Error: Incompatible save file (signature %08x, expected %08x)",
508 file_sig, signature);
509 goto bad;
510 }
511
512 if(ss_dump_array[9] & SS_NO_SOUND)
513 {
514 if(Machine->sample_rate)
515 usrintf_showmessage("Warning: Game was saved with sound off, but sound is on. Result may be interesting.");
516 }
517 else
518 {
519 if(!Machine->sample_rate)
520 usrintf_showmessage("Warning: Game was saved with sound on, but sound is off. Result may be interesting.");
521 }
522
523 offset = 0x18;
524 for(m = ss_registry; m; m=m->next) {
525 int i;
526 for(i=0; i<MAX_INSTANCES; i++) {
527 ss_entry *e;
528 for(e = m->instances[i]; e; e=e->next) {
529 e->offset = offset;
530 offset += ss_size[e->type]*e->size;
531 }
532 }
533 }
534 return 0;
535
536 bad:
537 free(ss_dump_array);
538 return 1;
539 }
540
541 void state_save_load_continue(void)
542 {
543 ss_module *m;
544 ss_func * f;
545 int count = 0;
546 int need_convert;
547
548 #ifdef LSB_FIRST
549 need_convert = (ss_dump_array[9] & SS_MSB_FIRST) != 0;
550 #else
551 need_convert = (ss_dump_array[9] & SS_MSB_FIRST) == 0;
552 #endif
553
554 TRACE(logerror("Loading tag %d\n", ss_current_tag));
555 TRACE(logerror(" copying data\n"));
556 for(m = ss_registry; m; m=m->next) {
557 int i;
558 for(i=0; i<MAX_INSTANCES; i++) {
559 ss_entry *e;
560 for(e = m->instances[i]; e; e=e->next)
561 if(e->tag == ss_current_tag) {
562 if(e->type == SS_INT) {
563 int v;
564 v = ss_dump_array[e->offset]
565 | (ss_dump_array[e->offset+1] << 8)
566 | (ss_dump_array[e->offset+2] << 16)
567 | (ss_dump_array[e->offset+3] << 24);
568 TRACE(logerror(" %s.%d.%s: %x..%x\n", m->name, i, e->name, e->offset, e->offset+3));
569 *(int *)(e->data) = v;
570 } else {
571 memcpy(e->data, ss_dump_array + e->offset, ss_size[e->type]*e->size);
572 if (need_convert && ss_conv[e->type])
573 ss_conv[e->type](e->data, e->size);
574 TRACE(logerror(" %s.%d.%s: %x..%x\n", m->name, i, e->name, e->offset, e->offset+ss_size[e->type]*e->size-1));
575 }
576 }
577 }
578 }
579 TRACE(logerror(" calling post-load functions\n"));
580 f = ss_postfunc_reg;
581 while(f) {
582 if(f->tag == ss_current_tag) {
583 count++;
584 (f->func)();
585 }
586 f = f->next;
587 }
588 TRACE(logerror(" %d functions called\n", count));
589 }
590
591 void state_save_load_finish(void)
592 {
593 TRACE(logerror("Finishing load\n"));
594 free(ss_dump_array);
595 ss_dump_array = 0;
596 ss_dump_size = 0;
597 ss_dump_file = 0;
598 }
599
600 void state_save_dump_registry(void)
601 {
602 #ifdef VERBOSE
603 ss_module *m;
604 for(m = ss_registry; m; m=m->next) {
605 int i;
606 for(i=0; i<MAX_INSTANCES; i++) {
607 ss_entry *e;
608 for(e = m->instances[i]; e; e=e->next)
609 logerror("%d %s.%d.%s: %s, %x\n", e->tag, m->name, i, e->name, ss_type[e->type], e->size);
610 }
611 }
612 #endif
613 }
614

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26