1 // $Id: savefile.c,v 1.6 2003/10/20 16:05:06 iain Exp $
5 static void writeWord (git_sint32 word)
8 write32 (buffer, word);
9 glk_put_buffer (buffer, 4);
12 static git_uint32 readWord (strid_t file)
15 glk_get_buffer_stream (file, buffer, 4);
16 return (git_uint32) read32 (buffer);
19 static int sort_heap_summary(const void *p1, const void *p2)
21 const glui32 *v1 = (const glui32 *)p1;
22 const glui32 *v2 = (const glui32 *)p2;
31 git_sint32 restoreFromFile (git_sint32 * base, git_sint32 id,
32 git_uint32 protectPos, git_uint32 protectSize)
34 git_uint32 protectEnd = protectPos + protectSize;
37 glui32 fileSize, fileStart;
44 // Find out what stream they want to use, and make sure it's valid.
45 file = git_find_stream_by_id (id);
50 if (readWord (file) != read32("FORM"))
51 return 1; // Not an IFF file.
53 fileSize = readWord (file);
54 fileStart = glk_stream_get_position (file);
56 if (readWord (file) != read32("IFZS"))
57 return 1; // Not a Quetzal file.
59 // Discard the current heap.
62 // Read all the chunks.
64 while (glk_stream_get_position(file) < fileStart + fileSize)
66 git_uint32 chunkType, chunkSize, chunkStart;
67 chunkType = readWord (file);
68 chunkSize = readWord (file);
69 chunkStart = glk_stream_get_position (file);
71 if (chunkType == read32("IFhd"))
81 for (i = 0 ; i < 128 ; ++i)
83 glui32 c = glk_get_char_stream (file);
88 else if (chunkType == read32("Stks"))
99 for ( ; chunkSize > 0 ; chunkSize -= 4)
100 *gStackPointer++ = readWord(file);
102 else if (chunkType == read32("CMem"))
104 git_uint32 bytesRead = 0;
110 if (resizeMemory (readWord(file), 1))
111 fatalError ("Can't resize memory map");
115 while (i < gExtStart && bytesRead < chunkSize)
118 char c = (char) glk_get_char_stream(file);
123 mult = (unsigned char) glk_get_char_stream(file);
127 for (++mult ; mult > 0 ; --mult, ++i)
128 if (i >= protectEnd || i < protectPos)
129 gRam [i] = gRom [i] ^ c;
132 while (i < gEndMem && bytesRead < chunkSize)
135 char c = (char) glk_get_char_stream(file);
140 mult = (unsigned char) glk_get_char_stream(file);
144 for (++mult ; mult > 0 ; --mult, ++i)
145 if (i >= protectEnd || i < protectPos)
149 while (i < gExtStart)
150 if (i >= protectEnd || i < protectPos)
151 gRam [i] = gRom [i], ++i;
154 if (i >= protectEnd || i < protectPos)
157 if (bytesRead != chunkSize)
158 return 1; // Too much data!
161 glk_get_char_stream (file);
163 else if (chunkType == read32("MAll"))
178 heap = malloc (chunkSize);
179 heapSize = chunkSize / 4;
180 for (i = 0 ; i < heapSize ; ++i)
181 heap[i] = readWord(file);
183 /* The summary might have come from any interpreter, so it could
184 be out of order. We'll sort it. */
185 qsort(heap+2, (heapSize-2)/2, 8, &sort_heap_summary);
187 if (heap_apply_summary (heapSize, heap))
188 fatalError ("Couldn't apply heap summary");
194 // Unknown chunk type -- just skip it.
195 glk_stream_set_position (file, (chunkSize + 1) & ~1, seekmode_Current);
199 // Make sure we have all the chunks we need.
202 fatalError ("No ident chunk in save file");
205 fatalError ("No stack chunk in save file");
208 fatalError ("No memory chunk in save file");
210 // If we reach this point, we restored successfully.
215 git_sint32 saveToFile (git_sint32 * base, git_sint32 * sp, git_sint32 id)
217 git_uint32 n, zeroCount;
218 glui32 fileSize, fileSizePos;
219 glui32 memSize, memSizePos;
223 strid_t file, oldFile;
225 // Find out what stream they want to use, and make sure it's valid.
226 file = git_find_stream_by_id (id);
230 // Get the state of the heap.
231 if (heap_get_summary (&heapSize, &heap))
232 fatalError ("Couldn't get heap summary");
234 // Make the given stream the default.
235 oldFile = glk_stream_get_current ();
236 glk_stream_set_current (file);
238 // Write Quetzal header.
239 glk_put_string ("FORM");
241 fileSizePos = glk_stream_get_position (file);
244 glk_put_string ("IFZS");
247 glk_put_string ("IFhd");
249 glk_put_buffer ((char *) gRom, 128);
252 glk_put_string ("Stks");
253 writeWord ((sp - base) * 4);
254 for (n = 0 ; n < (git_uint32) (sp - base) ; ++n)
255 writeWord (base [n]);
260 glk_put_string ("MAll");
261 writeWord (heapSize * 4);
262 for (n = 0 ; n < heapSize ; ++n)
263 writeWord (heap [n]);
268 glk_put_string ("CMem");
269 memSizePos = glk_stream_get_position (file);
273 for (zeroCount = 0, n = gRamStart ; n < gEndMem ; ++n)
275 unsigned char romC = (n < gExtStart) ? gRom[n] : 0;
276 unsigned char c = ((git_uint32) romC) ^ ((git_uint32) gRam[n]);
281 for ( ; zeroCount > 256 ; zeroCount -= 256)
290 glk_put_char ((char) (zeroCount - 1));
297 // Note: we don't bother writing out any remaining zeroes,
298 // because the memory is padded out with zeroes on restore.
300 memSize = glk_stream_get_position (file) - memSizePos - 4;
304 // Back up and fill in the lengths.
305 fileSize = glk_stream_get_position (file) - fileSizePos - 4;
307 glk_stream_set_position (file, fileSizePos, seekmode_Start);
308 writeWord (fileSize);
310 glk_stream_set_position (file, memSizePos, seekmode_Start);
313 // Restore the previous default stream.
314 glk_stream_set_current (oldFile);