source: abuse/trunk/src/lcache.cpp

Last change on this file was 636, checked in by Sam Hocevar, 9 years ago

lisp: merge the Lisp and LispGC classes and improve coding style.

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, by
8 *  Jonathan Clark, or by Sam Hocevar.
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#if defined HAVE_CONFIG_H
18#   include "config.h"
19#endif
20
21#include "lisp.h"
22#include "specs.h"
23
24size_t block_size(LObject *level)  // return size needed to recreate this block
25{
26    if (!level) // NULL pointers don't need to be stored
27        return 0;
28
29    switch (item_type(level))
30    {
31    case L_CONS_CELL:
32        {
33            size_t ret = sizeof(uint8_t) + sizeof(uint32_t);
34            void *b = level;
35            for (; b && item_type(b) == L_CONS_CELL; b = CDR(b))
36                ;
37            if (b)
38                ret += block_size((LObject *)b);
39            for (b = level; b && item_type(b) == L_CONS_CELL; b = CDR(b))
40                ret += block_size(CAR(b));
41            return ret;
42        }
43    case L_CHARACTER:
44        return sizeof(uint8_t) + sizeof(uint16_t);
45    case L_STRING:
46        return sizeof(uint8_t) + sizeof(uint32_t)
47                               + strlen(lstring_value(level)) + 1;
48    case L_NUMBER:
49        return sizeof(uint8_t) + sizeof(uint32_t);
50    case L_SYMBOL:
51        return sizeof(uint8_t) + sizeof(uintptr_t);
52    }
53
54    /* Do not serialise other types */
55    return 0;
56}
57
58void write_level(bFILE *fp, LObject *level)
59{
60    int type = item_type(level);
61    fp->write_uint8(type);
62
63    switch (type)
64    {
65    case L_CONS_CELL:
66        if (!level)
67            fp->write_uint32(0);
68        else
69        {
70            size_t count = 0;
71            void *b = level;
72            for (; b && item_type(b) == L_CONS_CELL; b = CDR(b))
73                count++;
74            /* If last element is not the empty list, it's a dotted list
75             * and we need to save the last object. Write a negative size
76             * to reflect that. */
77            fp->write_uint32(b ? -(int32_t)count : count);
78            if (b)
79                write_level(fp, (LObject *)b);
80
81            for (b = level; b && item_type(b) == L_CONS_CELL; b = CDR(b))
82                write_level(fp, CAR(b));
83        }
84        break;
85    case L_CHARACTER:
86        fp->write_uint16(((LChar *)level)->GetValue());
87        break;
88    case L_STRING:
89        {
90            size_t count = strlen(lstring_value(level)) + 1;
91            fp->write_uint32(count);
92            fp->write(lstring_value(level), count);
93        }
94        break;
95    case L_NUMBER:
96        fp->write_uint32(lnumber_value(level));
97        break;
98    case L_SYMBOL:
99        {
100            uintptr_t p = (uintptr_t)level;
101            for (size_t i = 0; i < sizeof(uintptr_t); i++)
102            {
103                fp->write_uint8((uint8_t)p);
104                p >>= 8;
105            }
106        }
107    }
108}
109
110LObject *load_block(bFILE *fp)
111{
112    int type = fp->read_uint8();
113
114    switch (type)
115    {
116    case L_CONS_CELL:
117        {
118            int32_t t = (int32_t)fp->read_uint32();
119
120            if (!t)
121                return NULL;
122
123            LList *last = NULL, *first = NULL;
124            for (size_t count = abs(t); count--; )
125            {
126                LList *c = LList::Create();
127                if (first)
128                    last->m_cdr = c;
129                else
130                    first = c;
131                last = c;
132            }
133            last->m_cdr = (t < 0) ? (LObject *)load_block(fp) : NULL;
134
135            last = first;
136            for (size_t count = abs(t); count--; last = (LList *)last->m_cdr)
137                last->m_car = load_block(fp);
138            return first;
139        }
140    case L_CHARACTER:
141        return LChar::Create(fp->read_uint16());
142    case L_STRING:
143        {
144            size_t count = fp->read_uint32();
145            LString *s = LString::Create(count);
146            fp->read(s->GetString(), count);
147            return s;
148        }
149    case L_NUMBER:
150        return LNumber::Create(fp->read_uint32());
151    case L_SYMBOL:
152        {
153            uintptr_t ret = 0, mul = 1;
154            for (size_t i = 0; i < sizeof(uintptr_t); i++)
155            {
156                ret |= mul * fp->read_uint8();
157                mul *= 8;
158            }
159            return (LObject *)ret;
160        }
161    }
162
163    return NULL;
164}
165
Note: See TracBrowser for help on using the repository browser.