]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - adventure/save.c
cgram(6): use standard cursor keys, use standard shuffle algorithm
[bsdgames-darwin.git] / adventure / save.c
1 /* $NetBSD: save.c,v 1.14 2014/03/22 22:04:40 dholland Exp $ */
2
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.
20 * 3. Neither the name of the University nor the names of its contributors
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
37 #include <sys/cdefs.h>
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)save.c 8.1 (Berkeley) 5/31/93";
41 #else
42 __RCSID("$NetBSD: save.c,v 1.14 2014/03/22 22:04:40 dholland Exp $");
43 #endif
44 #endif /* not lint */
45
46 #include <sys/types.h>
47 #include <sys/time.h>
48 #include <stdbool.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <err.h>
52 #include <assert.h>
53
54 #include "hdr.h"
55 #include "extern.h"
56
57 struct savefile {
58 FILE *f;
59 const char *name;
60 bool warned;
61 size_t bintextpos;
62 uint32_t key;
63 struct crcstate crc;
64 unsigned char pad[8];
65 unsigned padpos;
66 };
67
68 #define BINTEXT_WIDTH 60
69 #define FORMAT_VERSION 2
70 #define FORMAT_VERSION_NOSUM 1
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
80 static const char coding[90] =
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;
137 crc_start(&sf->crc);
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);
346 val += udata[i] ^ 0xbeefU;
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;
366 crc_start(&sf->crc);
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 }
416 crc_add(&sf->crc, data, len);
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 }
448 crc_add(&sf->crc, data, len);
449 return 0;
450 }
451
452 ////////////////////////////////////////////////////////////
453 // compat for old save files
454
455 struct compat_saveinfo {
456 void *address;
457 size_t width;
458 };
459
460 static const struct compat_saveinfo compat_savearray[] =
461 {
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)},
471 {&isclosing, sizeof(isclosing)},
472 {&daltloc, sizeof(daltloc)},
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)},
480 {&holding, sizeof(holding)},
481 {&iwest, sizeof(iwest)},
482 {&k, sizeof(k)},
483 {&k2, sizeof(k2)},
484 {&knfloc, sizeof(knfloc)},
485 {&kq, sizeof(kq)},
486 {&latency, sizeof(latency)},
487 {&limit, sizeof(limit)},
488 {&lmwarn, sizeof(lmwarn)},
489 {&loc, sizeof(loc)},
490 {&maxdie, sizeof(maxdie)},
491 {&maxscore, sizeof(maxscore)},
492 {&newloc, sizeof(newloc)},
493 {&numdie, sizeof(numdie)},
494 {&obj, sizeof(obj)},
495 {&oldloc2, sizeof(oldloc2)},
496 {&oldloc, sizeof(oldloc)},
497 {&panic, sizeof(panic)},
498 {&saveday, sizeof(saveday)},
499 {&savet, sizeof(savet)},
500 {&scoring, sizeof(scoring)},
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)},
510 {&wasdark, sizeof(wasdark)},
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)},
522
523 {NULL, 0}
524 };
525
526 static int
527 compat_restore(const char *infile)
528 {
529 FILE *in;
530 const struct compat_saveinfo *p;
531 char *s;
532 long sum, cksum = 0;
533 size_t i;
534 struct crcstate crc;
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;
541 }
542 fread(&sum, sizeof(sum), 1, in); /* Get the seed */
543 srandom((int) sum);
544 for (p = compat_savearray; p->address != NULL; p++) {
545 fread(p->address, p->width, 1, in);
546 for (s = p->address, i = 0; i < p->width; i++, s++)
547 *s = (*s ^ random()) & 0xFF; /* Lightly decrypt */
548 }
549 fclose(in);
550
551 crc_start(&crc); /* See if she cheated */
552 for (p = compat_savearray; p->address != NULL; p++)
553 crc_add(&crc, p->address, p->width);
554 cksum = crc_get(&crc);
555 if (sum != cksum) /* Tsk tsk */
556 return 2; /* Altered the file */
557 /* We successfully restored, so this really was a save file */
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;
669 uint32_t val, sum;
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
740 sum = htonl(crc_get(&sf->crc));
741 if (savefile_binwrite(sf, &sum, sizeof(&sum))) {
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;
761 bool skipsum = false;
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);
786 switch (version) {
787 case FORMAT_VERSION:
788 break;
789 case FORMAT_VERSION_NOSUM:
790 skipsum = true;
791 break;
792 default:
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 */
855 if (!skipsum && sum != crc_get(&sf->crc)) {
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
867 return 0;
868 }