[BACK]Return to save.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / games / adventure

Annotation of src/games/adventure/save.c, Revision 1.15

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

CVSweb <webmaster@jp.NetBSD.org>