Annotation of src/games/adventure/save.c, Revision 1.15
1.15 ! mrg 1: /* $NetBSD: save.c,v 1.14 2014/03/22 22:04:40 dholland Exp $ */
1.2 cgd 2:
1.1 jtc 3: /*-
4: * Copyright (c) 1991, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * The game adventure was originally written in Fortran by Will Crowther
8: * and Don Woods. It was later translated to C and enhanced by Jim
9: * Gillogly. This code is derived from software contributed to Berkeley
10: * by Jim Gillogly at The Rand Corporation.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
1.8 agc 20: * 3. Neither the name of the University nor the names of its contributors
1.1 jtc 21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
1.3 christos 37: #include <sys/cdefs.h>
1.1 jtc 38: #ifndef lint
1.2 cgd 39: #if 0
1.1 jtc 40: static char sccsid[] = "@(#)save.c 8.1 (Berkeley) 5/31/93";
1.2 cgd 41: #else
1.15 ! mrg 42: __RCSID("$NetBSD: save.c,v 1.14 2014/03/22 22:04:40 dholland Exp $");
1.2 cgd 43: #endif
1.4 lukem 44: #endif /* not lint */
1.1 jtc 45:
1.12 dholland 46: #include <sys/types.h>
47: #include <sys/time.h>
48: #include <stdbool.h>
1.1 jtc 49: #include <stdio.h>
1.3 christos 50: #include <stdlib.h>
1.12 dholland 51: #include <err.h>
52: #include <assert.h>
53:
1.1 jtc 54: #include "hdr.h"
1.3 christos 55: #include "extern.h"
1.1 jtc 56:
1.12 dholland 57: struct savefile {
58: FILE *f;
59: const char *name;
60: bool warned;
1.14 dholland 61: size_t bintextpos;
1.12 dholland 62: uint32_t key;
1.13 dholland 63: struct crcstate crc;
1.12 dholland 64: unsigned char pad[8];
65: unsigned padpos;
66: };
67:
68: #define BINTEXT_WIDTH 60
1.13 dholland 69: #define FORMAT_VERSION 2
70: #define FORMAT_VERSION_NOSUM 1
1.12 dholland 71: static const char header[] = "Adventure save file\n";
72:
73: ////////////////////////////////////////////////////////////
74: // base16 output encoding
75:
76: /*
77: * Map 16 plain values into 90 coded values and back.
78: */
79:
1.15 ! mrg 80: static const char coding[91] =
1.12 dholland 81: "Db.GOyT]7a6zpF(c*5H9oK~0[WVAg&kR)ml,2^q-1Y3v+"
82: "X/=JirZL$C>_N?:}B{dfnsxU<@MQ%8|P!4h`ESt;euwIj"
83: ;
84:
85: static int
86: readletter(char letter, unsigned char *ret)
87: {
88: const char *s;
89:
90: s = strchr(coding, letter);
91: if (s == NULL) {
92: return 1;
93: }
94: *ret = (s - coding) % 16;
95: return 0;
96: }
97:
98: static char
99: writeletter(unsigned char nibble)
100: {
101: unsigned code;
102:
103: assert(nibble < 16);
104: do {
105: code = (16 * (random() % 6)) + nibble;
106: } while (code >= 90);
107: return coding[code];
108: }
109:
110: ////////////////////////////////////////////////////////////
111: // savefile
112:
113: /*
114: * Open a savefile.
115: */
116: static struct savefile *
117: savefile_open(const char *name, bool forwrite)
118: {
119: struct savefile *sf;
120:
121: sf = malloc(sizeof(*sf));
122: if (sf == NULL) {
123: return NULL;
124: }
125: sf->f = fopen(name, forwrite ? "w" : "r");
126: if (sf->f == NULL) {
127: free(sf);
128: fprintf(stderr,
129: "Hmm. The name \"%s\" appears to be magically blocked.\n",
130: name);
131: return NULL;
132: }
133: sf->name = name;
134: sf->warned = false;
135: sf->bintextpos = 0;
136: sf->key = 0;
1.13 dholland 137: crc_start(&sf->crc);
1.12 dholland 138: memset(sf->pad, 0, sizeof(sf->pad));
139: sf->padpos = 0;
140: return sf;
141: }
142:
143: /*
144: * Raw read.
145: */
146: static int
147: savefile_rawread(struct savefile *sf, void *data, size_t len)
148: {
149: size_t result;
150:
151: result = fread(data, 1, len, sf->f);
152: if (result != len || ferror(sf->f)) {
153: fprintf(stderr, "Oops: error reading %s.\n", sf->name);
154: sf->warned = true;
155: return 1;
156: }
157: return 0;
158: }
159:
160: /*
161: * Raw write.
162: */
163: static int
164: savefile_rawwrite(struct savefile *sf, const void *data, size_t len)
165: {
166: size_t result;
167:
168: result = fwrite(data, 1, len, sf->f);
169: if (result != len || ferror(sf->f)) {
170: fprintf(stderr, "Oops: error writing %s.\n", sf->name);
171: sf->warned = true;
172: return 1;
173: }
174: return 0;
175: }
176:
177: /*
178: * Close a savefile.
179: */
180: static int
181: savefile_close(struct savefile *sf)
182: {
183: int ret;
184:
185: if (sf->bintextpos > 0) {
186: savefile_rawwrite(sf, "\n", 1);
187: }
188:
189: ret = 0;
190: if (fclose(sf->f)) {
191: if (!sf->warned) {
192: fprintf(stderr, "Oops: error on %s.\n", sf->name);
193: }
194: ret = 1;
195: }
196: free(sf);
197: return ret;
198: }
199:
200: /*
201: * Read encoded binary data, discarding any whitespace that appears.
202: */
203: static int
204: savefile_bintextread(struct savefile *sf, void *data, size_t len)
205: {
206: size_t pos;
207: unsigned char *udata;
208: int ch;
209:
210: udata = data;
211: pos = 0;
212: while (pos < len) {
213: ch = fgetc(sf->f);
214: if (ch == EOF || ferror(sf->f)) {
215: fprintf(stderr, "Oops: error reading %s.\n", sf->name);
216: sf->warned = true;
217: return 1;
218: }
219: if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
220: continue;
221: }
222: udata[pos++] = ch;
223: }
224: return 0;
225: }
226:
227: /*
228: * Read binary data, decoding from text using readletter().
229: */
230: static int
231: savefile_binread(struct savefile *sf, void *data, size_t len)
232: {
233: unsigned char buf[64];
234: unsigned char *udata;
235: unsigned char val1, val2;
236: size_t pos, amt, i;
237:
238: udata = data;
239: pos = 0;
240: while (pos < len) {
241: amt = len - pos;
242: if (amt > sizeof(buf) / 2) {
243: amt = sizeof(buf) / 2;
244: }
245: if (savefile_bintextread(sf, buf, amt*2)) {
246: return 1;
247: }
248: for (i=0; i<amt; i++) {
249: if (readletter(buf[i*2], &val1)) {
250: return 1;
251: }
252: if (readletter(buf[i*2 + 1], &val2)) {
253: return 1;
254: }
255: udata[pos++] = val1 * 16 + val2;
256: }
257: }
258: return 0;
259: }
260:
261: /*
262: * Write encoded binary data, inserting newlines to get a neatly
263: * formatted block.
264: */
265: static int
266: savefile_bintextwrite(struct savefile *sf, const void *data, size_t len)
267: {
268: size_t pos, amt;
269: const unsigned char *udata;
270:
271: udata = data;
272: pos = 0;
273: while (pos < len) {
274: amt = BINTEXT_WIDTH - sf->bintextpos;
275: if (amt > len - pos) {
276: amt = len - pos;
277: }
278: if (savefile_rawwrite(sf, udata + pos, amt)) {
279: return 1;
280: }
281: pos += amt;
282: sf->bintextpos += amt;
283: if (sf->bintextpos >= BINTEXT_WIDTH) {
284: savefile_rawwrite(sf, "\n", 1);
285: sf->bintextpos = 0;
286: }
287: }
288: return 0;
289: }
290:
291: /*
292: * Write binary data, encoding as text using writeletter().
293: */
294: static int
295: savefile_binwrite(struct savefile *sf, const void *data, size_t len)
296: {
297: unsigned char buf[64];
298: const unsigned char *udata;
299: size_t pos, bpos;
300: unsigned char byte;
301:
302: udata = data;
303: pos = 0;
304: bpos = 0;
305: while (pos < len) {
306: byte = udata[pos++];
307: buf[bpos++] = writeletter(byte >> 4);
308: buf[bpos++] = writeletter(byte & 0xf);
309: if (bpos >= sizeof(buf)) {
310: if (savefile_bintextwrite(sf, buf, bpos)) {
311: return 1;
312: }
313: bpos = 0;
314: }
315: }
316: if (savefile_bintextwrite(sf, buf, bpos)) {
317: return 1;
318: }
319: return 0;
320: }
321:
322: /*
323: * Lightweight "encryption" for save files. This is not meant to
324: * be secure and wouldn't be even if we didn't write the decrypt
325: * key to the beginning of the save file; it's just meant to be
326: * enough to discourage casual cheating.
327: */
328:
329: /*
330: * Make cheesy hash of buf[0..buflen]. Note: buf and outhash may overlap.
331: */
332: static void
333: hash(const void *data, size_t datalen, unsigned char *out, size_t outlen)
334: {
335: const unsigned char *udata;
336: size_t i;
337: uint64_t val;
338: const unsigned char *uval;
339: size_t valpos;
340:
341: udata = data;
342: val = 0;
343: for (i=0; i<datalen; i++) {
344: val = val ^ 0xbadc0ffee;
345: val = (val << 4) | (val >> 60);
1.14 dholland 346: val += udata[i] ^ 0xbeefU;
1.12 dholland 347: }
348:
349: uval = (unsigned char *)&val;
350: valpos = 0;
351: for (i=0; i<outlen; i++) {
352: out[i] = uval[valpos++];
353: if (valpos >= sizeof(val)) {
354: valpos = 0;
355: }
356: }
357: }
358:
359: /*
360: * Set the "encryption" key.
361: */
362: static void
363: savefile_key(struct savefile *sf, uint32_t key)
364: {
365: sf->key = 0;
1.13 dholland 366: crc_start(&sf->crc);
1.12 dholland 367: hash(&sf->key, sizeof(sf->key), sf->pad, sizeof(sf->pad));
368: sf->padpos = 0;
369: }
370:
371: /*
372: * Get an "encryption" pad byte. This forms a stream "cipher" that we
373: * xor with the plaintext save data.
374: */
375: static unsigned char
376: savefile_getpad(struct savefile *sf)
377: {
378: unsigned char ret;
379:
380: ret = sf->pad[sf->padpos++];
381: if (sf->padpos >= sizeof(sf->pad)) {
382: hash(sf->pad, sizeof(sf->pad), sf->pad, sizeof(sf->pad));
383: sf->padpos = 0;
384: }
385: return ret;
386: }
387:
388: /*
389: * Read "encrypted" data.
390: */
391: static int
392: savefile_cread(struct savefile *sf, void *data, size_t len)
393: {
394: char buf[64];
395: unsigned char *udata;
396: size_t pos, amt, i;
397: unsigned char ch;
398:
399: udata = data;
400: pos = 0;
401: while (pos < len) {
402: amt = len - pos;
403: if (amt > sizeof(buf)) {
404: amt = sizeof(buf);
405: }
406: if (savefile_binread(sf, buf, amt)) {
407: return 1;
408: }
409: for (i=0; i<amt; i++) {
410: ch = buf[i];
411: ch ^= savefile_getpad(sf);
412: udata[pos + i] = ch;
413: }
414: pos += amt;
415: }
1.13 dholland 416: crc_add(&sf->crc, data, len);
1.12 dholland 417: return 0;
418: }
419:
420: /*
421: * Write "encrypted" data.
422: */
423: static int
424: savefile_cwrite(struct savefile *sf, const void *data, size_t len)
425: {
426: char buf[64];
427: const unsigned char *udata;
428: size_t pos, amt, i;
429: unsigned char ch;
430:
431: udata = data;
432: pos = 0;
433: while (pos < len) {
434: amt = len - pos;
435: if (amt > sizeof(buf)) {
436: amt = sizeof(buf);
437: }
438: for (i=0; i<amt; i++) {
439: ch = udata[pos + i];
440: ch ^= savefile_getpad(sf);
441: buf[i] = ch;
442: }
443: if (savefile_binwrite(sf, buf, amt)) {
444: return 1;
445: }
446: pos += amt;
447: }
1.13 dholland 448: crc_add(&sf->crc, data, len);
1.12 dholland 449: return 0;
450: }
451:
452: ////////////////////////////////////////////////////////////
453: // compat for old save files
454:
455: struct compat_saveinfo {
1.4 lukem 456: void *address;
1.14 dholland 457: size_t width;
1.1 jtc 458: };
459:
1.12 dholland 460: static const struct compat_saveinfo compat_savearray[] =
1.1 jtc 461: {
1.4 lukem 462: {&abbnum, sizeof(abbnum)},
463: {&attack, sizeof(attack)},
464: {&blklin, sizeof(blklin)},
465: {&bonus, sizeof(bonus)},
466: {&chloc, sizeof(chloc)},
467: {&chloc2, sizeof(chloc2)},
468: {&clock1, sizeof(clock1)},
469: {&clock2, sizeof(clock2)},
470: {&closed, sizeof(closed)},
1.11 dholland 471: {&isclosing, sizeof(isclosing)},
472: {&daltloc, sizeof(daltloc)},
1.4 lukem 473: {&demo, sizeof(demo)},
474: {&detail, sizeof(detail)},
475: {&dflag, sizeof(dflag)},
476: {&dkill, sizeof(dkill)},
477: {&dtotal, sizeof(dtotal)},
478: {&foobar, sizeof(foobar)},
479: {&gaveup, sizeof(gaveup)},
1.11 dholland 480: {&holding, sizeof(holding)},
1.4 lukem 481: {&iwest, sizeof(iwest)},
482: {&k, sizeof(k)},
483: {&k2, sizeof(k2)},
484: {&knfloc, sizeof(knfloc)},
485: {&kq, sizeof(kq)},
1.11 dholland 486: {&latency, sizeof(latency)},
1.4 lukem 487: {&limit, sizeof(limit)},
488: {&lmwarn, sizeof(lmwarn)},
489: {&loc, sizeof(loc)},
490: {&maxdie, sizeof(maxdie)},
1.11 dholland 491: {&maxscore, sizeof(maxscore)},
1.4 lukem 492: {&newloc, sizeof(newloc)},
493: {&numdie, sizeof(numdie)},
494: {&obj, sizeof(obj)},
1.11 dholland 495: {&oldloc2, sizeof(oldloc2)},
1.4 lukem 496: {&oldloc, sizeof(oldloc)},
497: {&panic, sizeof(panic)},
1.6 hubertf 498: {&saveday, sizeof(saveday)},
1.4 lukem 499: {&savet, sizeof(savet)},
1.11 dholland 500: {&scoring, sizeof(scoring)},
1.4 lukem 501: {&spk, sizeof(spk)},
502: {&stick, sizeof(stick)},
503: {&tally, sizeof(tally)},
504: {&tally2, sizeof(tally2)},
505: {&tkk, sizeof(tkk)},
506: {&turns, sizeof(turns)},
507: {&verb, sizeof(verb)},
508: {&wd1, sizeof(wd1)},
509: {&wd2, sizeof(wd2)},
1.11 dholland 510: {&wasdark, sizeof(wasdark)},
1.4 lukem 511: {&yea, sizeof(yea)},
512: {atloc, sizeof(atloc)},
513: {dloc, sizeof(dloc)},
514: {dseen, sizeof(dseen)},
515: {fixed, sizeof(fixed)},
516: {hinted, sizeof(hinted)},
517: {links, sizeof(links)},
518: {odloc, sizeof(odloc)},
519: {place, sizeof(place)},
520: {prop, sizeof(prop)},
521: {tk, sizeof(tk)},
1.1 jtc 522:
1.4 lukem 523: {NULL, 0}
1.1 jtc 524: };
525:
1.12 dholland 526: static int
527: compat_restore(const char *infile)
1.1 jtc 528: {
1.4 lukem 529: FILE *in;
1.12 dholland 530: const struct compat_saveinfo *p;
1.4 lukem 531: char *s;
532: long sum, cksum = 0;
1.14 dholland 533: size_t i;
1.13 dholland 534: struct crcstate crc;
1.4 lukem 535:
536: if ((in = fopen(infile, "rb")) == NULL) {
537: fprintf(stderr,
538: "Hmm. The file \"%s\" appears to be magically blocked.\n",
539: infile);
540: return 1;
1.1 jtc 541: }
1.4 lukem 542: fread(&sum, sizeof(sum), 1, in); /* Get the seed */
1.1 jtc 543: srandom((int) sum);
1.12 dholland 544: for (p = compat_savearray; p->address != NULL; p++) {
1.1 jtc 545: fread(p->address, p->width, 1, in);
546: for (s = p->address, i = 0; i < p->width; i++, s++)
1.4 lukem 547: *s = (*s ^ random()) & 0xFF; /* Lightly decrypt */
1.1 jtc 548: }
549: fclose(in);
550:
1.13 dholland 551: crc_start(&crc); /* See if she cheated */
1.12 dholland 552: for (p = compat_savearray; p->address != NULL; p++)
1.13 dholland 553: crc_add(&crc, p->address, p->width);
554: cksum = crc_get(&crc);
1.4 lukem 555: if (sum != cksum) /* Tsk tsk */
556: return 2; /* Altered the file */
1.1 jtc 557: /* We successfully restored, so this really was a save file */
1.12 dholland 558:
559: /*
560: * The above code loads these from disk even though they're
561: * pointers. Null them out and hope we don't crash on them
562: * later; that's better than having them be garbage.
563: */
564: tkk = NULL;
565: wd1 = NULL;
566: wd2 = NULL;
567:
568: return 0;
569: }
570:
571: ////////////////////////////////////////////////////////////
572: // save + restore
573:
574: static int *const save_ints[] = {
575: &abbnum,
576: &attack,
577: &blklin,
578: &bonus,
579: &chloc,
580: &chloc2,
581: &clock1,
582: &clock2,
583: &closed,
584: &isclosing,
585: &daltloc,
586: &demo,
587: &detail,
588: &dflag,
589: &dkill,
590: &dtotal,
591: &foobar,
592: &gaveup,
593: &holding,
594: &iwest,
595: &k,
596: &k2,
597: &knfloc,
598: &kq,
599: &latency,
600: &limit,
601: &lmwarn,
602: &loc,
603: &maxdie,
604: &maxscore,
605: &newloc,
606: &numdie,
607: &obj,
608: &oldloc2,
609: &oldloc,
610: &panic,
611: &saveday,
612: &savet,
613: &scoring,
614: &spk,
615: &stick,
616: &tally,
617: &tally2,
618: &turns,
619: &verb,
620: &wasdark,
621: &yea,
622: };
623: static const unsigned num_save_ints = __arraycount(save_ints);
624:
625: #define INTARRAY(sym) { sym, __arraycount(sym) }
626:
627: static const struct {
628: int *ptr;
629: unsigned num;
630: } save_intarrays[] = {
631: INTARRAY(atloc),
632: INTARRAY(dseen),
633: INTARRAY(dloc),
634: INTARRAY(odloc),
635: INTARRAY(fixed),
636: INTARRAY(hinted),
637: INTARRAY(links),
638: INTARRAY(place),
639: INTARRAY(prop),
640: INTARRAY(tk),
641: };
642: static const unsigned num_save_intarrays = __arraycount(save_intarrays);
643:
644: #undef INTARRAY
645:
646: #if 0
647: static const struct {
648: void *ptr;
649: size_t len;
650: } save_blobs[] = {
651: { &wd1, sizeof(wd1) },
652: { &wd2, sizeof(wd2) },
653: { &tkk, sizeof(tkk) },
654: };
655: static const unsigned num_save_blobs = __arraycount(save_blobs);
656: #endif
657:
658: /*
659: * Write out a save file. Returns nonzero on error.
660: */
661: int
662: save(const char *outfile)
663: {
664: struct savefile *sf;
665: struct timespec now;
666: uint32_t key, writeable_key;
667: uint32_t version;
668: unsigned i, j, n;
1.13 dholland 669: uint32_t val, sum;
1.12 dholland 670:
671: sf = savefile_open(outfile, true);
672: if (sf == NULL) {
673: return 1;
674: }
675:
676: if (savefile_rawwrite(sf, header, strlen(header))) {
677: savefile_close(sf);
678: return 1;
679: }
680:
681: version = htonl(FORMAT_VERSION);
682: if (savefile_binwrite(sf, &version, sizeof(version))) {
683: savefile_close(sf);
684: return 1;
685: }
686:
687: clock_gettime(CLOCK_REALTIME, &now);
688: key = (uint32_t)(now.tv_sec & 0xffffffff) ^ (uint32_t)(now.tv_nsec);
689:
690: writeable_key = htonl(key);
691: if (savefile_binwrite(sf, &writeable_key, sizeof(writeable_key))) {
692: savefile_close(sf);
693: return 1;
694: }
695:
696: /* other parts of the code may depend on us doing this here */
697: srandom(key);
698:
699: savefile_key(sf, key);
700:
701: /*
702: * Integers
703: */
704: for (i=0; i<num_save_ints; i++) {
705: val = *(save_ints[i]);
706: val = htonl(val);
707: if (savefile_cwrite(sf, &val, sizeof(val))) {
708: savefile_close(sf);
709: return 1;
710: }
711: }
712:
713: /*
714: * Arrays of integers
715: */
716: for (i=0; i<num_save_intarrays; i++) {
717: n = save_intarrays[i].num;
718: for (j=0; j<n; j++) {
719: val = save_intarrays[i].ptr[j];
720: val = htonl(val);
721: if (savefile_cwrite(sf, &val, sizeof(val))) {
722: savefile_close(sf);
723: return 1;
724: }
725: }
726: }
727:
728: #if 0
729: /*
730: * Blobs
731: */
732: for (i=0; i<num_save_blobs; i++) {
733: if (savefile_cwrite(sf, save_blobs[i].ptr, save_blobs[i].len)) {
734: savefile_close(sf);
735: return 1;
736: }
737: }
738: #endif
739:
1.13 dholland 740: sum = htonl(crc_get(&sf->crc));
741: if (savefile_binwrite(sf, &sum, sizeof(&sum))) {
1.12 dholland 742: savefile_close(sf);
743: return 1;
744: }
745: savefile_close(sf);
746: return 0;
747: }
748:
749: /*
750: * Read in a save file. Returns nonzero on error.
751: */
752: int
753: restore(const char *infile)
754: {
755: struct savefile *sf;
756: char buf[sizeof(header)];
757: size_t headersize = strlen(header);
758: uint32_t version, key, sum;
759: unsigned i, j, n;
760: uint32_t val;
1.13 dholland 761: bool skipsum = false;
1.12 dholland 762:
763: sf = savefile_open(infile, false);
764: if (sf == NULL) {
765: return 1;
766: }
767:
768: if (savefile_rawread(sf, buf, headersize)) {
769: savefile_close(sf);
770: return 1;
771: }
772: buf[headersize] = 0;
773: if (strcmp(buf, header) != 0) {
774: savefile_close(sf);
775: fprintf(stderr, "Oh dear, that isn't one of my save files.\n");
776: fprintf(stderr,
777: "Trying the Olde Waye; this myte notte Worke.\n");
778: return compat_restore(infile);
779: }
780:
781: if (savefile_binread(sf, &version, sizeof(version))) {
782: savefile_close(sf);
783: return 1;
784: }
785: version = ntohl(version);
1.13 dholland 786: switch (version) {
787: case FORMAT_VERSION:
788: break;
789: case FORMAT_VERSION_NOSUM:
790: skipsum = true;
791: break;
792: default:
1.12 dholland 793: savefile_close(sf);
794: fprintf(stderr,
795: "Oh dear, that file must be from the future. I don't know"
796: " how to read it!\n");
797: return 1;
798: }
799:
800: if (savefile_binread(sf, &key, sizeof(key))) {
801: savefile_close(sf);
802: return 1;
803: }
804: key = ntohl(key);
805: savefile_key(sf, key);
806:
807: /* other parts of the code may depend on us doing this here */
808: srandom(key);
809:
810: /*
811: * Integers
812: */
813: for (i=0; i<num_save_ints; i++) {
814: if (savefile_cread(sf, &val, sizeof(val))) {
815: savefile_close(sf);
816: return 1;
817: }
818: val = ntohl(val);
819: *(save_ints[i]) = val;
820: }
821:
822: /*
823: * Arrays of integers
824: */
825: for (i=0; i<num_save_intarrays; i++) {
826: n = save_intarrays[i].num;
827: for (j=0; j<n; j++) {
828: if (savefile_cread(sf, &val, sizeof(val))) {
829: savefile_close(sf);
830: return 1;
831: }
832: val = ntohl(val);
833: save_intarrays[i].ptr[j] = val;
834: }
835: }
836:
837: #if 0
838: /*
839: * Blobs
840: */
841: for (i=0; i<num_save_blobs; i++) {
842: if (savefile_cread(sf, save_blobs[i].ptr, save_blobs[i].len)) {
843: savefile_close(sf);
844: return 1;
845: }
846: }
847: #endif
848:
849: if (savefile_binread(sf, &sum, sizeof(&sum))) {
850: savefile_close(sf);
851: return 1;
852: }
853: sum = ntohl(sum);
854: /* See if she cheated */
1.13 dholland 855: if (!skipsum && sum != crc_get(&sf->crc)) {
1.12 dholland 856: /* Tsk tsk, altered the file */
857: savefile_close(sf);
858: return 2;
859: }
860: savefile_close(sf);
861:
862: /* Load theoretically invalidates these */
863: tkk = NULL;
864: wd1 = NULL;
865: wd2 = NULL;
866:
1.1 jtc 867: return 0;
868: }
CVSweb <webmaster@jp.NetBSD.org>