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