static glui32 write_heapstate(dest_t *dest, int portable) { glui32 res; glui32 sumlen; glui32 *sumarray; res = heap_get_summary(&sumlen, &sumarray); if (res) return res; if (!sumarray) return 0; /* no heap */ res = write_heapstate_sub(sumlen, sumarray, dest, portable); glulx_free(sumarray); return res; }
git_sint32 saveToFile (git_sint32 * base, git_sint32 * sp, git_sint32 id) { git_uint32 n, zeroCount; glui32 fileSize, fileSizePos; glui32 memSize, memSizePos; glui32 heapSize; glui32* heap; strid_t file, oldFile; // Find out what stream they want to use, and make sure it's valid. file = git_find_stream_by_id (id); if (file == 0) return 1; // Get the state of the heap. if (heap_get_summary (&heapSize, &heap)) fatalError ("Couldn't get heap summary"); // Make the given stream the default. oldFile = glk_stream_get_current (); glk_stream_set_current (file); // Write Quetzal header. glk_put_string ("FORM"); fileSizePos = glk_stream_get_position (file); writeWord (0); glk_put_string ("IFZS"); // Header chunk. glk_put_string ("IFhd"); writeWord (128); glk_put_buffer ((char *) gRom, 128); // Stack chunk. glk_put_string ("Stks"); writeWord ((sp - base) * 4); for (n = 0 ; n < (git_uint32) (sp - base) ; ++n) writeWord (base [n]); // Heap chunk. if (heap != 0) { glk_put_string ("MAll"); writeWord (heapSize * 4); for (n = 0 ; n < heapSize ; ++n) writeWord (heap [n]); free(heap); } // Memory chunk. glk_put_string ("CMem"); memSizePos = glk_stream_get_position (file); writeWord (0); writeWord (gEndMem); for (zeroCount = 0, n = gRamStart ; n < gEndMem ; ++n) { unsigned char romC = (n < gExtStart) ? gRom[n] : 0; unsigned char c = ((git_uint32) romC) ^ ((git_uint32) gRam[n]); if (c == 0) ++zeroCount; else { for ( ; zeroCount > 256 ; zeroCount -= 256) { glk_put_char (0); glk_put_char (0xff); } if (zeroCount > 0) { glk_put_char (0); glk_put_char ((char) (zeroCount - 1)); zeroCount = 0; } glk_put_char (c); } } // Note: we don't bother writing out any remaining zeroes, // because the memory is padded out with zeroes on restore. memSize = glk_stream_get_position (file) - memSizePos - 4; if (memSize & 1) glk_put_char (0); // Back up and fill in the lengths. fileSize = glk_stream_get_position (file) - fileSizePos - 4; glk_stream_set_position (file, fileSizePos, seekmode_Start); writeWord (fileSize); glk_stream_set_position (file, memSizePos, seekmode_Start); writeWord (memSize); // Restore the previous default stream. glk_stream_set_current (oldFile); // And we're done. return 0; }
int saveUndo (git_sint32 * base, git_sint32 * sp) { git_uint32 undoSize = sizeof(UndoRecord); git_uint32 mapSize = sizeof(MemoryPage*) * (gEndMem - gRamStart) / 256; git_uint32 stackSize = sizeof(git_sint32) * (sp - base); git_uint32 totalSize = undoSize + mapSize + stackSize; git_uint32 addr = gRamStart; // Address in glulx memory. git_uint32 slot = 0; // Slot in our memory map. UndoRecord * undo = malloc (undoSize); if (undo == NULL) fatalError ("Couldn't allocate undo record"); undo->endMem = gEndMem; undo->memoryMap = malloc (mapSize); undo->stackSize = stackSize; undo->stack = malloc (stackSize); undo->prev = NULL; undo->next = NULL; if (undo->memoryMap == NULL || undo->stack == NULL) fatalError ("Couldn't allocate memory for undo"); // Save the stack. memcpy (undo->stack, base, undo->stackSize); // Are we diffing against the previous undo record, // or against the initial gamefile state? if (gUndo == NULL) { // We're diffing against the gamefile. for ( ; addr < gExtStart ; addr += 256, ++slot) { if (memcmp (gInitMem + addr, gMem + addr, 256) != 0) { // We need to save this page. git_uint8 * page = malloc(256); if (page == NULL) fatalError ("Couldn't allocate memory for undo"); memcpy (page, gMem + addr, 256); undo->memoryMap[slot] = page; totalSize += 256; } else { // We don't need to save this page. // Just make it point into ROM. undo->memoryMap[slot] = gInitMem + addr; } } // If the memory map has been extended, save the exended area for (addr = gExtStart ; addr < gEndMem ; addr += 256, ++slot) { git_uint8 * page = malloc(256); if (page == NULL) fatalError ("Couldn't allocate memory for undo"); memcpy (page, gMem + addr, 256); undo->memoryMap[slot] = page; totalSize += 256; } } else { // We're diffing against the most recent undo record. git_uint32 endMem = (gUndo->endMem < gEndMem) ? gUndo->endMem : gEndMem; for ( ; addr < endMem ; addr += 256, ++slot) { if (memcmp (gUndo->memoryMap [slot], gMem + addr, 256) != 0) { // We need to save this page. git_uint8 * page = malloc(256); memcpy (page, gMem + addr, 256); undo->memoryMap[slot] = page; totalSize += 256; } else { // We don't need to save this page. Just copy // the pointer from the previous undo record. undo->memoryMap[slot] = gUndo->memoryMap[slot]; } } // If the memory map has been extended, save the exended area for (addr = endMem ; addr < gEndMem ; addr += 256, ++slot) { git_uint8 * page = malloc(256); if (page == NULL) fatalError ("Couldn't allocate memory for undo"); memcpy (page, gMem + addr, 256); undo->memoryMap[slot] = page; totalSize += 256; } } // Save the heap. if (heap_get_summary (&(undo->heapSize), &(undo->heap))) fatalError ("Couldn't get heap summary"); totalSize += undo->heapSize * 4; // Link this record into the undo list. undo->prev = gUndo; if (gUndo) gUndo->next = undo; gUndo = undo; gUndoSize += totalSize; // Delete old records until we have enough free space. reserveSpace (0); // And we're done. return 0; }