/* perform_restoreundo(): Pull a state pointer from the undo chain. This returns 0 on success, 1 on failure. Note that if it succeeds, the frameptr, localsbase, and valstackbase registers are invalid; they must be rebuilt from the stack. */ glui32 perform_restoreundo() { dest_t dest; glui32 res, val; glui32 heapsumlen = 0; glui32 *heapsumarr = NULL; if (undo_chain_size == 0 || undo_chain_num == 0) return 1; dest.ismem = TRUE; dest.size = 0; dest.pos = 0; dest.ptr = undo_chain[0]; dest.str = NULL; res = 0; if (res == 0) { res = read_long(&dest, &val); } if (res == 0) { res = read_memstate(&dest, val); } if (res == 0) { res = read_long(&dest, &val); } if (res == 0) { res = read_heapstate(&dest, val, FALSE, &heapsumlen, &heapsumarr); } if (res == 0) { res = read_long(&dest, &val); } if (res == 0) { res = read_stackstate(&dest, val, FALSE); } /* ### really, many of the failure modes of those calls ought to cause fatal errors. The stack or main memory may be damaged now. */ if (res == 0) { if (heapsumarr) res = heap_apply_summary(heapsumlen, heapsumarr); } if (res == 0) { /* It worked. */ if (undo_chain_size > 1) memmove(undo_chain, undo_chain+1, (undo_chain_size-1) * sizeof(unsigned char *)); undo_chain_num -= 1; glulx_free(dest.ptr); dest.ptr = NULL; } else { /* It didn't work. */ dest.ptr = NULL; } return res; }
/* perform_restore(): Pull a state pointer from a stream. This returns 0 on success, 1 on failure. Note that if it succeeds, the frameptr, localsbase, and valstackbase registers are invalid; they must be rebuilt from the stack. If fromshell is true, the restore is being invoked by the library shell (an autorestore of some kind). This currently happens only in iosglk. */ glui32 perform_restore(strid_t str, int fromshell) { dest_t dest; int ix; glui32 lx, res, val; glui32 filestart, filelen; glui32 heapsumlen = 0; glui32 *heapsumarr = NULL; /* If profiling is enabled and active then fail. */ #if VM_PROFILING if (profile_profiling_active()) return 1; #endif /* VM_PROFILING */ stream_get_iosys(&val, &lx); if (val != 2 && !fromshell) { /* Not using the Glk I/O system, so bail. This function only knows how to read from a Glk stream. (But in the autorestore case, iosys hasn't been set yet, so ignore this test.) */ fatal_error("Streams are only available in Glk I/O system."); } if (str == 0) return 1; dest.ismem = FALSE; dest.size = 0; dest.pos = 0; dest.ptr = NULL; dest.str = str; res = 0; /* ### the format errors checked below should send error messages to the current stream. */ if (res == 0) { res = read_long(&dest, &val); } if (res == 0 && val != IFFID('F', 'O', 'R', 'M')) { /* ### bad header */ return 1; } if (res == 0) { res = read_long(&dest, &filelen); } filestart = dest.pos; if (res == 0) { res = read_long(&dest, &val); } if (res == 0 && val != IFFID('I', 'F', 'Z', 'S')) { /* ### ? */ /* ### bad header */ return 1; } while (res == 0 && dest.pos < filestart+filelen) { /* Read a chunk and deal with it. */ glui32 chunktype=0, chunkstart=0, chunklen=0; unsigned char dummy; if (res == 0) { res = read_long(&dest, &chunktype); } if (res == 0) { res = read_long(&dest, &chunklen); } chunkstart = dest.pos; if (chunktype == IFFID('I', 'F', 'h', 'd')) { for (ix=0; res==0 && ix<128; ix++) { res = read_byte(&dest, &dummy); if (res == 0 && Mem1(ix) != dummy) { /* ### non-matching header */ return 1; } } } else if (chunktype == IFFID('C', 'M', 'e', 'm')) { res = read_memstate(&dest, chunklen); } else if (chunktype == IFFID('M', 'A', 'l', 'l')) { res = read_heapstate(&dest, chunklen, TRUE, &heapsumlen, &heapsumarr); } else if (chunktype == IFFID('S', 't', 'k', 's')) { res = read_stackstate(&dest, chunklen, TRUE); } else { /* Unknown chunk type. Skip it. */ for (lx=0; res==0 && lx<chunklen; lx++) { res = read_byte(&dest, &dummy); } } if (chunkstart+chunklen != dest.pos) { /* ### funny chunk length */ return 1; } if ((chunklen & 1) != 0) { if (res == 0) { res = read_byte(&dest, &dummy); } } } if (res == 0) { if (heapsumarr) { /* The summary might have come from any interpreter, so it could be out of order. We'll sort it. */ glulx_sort(heapsumarr+2, (heapsumlen-2)/2, 2*sizeof(glui32), &sort_heap_summary); res = heap_apply_summary(heapsumlen, heapsumarr); } } if (res) return 1; return 0; }