1*0a6a1f1dSLionel Sambuc /* $NetBSD: save.c,v 1.14 2014/03/22 22:04:40 dholland Exp $ */
20819c9f8SThomas Cort
30819c9f8SThomas Cort /*-
40819c9f8SThomas Cort * Copyright (c) 1991, 1993
50819c9f8SThomas Cort * The Regents of the University of California. All rights reserved.
60819c9f8SThomas Cort *
70819c9f8SThomas Cort * The game adventure was originally written in Fortran by Will Crowther
80819c9f8SThomas Cort * and Don Woods. It was later translated to C and enhanced by Jim
90819c9f8SThomas Cort * Gillogly. This code is derived from software contributed to Berkeley
100819c9f8SThomas Cort * by Jim Gillogly at The Rand Corporation.
110819c9f8SThomas Cort *
120819c9f8SThomas Cort * Redistribution and use in source and binary forms, with or without
130819c9f8SThomas Cort * modification, are permitted provided that the following conditions
140819c9f8SThomas Cort * are met:
150819c9f8SThomas Cort * 1. Redistributions of source code must retain the above copyright
160819c9f8SThomas Cort * notice, this list of conditions and the following disclaimer.
170819c9f8SThomas Cort * 2. Redistributions in binary form must reproduce the above copyright
180819c9f8SThomas Cort * notice, this list of conditions and the following disclaimer in the
190819c9f8SThomas Cort * documentation and/or other materials provided with the distribution.
200819c9f8SThomas Cort * 3. Neither the name of the University nor the names of its contributors
210819c9f8SThomas Cort * may be used to endorse or promote products derived from this software
220819c9f8SThomas Cort * without specific prior written permission.
230819c9f8SThomas Cort *
240819c9f8SThomas Cort * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
250819c9f8SThomas Cort * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
260819c9f8SThomas Cort * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
270819c9f8SThomas Cort * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
280819c9f8SThomas Cort * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
290819c9f8SThomas Cort * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
300819c9f8SThomas Cort * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
310819c9f8SThomas Cort * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
320819c9f8SThomas Cort * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
330819c9f8SThomas Cort * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
340819c9f8SThomas Cort * SUCH DAMAGE.
350819c9f8SThomas Cort */
360819c9f8SThomas Cort
370819c9f8SThomas Cort #include <sys/cdefs.h>
380819c9f8SThomas Cort #ifndef lint
390819c9f8SThomas Cort #if 0
400819c9f8SThomas Cort static char sccsid[] = "@(#)save.c 8.1 (Berkeley) 5/31/93";
410819c9f8SThomas Cort #else
42*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: save.c,v 1.14 2014/03/22 22:04:40 dholland Exp $");
430819c9f8SThomas Cort #endif
440819c9f8SThomas Cort #endif /* not lint */
450819c9f8SThomas Cort
460819c9f8SThomas Cort #include <sys/types.h>
470819c9f8SThomas Cort #include <sys/time.h>
480819c9f8SThomas Cort #include <stdbool.h>
490819c9f8SThomas Cort #include <stdio.h>
500819c9f8SThomas Cort #include <stdlib.h>
510819c9f8SThomas Cort #include <err.h>
520819c9f8SThomas Cort #include <assert.h>
530819c9f8SThomas Cort
540819c9f8SThomas Cort #include "hdr.h"
550819c9f8SThomas Cort #include "extern.h"
560819c9f8SThomas Cort
570819c9f8SThomas Cort struct savefile {
580819c9f8SThomas Cort FILE *f;
590819c9f8SThomas Cort const char *name;
600819c9f8SThomas Cort bool warned;
61*0a6a1f1dSLionel Sambuc size_t bintextpos;
620819c9f8SThomas Cort uint32_t key;
630819c9f8SThomas Cort struct crcstate crc;
640819c9f8SThomas Cort unsigned char pad[8];
650819c9f8SThomas Cort unsigned padpos;
660819c9f8SThomas Cort };
670819c9f8SThomas Cort
680819c9f8SThomas Cort #define BINTEXT_WIDTH 60
690819c9f8SThomas Cort #define FORMAT_VERSION 2
700819c9f8SThomas Cort #define FORMAT_VERSION_NOSUM 1
710819c9f8SThomas Cort static const char header[] = "Adventure save file\n";
720819c9f8SThomas Cort
730819c9f8SThomas Cort ////////////////////////////////////////////////////////////
740819c9f8SThomas Cort // base16 output encoding
750819c9f8SThomas Cort
760819c9f8SThomas Cort /*
770819c9f8SThomas Cort * Map 16 plain values into 90 coded values and back.
780819c9f8SThomas Cort */
790819c9f8SThomas Cort
800819c9f8SThomas Cort static const char coding[90] =
810819c9f8SThomas Cort "Db.GOyT]7a6zpF(c*5H9oK~0[WVAg&kR)ml,2^q-1Y3v+"
820819c9f8SThomas Cort "X/=JirZL$C>_N?:}B{dfnsxU<@MQ%8|P!4h`ESt;euwIj"
830819c9f8SThomas Cort ;
840819c9f8SThomas Cort
850819c9f8SThomas Cort static int
readletter(char letter,unsigned char * ret)860819c9f8SThomas Cort readletter(char letter, unsigned char *ret)
870819c9f8SThomas Cort {
880819c9f8SThomas Cort const char *s;
890819c9f8SThomas Cort
900819c9f8SThomas Cort s = strchr(coding, letter);
910819c9f8SThomas Cort if (s == NULL) {
920819c9f8SThomas Cort return 1;
930819c9f8SThomas Cort }
940819c9f8SThomas Cort *ret = (s - coding) % 16;
950819c9f8SThomas Cort return 0;
960819c9f8SThomas Cort }
970819c9f8SThomas Cort
980819c9f8SThomas Cort static char
writeletter(unsigned char nibble)990819c9f8SThomas Cort writeletter(unsigned char nibble)
1000819c9f8SThomas Cort {
1010819c9f8SThomas Cort unsigned code;
1020819c9f8SThomas Cort
1030819c9f8SThomas Cort assert(nibble < 16);
1040819c9f8SThomas Cort do {
1050819c9f8SThomas Cort code = (16 * (random() % 6)) + nibble;
1060819c9f8SThomas Cort } while (code >= 90);
1070819c9f8SThomas Cort return coding[code];
1080819c9f8SThomas Cort }
1090819c9f8SThomas Cort
1100819c9f8SThomas Cort ////////////////////////////////////////////////////////////
1110819c9f8SThomas Cort // savefile
1120819c9f8SThomas Cort
1130819c9f8SThomas Cort /*
1140819c9f8SThomas Cort * Open a savefile.
1150819c9f8SThomas Cort */
1160819c9f8SThomas Cort static struct savefile *
savefile_open(const char * name,bool forwrite)1170819c9f8SThomas Cort savefile_open(const char *name, bool forwrite)
1180819c9f8SThomas Cort {
1190819c9f8SThomas Cort struct savefile *sf;
1200819c9f8SThomas Cort
1210819c9f8SThomas Cort sf = malloc(sizeof(*sf));
1220819c9f8SThomas Cort if (sf == NULL) {
1230819c9f8SThomas Cort return NULL;
1240819c9f8SThomas Cort }
1250819c9f8SThomas Cort sf->f = fopen(name, forwrite ? "w" : "r");
1260819c9f8SThomas Cort if (sf->f == NULL) {
1270819c9f8SThomas Cort free(sf);
1280819c9f8SThomas Cort fprintf(stderr,
1290819c9f8SThomas Cort "Hmm. The name \"%s\" appears to be magically blocked.\n",
1300819c9f8SThomas Cort name);
1310819c9f8SThomas Cort return NULL;
1320819c9f8SThomas Cort }
1330819c9f8SThomas Cort sf->name = name;
1340819c9f8SThomas Cort sf->warned = false;
1350819c9f8SThomas Cort sf->bintextpos = 0;
1360819c9f8SThomas Cort sf->key = 0;
1370819c9f8SThomas Cort crc_start(&sf->crc);
1380819c9f8SThomas Cort memset(sf->pad, 0, sizeof(sf->pad));
1390819c9f8SThomas Cort sf->padpos = 0;
1400819c9f8SThomas Cort return sf;
1410819c9f8SThomas Cort }
1420819c9f8SThomas Cort
1430819c9f8SThomas Cort /*
1440819c9f8SThomas Cort * Raw read.
1450819c9f8SThomas Cort */
1460819c9f8SThomas Cort static int
savefile_rawread(struct savefile * sf,void * data,size_t len)1470819c9f8SThomas Cort savefile_rawread(struct savefile *sf, void *data, size_t len)
1480819c9f8SThomas Cort {
1490819c9f8SThomas Cort size_t result;
1500819c9f8SThomas Cort
1510819c9f8SThomas Cort result = fread(data, 1, len, sf->f);
1520819c9f8SThomas Cort if (result != len || ferror(sf->f)) {
1530819c9f8SThomas Cort fprintf(stderr, "Oops: error reading %s.\n", sf->name);
1540819c9f8SThomas Cort sf->warned = true;
1550819c9f8SThomas Cort return 1;
1560819c9f8SThomas Cort }
1570819c9f8SThomas Cort return 0;
1580819c9f8SThomas Cort }
1590819c9f8SThomas Cort
1600819c9f8SThomas Cort /*
1610819c9f8SThomas Cort * Raw write.
1620819c9f8SThomas Cort */
1630819c9f8SThomas Cort static int
savefile_rawwrite(struct savefile * sf,const void * data,size_t len)1640819c9f8SThomas Cort savefile_rawwrite(struct savefile *sf, const void *data, size_t len)
1650819c9f8SThomas Cort {
1660819c9f8SThomas Cort size_t result;
1670819c9f8SThomas Cort
1680819c9f8SThomas Cort result = fwrite(data, 1, len, sf->f);
1690819c9f8SThomas Cort if (result != len || ferror(sf->f)) {
1700819c9f8SThomas Cort fprintf(stderr, "Oops: error writing %s.\n", sf->name);
1710819c9f8SThomas Cort sf->warned = true;
1720819c9f8SThomas Cort return 1;
1730819c9f8SThomas Cort }
1740819c9f8SThomas Cort return 0;
1750819c9f8SThomas Cort }
1760819c9f8SThomas Cort
1770819c9f8SThomas Cort /*
1780819c9f8SThomas Cort * Close a savefile.
1790819c9f8SThomas Cort */
1800819c9f8SThomas Cort static int
savefile_close(struct savefile * sf)1810819c9f8SThomas Cort savefile_close(struct savefile *sf)
1820819c9f8SThomas Cort {
1830819c9f8SThomas Cort int ret;
1840819c9f8SThomas Cort
1850819c9f8SThomas Cort if (sf->bintextpos > 0) {
1860819c9f8SThomas Cort savefile_rawwrite(sf, "\n", 1);
1870819c9f8SThomas Cort }
1880819c9f8SThomas Cort
1890819c9f8SThomas Cort ret = 0;
1900819c9f8SThomas Cort if (fclose(sf->f)) {
1910819c9f8SThomas Cort if (!sf->warned) {
1920819c9f8SThomas Cort fprintf(stderr, "Oops: error on %s.\n", sf->name);
1930819c9f8SThomas Cort }
1940819c9f8SThomas Cort ret = 1;
1950819c9f8SThomas Cort }
1960819c9f8SThomas Cort free(sf);
1970819c9f8SThomas Cort return ret;
1980819c9f8SThomas Cort }
1990819c9f8SThomas Cort
2000819c9f8SThomas Cort /*
2010819c9f8SThomas Cort * Read encoded binary data, discarding any whitespace that appears.
2020819c9f8SThomas Cort */
2030819c9f8SThomas Cort static int
savefile_bintextread(struct savefile * sf,void * data,size_t len)2040819c9f8SThomas Cort savefile_bintextread(struct savefile *sf, void *data, size_t len)
2050819c9f8SThomas Cort {
2060819c9f8SThomas Cort size_t pos;
2070819c9f8SThomas Cort unsigned char *udata;
2080819c9f8SThomas Cort int ch;
2090819c9f8SThomas Cort
2100819c9f8SThomas Cort udata = data;
2110819c9f8SThomas Cort pos = 0;
2120819c9f8SThomas Cort while (pos < len) {
2130819c9f8SThomas Cort ch = fgetc(sf->f);
2140819c9f8SThomas Cort if (ch == EOF || ferror(sf->f)) {
2150819c9f8SThomas Cort fprintf(stderr, "Oops: error reading %s.\n", sf->name);
2160819c9f8SThomas Cort sf->warned = true;
2170819c9f8SThomas Cort return 1;
2180819c9f8SThomas Cort }
2190819c9f8SThomas Cort if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
2200819c9f8SThomas Cort continue;
2210819c9f8SThomas Cort }
2220819c9f8SThomas Cort udata[pos++] = ch;
2230819c9f8SThomas Cort }
2240819c9f8SThomas Cort return 0;
2250819c9f8SThomas Cort }
2260819c9f8SThomas Cort
2270819c9f8SThomas Cort /*
2280819c9f8SThomas Cort * Read binary data, decoding from text using readletter().
2290819c9f8SThomas Cort */
2300819c9f8SThomas Cort static int
savefile_binread(struct savefile * sf,void * data,size_t len)2310819c9f8SThomas Cort savefile_binread(struct savefile *sf, void *data, size_t len)
2320819c9f8SThomas Cort {
2330819c9f8SThomas Cort unsigned char buf[64];
2340819c9f8SThomas Cort unsigned char *udata;
2350819c9f8SThomas Cort unsigned char val1, val2;
2360819c9f8SThomas Cort size_t pos, amt, i;
2370819c9f8SThomas Cort
2380819c9f8SThomas Cort udata = data;
2390819c9f8SThomas Cort pos = 0;
2400819c9f8SThomas Cort while (pos < len) {
2410819c9f8SThomas Cort amt = len - pos;
2420819c9f8SThomas Cort if (amt > sizeof(buf) / 2) {
2430819c9f8SThomas Cort amt = sizeof(buf) / 2;
2440819c9f8SThomas Cort }
2450819c9f8SThomas Cort if (savefile_bintextread(sf, buf, amt*2)) {
2460819c9f8SThomas Cort return 1;
2470819c9f8SThomas Cort }
2480819c9f8SThomas Cort for (i=0; i<amt; i++) {
2490819c9f8SThomas Cort if (readletter(buf[i*2], &val1)) {
2500819c9f8SThomas Cort return 1;
2510819c9f8SThomas Cort }
2520819c9f8SThomas Cort if (readletter(buf[i*2 + 1], &val2)) {
2530819c9f8SThomas Cort return 1;
2540819c9f8SThomas Cort }
2550819c9f8SThomas Cort udata[pos++] = val1 * 16 + val2;
2560819c9f8SThomas Cort }
2570819c9f8SThomas Cort }
2580819c9f8SThomas Cort return 0;
2590819c9f8SThomas Cort }
2600819c9f8SThomas Cort
2610819c9f8SThomas Cort /*
2620819c9f8SThomas Cort * Write encoded binary data, inserting newlines to get a neatly
2630819c9f8SThomas Cort * formatted block.
2640819c9f8SThomas Cort */
2650819c9f8SThomas Cort static int
savefile_bintextwrite(struct savefile * sf,const void * data,size_t len)2660819c9f8SThomas Cort savefile_bintextwrite(struct savefile *sf, const void *data, size_t len)
2670819c9f8SThomas Cort {
2680819c9f8SThomas Cort size_t pos, amt;
2690819c9f8SThomas Cort const unsigned char *udata;
2700819c9f8SThomas Cort
2710819c9f8SThomas Cort udata = data;
2720819c9f8SThomas Cort pos = 0;
2730819c9f8SThomas Cort while (pos < len) {
2740819c9f8SThomas Cort amt = BINTEXT_WIDTH - sf->bintextpos;
2750819c9f8SThomas Cort if (amt > len - pos) {
2760819c9f8SThomas Cort amt = len - pos;
2770819c9f8SThomas Cort }
2780819c9f8SThomas Cort if (savefile_rawwrite(sf, udata + pos, amt)) {
2790819c9f8SThomas Cort return 1;
2800819c9f8SThomas Cort }
2810819c9f8SThomas Cort pos += amt;
2820819c9f8SThomas Cort sf->bintextpos += amt;
2830819c9f8SThomas Cort if (sf->bintextpos >= BINTEXT_WIDTH) {
2840819c9f8SThomas Cort savefile_rawwrite(sf, "\n", 1);
2850819c9f8SThomas Cort sf->bintextpos = 0;
2860819c9f8SThomas Cort }
2870819c9f8SThomas Cort }
2880819c9f8SThomas Cort return 0;
2890819c9f8SThomas Cort }
2900819c9f8SThomas Cort
2910819c9f8SThomas Cort /*
2920819c9f8SThomas Cort * Write binary data, encoding as text using writeletter().
2930819c9f8SThomas Cort */
2940819c9f8SThomas Cort static int
savefile_binwrite(struct savefile * sf,const void * data,size_t len)2950819c9f8SThomas Cort savefile_binwrite(struct savefile *sf, const void *data, size_t len)
2960819c9f8SThomas Cort {
2970819c9f8SThomas Cort unsigned char buf[64];
2980819c9f8SThomas Cort const unsigned char *udata;
2990819c9f8SThomas Cort size_t pos, bpos;
3000819c9f8SThomas Cort unsigned char byte;
3010819c9f8SThomas Cort
3020819c9f8SThomas Cort udata = data;
3030819c9f8SThomas Cort pos = 0;
3040819c9f8SThomas Cort bpos = 0;
3050819c9f8SThomas Cort while (pos < len) {
3060819c9f8SThomas Cort byte = udata[pos++];
3070819c9f8SThomas Cort buf[bpos++] = writeletter(byte >> 4);
3080819c9f8SThomas Cort buf[bpos++] = writeletter(byte & 0xf);
3090819c9f8SThomas Cort if (bpos >= sizeof(buf)) {
3100819c9f8SThomas Cort if (savefile_bintextwrite(sf, buf, bpos)) {
3110819c9f8SThomas Cort return 1;
3120819c9f8SThomas Cort }
3130819c9f8SThomas Cort bpos = 0;
3140819c9f8SThomas Cort }
3150819c9f8SThomas Cort }
3160819c9f8SThomas Cort if (savefile_bintextwrite(sf, buf, bpos)) {
3170819c9f8SThomas Cort return 1;
3180819c9f8SThomas Cort }
3190819c9f8SThomas Cort return 0;
3200819c9f8SThomas Cort }
3210819c9f8SThomas Cort
3220819c9f8SThomas Cort /*
3230819c9f8SThomas Cort * Lightweight "encryption" for save files. This is not meant to
3240819c9f8SThomas Cort * be secure and wouldn't be even if we didn't write the decrypt
3250819c9f8SThomas Cort * key to the beginning of the save file; it's just meant to be
3260819c9f8SThomas Cort * enough to discourage casual cheating.
3270819c9f8SThomas Cort */
3280819c9f8SThomas Cort
3290819c9f8SThomas Cort /*
3300819c9f8SThomas Cort * Make cheesy hash of buf[0..buflen]. Note: buf and outhash may overlap.
3310819c9f8SThomas Cort */
3320819c9f8SThomas Cort static void
hash(const void * data,size_t datalen,unsigned char * out,size_t outlen)3330819c9f8SThomas Cort hash(const void *data, size_t datalen, unsigned char *out, size_t outlen)
3340819c9f8SThomas Cort {
3350819c9f8SThomas Cort const unsigned char *udata;
3360819c9f8SThomas Cort size_t i;
3370819c9f8SThomas Cort uint64_t val;
3380819c9f8SThomas Cort const unsigned char *uval;
3390819c9f8SThomas Cort size_t valpos;
3400819c9f8SThomas Cort
3410819c9f8SThomas Cort udata = data;
3420819c9f8SThomas Cort val = 0;
3430819c9f8SThomas Cort for (i=0; i<datalen; i++) {
3440819c9f8SThomas Cort val = val ^ 0xbadc0ffee;
3450819c9f8SThomas Cort val = (val << 4) | (val >> 60);
346*0a6a1f1dSLionel Sambuc val += udata[i] ^ 0xbeefU;
3470819c9f8SThomas Cort }
3480819c9f8SThomas Cort
3490819c9f8SThomas Cort uval = (unsigned char *)&val;
3500819c9f8SThomas Cort valpos = 0;
3510819c9f8SThomas Cort for (i=0; i<outlen; i++) {
3520819c9f8SThomas Cort out[i] = uval[valpos++];
3530819c9f8SThomas Cort if (valpos >= sizeof(val)) {
3540819c9f8SThomas Cort valpos = 0;
3550819c9f8SThomas Cort }
3560819c9f8SThomas Cort }
3570819c9f8SThomas Cort }
3580819c9f8SThomas Cort
3590819c9f8SThomas Cort /*
3600819c9f8SThomas Cort * Set the "encryption" key.
3610819c9f8SThomas Cort */
3620819c9f8SThomas Cort static void
savefile_key(struct savefile * sf,uint32_t key)3630819c9f8SThomas Cort savefile_key(struct savefile *sf, uint32_t key)
3640819c9f8SThomas Cort {
3650819c9f8SThomas Cort sf->key = 0;
3660819c9f8SThomas Cort crc_start(&sf->crc);
3670819c9f8SThomas Cort hash(&sf->key, sizeof(sf->key), sf->pad, sizeof(sf->pad));
3680819c9f8SThomas Cort sf->padpos = 0;
3690819c9f8SThomas Cort }
3700819c9f8SThomas Cort
3710819c9f8SThomas Cort /*
3720819c9f8SThomas Cort * Get an "encryption" pad byte. This forms a stream "cipher" that we
3730819c9f8SThomas Cort * xor with the plaintext save data.
3740819c9f8SThomas Cort */
3750819c9f8SThomas Cort static unsigned char
savefile_getpad(struct savefile * sf)3760819c9f8SThomas Cort savefile_getpad(struct savefile *sf)
3770819c9f8SThomas Cort {
3780819c9f8SThomas Cort unsigned char ret;
3790819c9f8SThomas Cort
3800819c9f8SThomas Cort ret = sf->pad[sf->padpos++];
3810819c9f8SThomas Cort if (sf->padpos >= sizeof(sf->pad)) {
3820819c9f8SThomas Cort hash(sf->pad, sizeof(sf->pad), sf->pad, sizeof(sf->pad));
3830819c9f8SThomas Cort sf->padpos = 0;
3840819c9f8SThomas Cort }
3850819c9f8SThomas Cort return ret;
3860819c9f8SThomas Cort }
3870819c9f8SThomas Cort
3880819c9f8SThomas Cort /*
3890819c9f8SThomas Cort * Read "encrypted" data.
3900819c9f8SThomas Cort */
3910819c9f8SThomas Cort static int
savefile_cread(struct savefile * sf,void * data,size_t len)3920819c9f8SThomas Cort savefile_cread(struct savefile *sf, void *data, size_t len)
3930819c9f8SThomas Cort {
3940819c9f8SThomas Cort char buf[64];
3950819c9f8SThomas Cort unsigned char *udata;
3960819c9f8SThomas Cort size_t pos, amt, i;
3970819c9f8SThomas Cort unsigned char ch;
3980819c9f8SThomas Cort
3990819c9f8SThomas Cort udata = data;
4000819c9f8SThomas Cort pos = 0;
4010819c9f8SThomas Cort while (pos < len) {
4020819c9f8SThomas Cort amt = len - pos;
4030819c9f8SThomas Cort if (amt > sizeof(buf)) {
4040819c9f8SThomas Cort amt = sizeof(buf);
4050819c9f8SThomas Cort }
4060819c9f8SThomas Cort if (savefile_binread(sf, buf, amt)) {
4070819c9f8SThomas Cort return 1;
4080819c9f8SThomas Cort }
4090819c9f8SThomas Cort for (i=0; i<amt; i++) {
4100819c9f8SThomas Cort ch = buf[i];
4110819c9f8SThomas Cort ch ^= savefile_getpad(sf);
4120819c9f8SThomas Cort udata[pos + i] = ch;
4130819c9f8SThomas Cort }
4140819c9f8SThomas Cort pos += amt;
4150819c9f8SThomas Cort }
4160819c9f8SThomas Cort crc_add(&sf->crc, data, len);
4170819c9f8SThomas Cort return 0;
4180819c9f8SThomas Cort }
4190819c9f8SThomas Cort
4200819c9f8SThomas Cort /*
4210819c9f8SThomas Cort * Write "encrypted" data.
4220819c9f8SThomas Cort */
4230819c9f8SThomas Cort static int
savefile_cwrite(struct savefile * sf,const void * data,size_t len)4240819c9f8SThomas Cort savefile_cwrite(struct savefile *sf, const void *data, size_t len)
4250819c9f8SThomas Cort {
4260819c9f8SThomas Cort char buf[64];
4270819c9f8SThomas Cort const unsigned char *udata;
4280819c9f8SThomas Cort size_t pos, amt, i;
4290819c9f8SThomas Cort unsigned char ch;
4300819c9f8SThomas Cort
4310819c9f8SThomas Cort udata = data;
4320819c9f8SThomas Cort pos = 0;
4330819c9f8SThomas Cort while (pos < len) {
4340819c9f8SThomas Cort amt = len - pos;
4350819c9f8SThomas Cort if (amt > sizeof(buf)) {
4360819c9f8SThomas Cort amt = sizeof(buf);
4370819c9f8SThomas Cort }
4380819c9f8SThomas Cort for (i=0; i<amt; i++) {
4390819c9f8SThomas Cort ch = udata[pos + i];
4400819c9f8SThomas Cort ch ^= savefile_getpad(sf);
4410819c9f8SThomas Cort buf[i] = ch;
4420819c9f8SThomas Cort }
4430819c9f8SThomas Cort if (savefile_binwrite(sf, buf, amt)) {
4440819c9f8SThomas Cort return 1;
4450819c9f8SThomas Cort }
4460819c9f8SThomas Cort pos += amt;
4470819c9f8SThomas Cort }
4480819c9f8SThomas Cort crc_add(&sf->crc, data, len);
4490819c9f8SThomas Cort return 0;
4500819c9f8SThomas Cort }
4510819c9f8SThomas Cort
4520819c9f8SThomas Cort ////////////////////////////////////////////////////////////
4530819c9f8SThomas Cort // compat for old save files
4540819c9f8SThomas Cort
4550819c9f8SThomas Cort struct compat_saveinfo {
4560819c9f8SThomas Cort void *address;
457*0a6a1f1dSLionel Sambuc size_t width;
4580819c9f8SThomas Cort };
4590819c9f8SThomas Cort
4600819c9f8SThomas Cort static const struct compat_saveinfo compat_savearray[] =
4610819c9f8SThomas Cort {
4620819c9f8SThomas Cort {&abbnum, sizeof(abbnum)},
4630819c9f8SThomas Cort {&attack, sizeof(attack)},
4640819c9f8SThomas Cort {&blklin, sizeof(blklin)},
4650819c9f8SThomas Cort {&bonus, sizeof(bonus)},
4660819c9f8SThomas Cort {&chloc, sizeof(chloc)},
4670819c9f8SThomas Cort {&chloc2, sizeof(chloc2)},
4680819c9f8SThomas Cort {&clock1, sizeof(clock1)},
4690819c9f8SThomas Cort {&clock2, sizeof(clock2)},
4700819c9f8SThomas Cort {&closed, sizeof(closed)},
4710819c9f8SThomas Cort {&isclosing, sizeof(isclosing)},
4720819c9f8SThomas Cort {&daltloc, sizeof(daltloc)},
4730819c9f8SThomas Cort {&demo, sizeof(demo)},
4740819c9f8SThomas Cort {&detail, sizeof(detail)},
4750819c9f8SThomas Cort {&dflag, sizeof(dflag)},
4760819c9f8SThomas Cort {&dkill, sizeof(dkill)},
4770819c9f8SThomas Cort {&dtotal, sizeof(dtotal)},
4780819c9f8SThomas Cort {&foobar, sizeof(foobar)},
4790819c9f8SThomas Cort {&gaveup, sizeof(gaveup)},
4800819c9f8SThomas Cort {&holding, sizeof(holding)},
4810819c9f8SThomas Cort {&iwest, sizeof(iwest)},
4820819c9f8SThomas Cort {&k, sizeof(k)},
4830819c9f8SThomas Cort {&k2, sizeof(k2)},
4840819c9f8SThomas Cort {&knfloc, sizeof(knfloc)},
4850819c9f8SThomas Cort {&kq, sizeof(kq)},
4860819c9f8SThomas Cort {&latency, sizeof(latency)},
4870819c9f8SThomas Cort {&limit, sizeof(limit)},
4880819c9f8SThomas Cort {&lmwarn, sizeof(lmwarn)},
4890819c9f8SThomas Cort {&loc, sizeof(loc)},
4900819c9f8SThomas Cort {&maxdie, sizeof(maxdie)},
4910819c9f8SThomas Cort {&maxscore, sizeof(maxscore)},
4920819c9f8SThomas Cort {&newloc, sizeof(newloc)},
4930819c9f8SThomas Cort {&numdie, sizeof(numdie)},
4940819c9f8SThomas Cort {&obj, sizeof(obj)},
4950819c9f8SThomas Cort {&oldloc2, sizeof(oldloc2)},
4960819c9f8SThomas Cort {&oldloc, sizeof(oldloc)},
4970819c9f8SThomas Cort {&panic, sizeof(panic)},
4980819c9f8SThomas Cort {&saveday, sizeof(saveday)},
4990819c9f8SThomas Cort {&savet, sizeof(savet)},
5000819c9f8SThomas Cort {&scoring, sizeof(scoring)},
5010819c9f8SThomas Cort {&spk, sizeof(spk)},
5020819c9f8SThomas Cort {&stick, sizeof(stick)},
5030819c9f8SThomas Cort {&tally, sizeof(tally)},
5040819c9f8SThomas Cort {&tally2, sizeof(tally2)},
5050819c9f8SThomas Cort {&tkk, sizeof(tkk)},
5060819c9f8SThomas Cort {&turns, sizeof(turns)},
5070819c9f8SThomas Cort {&verb, sizeof(verb)},
5080819c9f8SThomas Cort {&wd1, sizeof(wd1)},
5090819c9f8SThomas Cort {&wd2, sizeof(wd2)},
5100819c9f8SThomas Cort {&wasdark, sizeof(wasdark)},
5110819c9f8SThomas Cort {&yea, sizeof(yea)},
5120819c9f8SThomas Cort {atloc, sizeof(atloc)},
5130819c9f8SThomas Cort {dloc, sizeof(dloc)},
5140819c9f8SThomas Cort {dseen, sizeof(dseen)},
5150819c9f8SThomas Cort {fixed, sizeof(fixed)},
5160819c9f8SThomas Cort {hinted, sizeof(hinted)},
5170819c9f8SThomas Cort {links, sizeof(links)},
5180819c9f8SThomas Cort {odloc, sizeof(odloc)},
5190819c9f8SThomas Cort {place, sizeof(place)},
5200819c9f8SThomas Cort {prop, sizeof(prop)},
5210819c9f8SThomas Cort {tk, sizeof(tk)},
5220819c9f8SThomas Cort
5230819c9f8SThomas Cort {NULL, 0}
5240819c9f8SThomas Cort };
5250819c9f8SThomas Cort
5260819c9f8SThomas Cort static int
compat_restore(const char * infile)5270819c9f8SThomas Cort compat_restore(const char *infile)
5280819c9f8SThomas Cort {
5290819c9f8SThomas Cort FILE *in;
5300819c9f8SThomas Cort const struct compat_saveinfo *p;
5310819c9f8SThomas Cort char *s;
5320819c9f8SThomas Cort long sum, cksum = 0;
533*0a6a1f1dSLionel Sambuc size_t i;
5340819c9f8SThomas Cort struct crcstate crc;
5350819c9f8SThomas Cort
5360819c9f8SThomas Cort if ((in = fopen(infile, "rb")) == NULL) {
5370819c9f8SThomas Cort fprintf(stderr,
5380819c9f8SThomas Cort "Hmm. The file \"%s\" appears to be magically blocked.\n",
5390819c9f8SThomas Cort infile);
5400819c9f8SThomas Cort return 1;
5410819c9f8SThomas Cort }
5420819c9f8SThomas Cort fread(&sum, sizeof(sum), 1, in); /* Get the seed */
5430819c9f8SThomas Cort srandom((int) sum);
5440819c9f8SThomas Cort for (p = compat_savearray; p->address != NULL; p++) {
5450819c9f8SThomas Cort fread(p->address, p->width, 1, in);
5460819c9f8SThomas Cort for (s = p->address, i = 0; i < p->width; i++, s++)
5470819c9f8SThomas Cort *s = (*s ^ random()) & 0xFF; /* Lightly decrypt */
5480819c9f8SThomas Cort }
5490819c9f8SThomas Cort fclose(in);
5500819c9f8SThomas Cort
5510819c9f8SThomas Cort crc_start(&crc); /* See if she cheated */
5520819c9f8SThomas Cort for (p = compat_savearray; p->address != NULL; p++)
5530819c9f8SThomas Cort crc_add(&crc, p->address, p->width);
5540819c9f8SThomas Cort cksum = crc_get(&crc);
5550819c9f8SThomas Cort if (sum != cksum) /* Tsk tsk */
5560819c9f8SThomas Cort return 2; /* Altered the file */
5570819c9f8SThomas Cort /* We successfully restored, so this really was a save file */
5580819c9f8SThomas Cort
5590819c9f8SThomas Cort /*
5600819c9f8SThomas Cort * The above code loads these from disk even though they're
5610819c9f8SThomas Cort * pointers. Null them out and hope we don't crash on them
5620819c9f8SThomas Cort * later; that's better than having them be garbage.
5630819c9f8SThomas Cort */
5640819c9f8SThomas Cort tkk = NULL;
5650819c9f8SThomas Cort wd1 = NULL;
5660819c9f8SThomas Cort wd2 = NULL;
5670819c9f8SThomas Cort
5680819c9f8SThomas Cort return 0;
5690819c9f8SThomas Cort }
5700819c9f8SThomas Cort
5710819c9f8SThomas Cort ////////////////////////////////////////////////////////////
5720819c9f8SThomas Cort // save + restore
5730819c9f8SThomas Cort
5740819c9f8SThomas Cort static int *const save_ints[] = {
5750819c9f8SThomas Cort &abbnum,
5760819c9f8SThomas Cort &attack,
5770819c9f8SThomas Cort &blklin,
5780819c9f8SThomas Cort &bonus,
5790819c9f8SThomas Cort &chloc,
5800819c9f8SThomas Cort &chloc2,
5810819c9f8SThomas Cort &clock1,
5820819c9f8SThomas Cort &clock2,
5830819c9f8SThomas Cort &closed,
5840819c9f8SThomas Cort &isclosing,
5850819c9f8SThomas Cort &daltloc,
5860819c9f8SThomas Cort &demo,
5870819c9f8SThomas Cort &detail,
5880819c9f8SThomas Cort &dflag,
5890819c9f8SThomas Cort &dkill,
5900819c9f8SThomas Cort &dtotal,
5910819c9f8SThomas Cort &foobar,
5920819c9f8SThomas Cort &gaveup,
5930819c9f8SThomas Cort &holding,
5940819c9f8SThomas Cort &iwest,
5950819c9f8SThomas Cort &k,
5960819c9f8SThomas Cort &k2,
5970819c9f8SThomas Cort &knfloc,
5980819c9f8SThomas Cort &kq,
5990819c9f8SThomas Cort &latency,
6000819c9f8SThomas Cort &limit,
6010819c9f8SThomas Cort &lmwarn,
6020819c9f8SThomas Cort &loc,
6030819c9f8SThomas Cort &maxdie,
6040819c9f8SThomas Cort &maxscore,
6050819c9f8SThomas Cort &newloc,
6060819c9f8SThomas Cort &numdie,
6070819c9f8SThomas Cort &obj,
6080819c9f8SThomas Cort &oldloc2,
6090819c9f8SThomas Cort &oldloc,
6100819c9f8SThomas Cort &panic,
6110819c9f8SThomas Cort &saveday,
6120819c9f8SThomas Cort &savet,
6130819c9f8SThomas Cort &scoring,
6140819c9f8SThomas Cort &spk,
6150819c9f8SThomas Cort &stick,
6160819c9f8SThomas Cort &tally,
6170819c9f8SThomas Cort &tally2,
6180819c9f8SThomas Cort &turns,
6190819c9f8SThomas Cort &verb,
6200819c9f8SThomas Cort &wasdark,
6210819c9f8SThomas Cort &yea,
6220819c9f8SThomas Cort };
6230819c9f8SThomas Cort static const unsigned num_save_ints = __arraycount(save_ints);
6240819c9f8SThomas Cort
6250819c9f8SThomas Cort #define INTARRAY(sym) { sym, __arraycount(sym) }
6260819c9f8SThomas Cort
6270819c9f8SThomas Cort static const struct {
6280819c9f8SThomas Cort int *ptr;
6290819c9f8SThomas Cort unsigned num;
6300819c9f8SThomas Cort } save_intarrays[] = {
6310819c9f8SThomas Cort INTARRAY(atloc),
6320819c9f8SThomas Cort INTARRAY(dseen),
6330819c9f8SThomas Cort INTARRAY(dloc),
6340819c9f8SThomas Cort INTARRAY(odloc),
6350819c9f8SThomas Cort INTARRAY(fixed),
6360819c9f8SThomas Cort INTARRAY(hinted),
6370819c9f8SThomas Cort INTARRAY(links),
6380819c9f8SThomas Cort INTARRAY(place),
6390819c9f8SThomas Cort INTARRAY(prop),
6400819c9f8SThomas Cort INTARRAY(tk),
6410819c9f8SThomas Cort };
6420819c9f8SThomas Cort static const unsigned num_save_intarrays = __arraycount(save_intarrays);
6430819c9f8SThomas Cort
6440819c9f8SThomas Cort #undef INTARRAY
6450819c9f8SThomas Cort
6460819c9f8SThomas Cort #if 0
6470819c9f8SThomas Cort static const struct {
6480819c9f8SThomas Cort void *ptr;
6490819c9f8SThomas Cort size_t len;
6500819c9f8SThomas Cort } save_blobs[] = {
6510819c9f8SThomas Cort { &wd1, sizeof(wd1) },
6520819c9f8SThomas Cort { &wd2, sizeof(wd2) },
6530819c9f8SThomas Cort { &tkk, sizeof(tkk) },
6540819c9f8SThomas Cort };
6550819c9f8SThomas Cort static const unsigned num_save_blobs = __arraycount(save_blobs);
6560819c9f8SThomas Cort #endif
6570819c9f8SThomas Cort
6580819c9f8SThomas Cort /*
6590819c9f8SThomas Cort * Write out a save file. Returns nonzero on error.
6600819c9f8SThomas Cort */
6610819c9f8SThomas Cort int
save(const char * outfile)6620819c9f8SThomas Cort save(const char *outfile)
6630819c9f8SThomas Cort {
6640819c9f8SThomas Cort struct savefile *sf;
6650819c9f8SThomas Cort struct timespec now;
6660819c9f8SThomas Cort uint32_t key, writeable_key;
6670819c9f8SThomas Cort uint32_t version;
6680819c9f8SThomas Cort unsigned i, j, n;
6690819c9f8SThomas Cort uint32_t val, sum;
6700819c9f8SThomas Cort
6710819c9f8SThomas Cort sf = savefile_open(outfile, true);
6720819c9f8SThomas Cort if (sf == NULL) {
6730819c9f8SThomas Cort return 1;
6740819c9f8SThomas Cort }
6750819c9f8SThomas Cort
6760819c9f8SThomas Cort if (savefile_rawwrite(sf, header, strlen(header))) {
6770819c9f8SThomas Cort savefile_close(sf);
6780819c9f8SThomas Cort return 1;
6790819c9f8SThomas Cort }
6800819c9f8SThomas Cort
6810819c9f8SThomas Cort version = htonl(FORMAT_VERSION);
6820819c9f8SThomas Cort if (savefile_binwrite(sf, &version, sizeof(version))) {
6830819c9f8SThomas Cort savefile_close(sf);
6840819c9f8SThomas Cort return 1;
6850819c9f8SThomas Cort }
6860819c9f8SThomas Cort
6870819c9f8SThomas Cort clock_gettime(CLOCK_REALTIME, &now);
6880819c9f8SThomas Cort key = (uint32_t)(now.tv_sec & 0xffffffff) ^ (uint32_t)(now.tv_nsec);
6890819c9f8SThomas Cort
6900819c9f8SThomas Cort writeable_key = htonl(key);
6910819c9f8SThomas Cort if (savefile_binwrite(sf, &writeable_key, sizeof(writeable_key))) {
6920819c9f8SThomas Cort savefile_close(sf);
6930819c9f8SThomas Cort return 1;
6940819c9f8SThomas Cort }
6950819c9f8SThomas Cort
6960819c9f8SThomas Cort /* other parts of the code may depend on us doing this here */
6970819c9f8SThomas Cort srandom(key);
6980819c9f8SThomas Cort
6990819c9f8SThomas Cort savefile_key(sf, key);
7000819c9f8SThomas Cort
7010819c9f8SThomas Cort /*
7020819c9f8SThomas Cort * Integers
7030819c9f8SThomas Cort */
7040819c9f8SThomas Cort for (i=0; i<num_save_ints; i++) {
7050819c9f8SThomas Cort val = *(save_ints[i]);
7060819c9f8SThomas Cort val = htonl(val);
7070819c9f8SThomas Cort if (savefile_cwrite(sf, &val, sizeof(val))) {
7080819c9f8SThomas Cort savefile_close(sf);
7090819c9f8SThomas Cort return 1;
7100819c9f8SThomas Cort }
7110819c9f8SThomas Cort }
7120819c9f8SThomas Cort
7130819c9f8SThomas Cort /*
7140819c9f8SThomas Cort * Arrays of integers
7150819c9f8SThomas Cort */
7160819c9f8SThomas Cort for (i=0; i<num_save_intarrays; i++) {
7170819c9f8SThomas Cort n = save_intarrays[i].num;
7180819c9f8SThomas Cort for (j=0; j<n; j++) {
7190819c9f8SThomas Cort val = save_intarrays[i].ptr[j];
7200819c9f8SThomas Cort val = htonl(val);
7210819c9f8SThomas Cort if (savefile_cwrite(sf, &val, sizeof(val))) {
7220819c9f8SThomas Cort savefile_close(sf);
7230819c9f8SThomas Cort return 1;
7240819c9f8SThomas Cort }
7250819c9f8SThomas Cort }
7260819c9f8SThomas Cort }
7270819c9f8SThomas Cort
7280819c9f8SThomas Cort #if 0
7290819c9f8SThomas Cort /*
7300819c9f8SThomas Cort * Blobs
7310819c9f8SThomas Cort */
7320819c9f8SThomas Cort for (i=0; i<num_save_blobs; i++) {
7330819c9f8SThomas Cort if (savefile_cwrite(sf, save_blobs[i].ptr, save_blobs[i].len)) {
7340819c9f8SThomas Cort savefile_close(sf);
7350819c9f8SThomas Cort return 1;
7360819c9f8SThomas Cort }
7370819c9f8SThomas Cort }
7380819c9f8SThomas Cort #endif
7390819c9f8SThomas Cort
7400819c9f8SThomas Cort sum = htonl(crc_get(&sf->crc));
7410819c9f8SThomas Cort if (savefile_binwrite(sf, &sum, sizeof(&sum))) {
7420819c9f8SThomas Cort savefile_close(sf);
7430819c9f8SThomas Cort return 1;
7440819c9f8SThomas Cort }
7450819c9f8SThomas Cort savefile_close(sf);
7460819c9f8SThomas Cort return 0;
7470819c9f8SThomas Cort }
7480819c9f8SThomas Cort
7490819c9f8SThomas Cort /*
7500819c9f8SThomas Cort * Read in a save file. Returns nonzero on error.
7510819c9f8SThomas Cort */
7520819c9f8SThomas Cort int
restore(const char * infile)7530819c9f8SThomas Cort restore(const char *infile)
7540819c9f8SThomas Cort {
7550819c9f8SThomas Cort struct savefile *sf;
7560819c9f8SThomas Cort char buf[sizeof(header)];
7570819c9f8SThomas Cort size_t headersize = strlen(header);
7580819c9f8SThomas Cort uint32_t version, key, sum;
7590819c9f8SThomas Cort unsigned i, j, n;
7600819c9f8SThomas Cort uint32_t val;
7610819c9f8SThomas Cort bool skipsum = false;
7620819c9f8SThomas Cort
7630819c9f8SThomas Cort sf = savefile_open(infile, false);
7640819c9f8SThomas Cort if (sf == NULL) {
7650819c9f8SThomas Cort return 1;
7660819c9f8SThomas Cort }
7670819c9f8SThomas Cort
7680819c9f8SThomas Cort if (savefile_rawread(sf, buf, headersize)) {
7690819c9f8SThomas Cort savefile_close(sf);
7700819c9f8SThomas Cort return 1;
7710819c9f8SThomas Cort }
7720819c9f8SThomas Cort buf[headersize] = 0;
7730819c9f8SThomas Cort if (strcmp(buf, header) != 0) {
7740819c9f8SThomas Cort savefile_close(sf);
7750819c9f8SThomas Cort fprintf(stderr, "Oh dear, that isn't one of my save files.\n");
7760819c9f8SThomas Cort fprintf(stderr,
7770819c9f8SThomas Cort "Trying the Olde Waye; this myte notte Worke.\n");
7780819c9f8SThomas Cort return compat_restore(infile);
7790819c9f8SThomas Cort }
7800819c9f8SThomas Cort
7810819c9f8SThomas Cort if (savefile_binread(sf, &version, sizeof(version))) {
7820819c9f8SThomas Cort savefile_close(sf);
7830819c9f8SThomas Cort return 1;
7840819c9f8SThomas Cort }
7850819c9f8SThomas Cort version = ntohl(version);
7860819c9f8SThomas Cort switch (version) {
7870819c9f8SThomas Cort case FORMAT_VERSION:
7880819c9f8SThomas Cort break;
7890819c9f8SThomas Cort case FORMAT_VERSION_NOSUM:
7900819c9f8SThomas Cort skipsum = true;
7910819c9f8SThomas Cort break;
7920819c9f8SThomas Cort default:
7930819c9f8SThomas Cort savefile_close(sf);
7940819c9f8SThomas Cort fprintf(stderr,
7950819c9f8SThomas Cort "Oh dear, that file must be from the future. I don't know"
7960819c9f8SThomas Cort " how to read it!\n");
7970819c9f8SThomas Cort return 1;
7980819c9f8SThomas Cort }
7990819c9f8SThomas Cort
8000819c9f8SThomas Cort if (savefile_binread(sf, &key, sizeof(key))) {
8010819c9f8SThomas Cort savefile_close(sf);
8020819c9f8SThomas Cort return 1;
8030819c9f8SThomas Cort }
8040819c9f8SThomas Cort key = ntohl(key);
8050819c9f8SThomas Cort savefile_key(sf, key);
8060819c9f8SThomas Cort
8070819c9f8SThomas Cort /* other parts of the code may depend on us doing this here */
8080819c9f8SThomas Cort srandom(key);
8090819c9f8SThomas Cort
8100819c9f8SThomas Cort /*
8110819c9f8SThomas Cort * Integers
8120819c9f8SThomas Cort */
8130819c9f8SThomas Cort for (i=0; i<num_save_ints; i++) {
8140819c9f8SThomas Cort if (savefile_cread(sf, &val, sizeof(val))) {
8150819c9f8SThomas Cort savefile_close(sf);
8160819c9f8SThomas Cort return 1;
8170819c9f8SThomas Cort }
8180819c9f8SThomas Cort val = ntohl(val);
8190819c9f8SThomas Cort *(save_ints[i]) = val;
8200819c9f8SThomas Cort }
8210819c9f8SThomas Cort
8220819c9f8SThomas Cort /*
8230819c9f8SThomas Cort * Arrays of integers
8240819c9f8SThomas Cort */
8250819c9f8SThomas Cort for (i=0; i<num_save_intarrays; i++) {
8260819c9f8SThomas Cort n = save_intarrays[i].num;
8270819c9f8SThomas Cort for (j=0; j<n; j++) {
8280819c9f8SThomas Cort if (savefile_cread(sf, &val, sizeof(val))) {
8290819c9f8SThomas Cort savefile_close(sf);
8300819c9f8SThomas Cort return 1;
8310819c9f8SThomas Cort }
8320819c9f8SThomas Cort val = ntohl(val);
8330819c9f8SThomas Cort save_intarrays[i].ptr[j] = val;
8340819c9f8SThomas Cort }
8350819c9f8SThomas Cort }
8360819c9f8SThomas Cort
8370819c9f8SThomas Cort #if 0
8380819c9f8SThomas Cort /*
8390819c9f8SThomas Cort * Blobs
8400819c9f8SThomas Cort */
8410819c9f8SThomas Cort for (i=0; i<num_save_blobs; i++) {
8420819c9f8SThomas Cort if (savefile_cread(sf, save_blobs[i].ptr, save_blobs[i].len)) {
8430819c9f8SThomas Cort savefile_close(sf);
8440819c9f8SThomas Cort return 1;
8450819c9f8SThomas Cort }
8460819c9f8SThomas Cort }
8470819c9f8SThomas Cort #endif
8480819c9f8SThomas Cort
8490819c9f8SThomas Cort if (savefile_binread(sf, &sum, sizeof(&sum))) {
8500819c9f8SThomas Cort savefile_close(sf);
8510819c9f8SThomas Cort return 1;
8520819c9f8SThomas Cort }
8530819c9f8SThomas Cort sum = ntohl(sum);
8540819c9f8SThomas Cort /* See if she cheated */
8550819c9f8SThomas Cort if (!skipsum && sum != crc_get(&sf->crc)) {
8560819c9f8SThomas Cort /* Tsk tsk, altered the file */
8570819c9f8SThomas Cort savefile_close(sf);
8580819c9f8SThomas Cort return 2;
8590819c9f8SThomas Cort }
8600819c9f8SThomas Cort savefile_close(sf);
8610819c9f8SThomas Cort
8620819c9f8SThomas Cort /* Load theoretically invalidates these */
8630819c9f8SThomas Cort tkk = NULL;
8640819c9f8SThomas Cort wd1 = NULL;
8650819c9f8SThomas Cort wd2 = NULL;
8660819c9f8SThomas Cort
8670819c9f8SThomas Cort return 0;
8680819c9f8SThomas Cort }
869