BOOL check_game_for_save(strid_t gamefile, zword release, const char serial[6], zword checksum) { int i; unsigned char header[64]; glk_stream_set_position(gamefile, 0, seekmode_Start); if(glk_get_buffer_stream(gamefile, (char *) header, 64) != 64) return FALSE; if(header[HD_ZVERSION] == 0 || header[HD_ZVERSION] > 8) return FALSE; if(MSBdecodeZ(header + HD_RELNUM) != release) return FALSE; if(MSBdecodeZ(header + HD_CHECKSUM) != checksum) return FALSE; for(i = 0; i < 6; i++) { if(header[HD_SERNUM + i] != serial[i]) return FALSE; } return TRUE; }
BOOL quetzal_stack_restore(strid_t stream, glui32 qsize) { glui32 i = 0; int num_frames = 0; kill_stack(); init_stack(1024, 128); while(i < qsize) { unsigned n; unsigned num_locals; zword locals[16]; int num_args; int var; glui32 qframe[5]; i += fillstruct(stream, qstackframe, qframe, NULL); if(qframe[qreturnPC] > total_size) { n_show_error(E_SAVE, "function return PC past end of memory", qframe[qreturnPC]); return FALSE; } if((qframe[qflags] & b11100000) != 0) { n_show_error(E_SAVE, "expected top bits of flag to be zero", qframe[qflags]); return FALSE; } var = qframe[qvar]; if(qframe[qflags] & b00010000) /* from a call_n */ var = -1; num_locals = qframe[qflags] & b00001111; if(num_locals > 15) { n_show_error(E_SAVE, "too many locals", num_locals); return FALSE; } num_args = 0; switch(qframe[qargs]) { default: n_show_error(E_SAVE, "invalid argument count", qframe[qargs]); return FALSE; case b01111111: num_args++; case b00111111: num_args++; case b00011111: num_args++; case b00001111: num_args++; case b00000111: num_args++; case b00000011: num_args++; case b00000001: num_args++; case b00000000: ; } for(n = 0; n < num_locals; n++) { unsigned char v[ZWORD_SIZE]; glk_get_buffer_stream(stream, (char *) v, ZWORD_SIZE); locals[n] = MSBdecodeZ(v); i+=ZWORD_SIZE; } if(zversion != 6 && num_frames == 0) ; /* dummy stack frame; don't really use it */ else add_stack_frame(qframe[qreturnPC], num_locals, locals, num_args, var); for(n = 0; n < qframe[qeval]; n++) { unsigned char v[ZWORD_SIZE]; glk_get_buffer_stream(stream, (char *) v, ZWORD_SIZE); stack_push(MSBdecodeZ(v)); i += ZWORD_SIZE; } num_frames++; } if(!verify_stack()) { n_show_error(E_SAVE, "restored stack fails verification", 0); return FALSE; } return TRUE; }