source: abuse/trunk/src/lcache.cpp @ 495

Last change on this file since 495 was 495, checked in by Sam Hocevar, 10 years ago

lisp: refactor the cache system.

File size: 4.4 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5 *
6 *  This software was released into the Public Domain. As with most public
7 *  domain software, no warranty is made or implied by Crack dot Com or
8 *  Jonathan Clark.
9 */
10
11/*
12 * This file contains serialisation methods for the cache system. It
13 * is NOT used to load and save games.
14 * XXX: this code has not been tested after the LObject refactor.
15 */
16
17#include "config.h"
18
19#include "lisp.h"
20#include "specs.h"
21#include "bus_type.h"
22
23size_t block_size(LObject *level)  // return size needed to recreate this block
24{
25    if (!level) // NULL pointers don't need to be stored
26        return 0;
27
28    switch (item_type(level))
29    {
30    case L_CONS_CELL:
31        {
32            size_t ret = sizeof(uint8_t) + sizeof(uint32_t);
33            void *b = level;
34            for (; b && item_type(b) == L_CONS_CELL; b = CDR(b))
35                ;
36            if (b)
37                ret += block_size((LObject *)b);
38            for (b = level; b && item_type(b) == L_CONS_CELL; b = CDR(b))
39                ret += block_size(CAR(b));
40            return ret;
41        }
42    case L_CHARACTER:
43        return sizeof(uint8_t) + sizeof(uint16_t);
44    case L_STRING:
45        return sizeof(uint8_t) + sizeof(uint32_t)
46                               + strlen(lstring_value(level)) + 1;
47    case L_NUMBER:
48        return sizeof(uint8_t) + sizeof(uint32_t);
49    case L_SYMBOL:
50        return sizeof(uint8_t) + sizeof(uintptr_t);
51    }
52
53    /* Do not serialise other types */
54    return 0;
55}
56
57void write_level(bFILE *fp, LObject *level)
58{
59    int type = item_type(level);
60    fp->write_uint8(type);
61
62    switch (type)
63    {
64    case L_CONS_CELL:
65        if (!level)
66            fp->write_uint32(0);
67        else
68        {
69            size_t count = 0;
70            void *b = level;
71            for (; b && item_type(b) == L_CONS_CELL; b = CDR(b))
72                count++;
73            /* If last element is not the empty list, it's a dotted list
74             * and we need to save the last object. Write a negative size
75             * to reflect that. */
76            fp->write_uint32(b ? -(int32_t)count : count);
77            if (b)
78                write_level(fp, (LObject *)b);
79
80            for (b = level; b && item_type(b) == L_CONS_CELL; b = CDR(b))
81                write_level(fp, CAR(b));
82        }
83        break;
84    case L_CHARACTER:
85        fp->write_uint16(lcharacter_value(level));
86        break;
87    case L_STRING:
88        {
89            size_t count = strlen(lstring_value(level)) + 1;
90            fp->write_uint32(count);
91            fp->write(lstring_value(level), count);
92        }
93        break;
94    case L_NUMBER:
95        fp->write_uint32(lnumber_value(level));
96        break;
97    case L_SYMBOL:
98        {
99            uintptr_t p = (uintptr_t)level;
100            for (size_t i = 0; i < sizeof(uintptr_t); i++)
101            {
102                fp->write_uint8((uint8_t)p);
103                p >>= 8;
104            }
105        }
106    }
107}
108
109LObject *load_block(bFILE *fp)
110{
111    int type = fp->read_uint8();
112
113    switch (type)
114    {
115    case L_CONS_CELL:
116        {
117            int32_t t = (int32_t)fp->read_uint32();
118
119            if (!t)
120                return NULL;
121
122            LList *last = NULL, *first = NULL;
123            for (size_t count = abs(t); count--; )
124            {
125                LList *c = LList::Create();
126                if (first)
127                    last->cdr = c;
128                else
129                    first = c;
130                last = c;
131            }
132            last->cdr = (t < 0) ? (LObject *)load_block(fp) : NULL;
133
134            last = first;
135            for (size_t count = abs(t); count--; last = (LList *)last->cdr)
136                last->car = load_block(fp);
137            return first;
138        }
139    case L_CHARACTER:
140        return LChar::Create(fp->read_uint16());
141    case L_STRING:
142        {
143            size_t count = fp->read_uint32();
144            LString *s = LString::Create(count);
145            fp->read(s->GetString(), count);
146            return s;
147        }
148    case L_NUMBER:
149        return LNumber::Create(fp->read_uint32());
150    case L_SYMBOL:
151        {
152            uintptr_t ret = 0, mul = 1;
153            for (size_t i = 0; i < sizeof(uintptr_t); i++)
154            {
155                ret |= mul * fp->read_uint8();
156                mul *= 8;
157            }
158            return (LObject *)ret;
159        }
160    }
161
162    return NULL;
163}
164
Note: See TracBrowser for help on using the repository browser.