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