save_error save_manager::write_file(emu_file &file) { // if we have illegal registrations, return an error if (m_illegal_regs > 0) return STATERR_ILLEGAL_REGISTRATIONS; // generate the header UINT8 header[HEADER_SIZE]; memcpy(&header[0], emulator_info::get_state_magic_num(), 8); header[8] = SAVE_VERSION; header[9] = NATIVE_ENDIAN_VALUE_LE_BE(0, SS_MSB_FIRST); strncpy((char *)&header[0x0a], machine().system().name, 0x1c - 0x0a); UINT32 sig = signature(); *(UINT32 *)&header[0x1c] = LITTLE_ENDIANIZE_INT32(sig); // write the header and turn on compression for the rest of the file file.compress(FCOMPRESS_NONE); file.seek(0, SEEK_SET); if (file.write(header, sizeof(header)) != sizeof(header)) return STATERR_WRITE_ERROR; file.compress(FCOMPRESS_MEDIUM); // call the pre-save functions for (state_callback *func = m_presave_list.first(); func != NULL; func = func->next()) func->m_func(); // then write all the data for (state_entry *entry = m_entry_list.first(); entry != NULL; entry = entry->next()) { UINT32 totalsize = entry->m_typesize * entry->m_typecount; if (file.write(entry->m_data, totalsize) != totalsize) return STATERR_WRITE_ERROR; } return STATERR_NONE; }
save_error save_manager::read_file(emu_file &file) { // if we have illegal registrations, return an error if (m_illegal_regs > 0) return STATERR_ILLEGAL_REGISTRATIONS; // read the header and turn on compression for the rest of the file file.compress(FCOMPRESS_NONE); file.seek(0, SEEK_SET); UINT8 header[HEADER_SIZE]; if (file.read(header, sizeof(header)) != sizeof(header)) return STATERR_READ_ERROR; file.compress(FCOMPRESS_MEDIUM); // verify the header and report an error if it doesn't match // JJG: Allow invalid headers //UINT32 sig = signature(); //if (validate_header(header, machine().system().name, sig, popmessage, "Error: ") != STATERR_NONE) //return STATERR_INVALID_HEADER; // determine whether or not to flip the data when done bool flip = NATIVE_ENDIAN_VALUE_LE_BE((header[9] & SS_MSB_FIRST) != 0, (header[9] & SS_MSB_FIRST) == 0); // read all the data, flipping if necessary for (state_entry *entry = m_entry_list.first(); entry != NULL; entry = entry->next()) { UINT32 totalsize = entry->m_typesize * entry->m_typecount; if (file.read(entry->m_data, totalsize) != totalsize) return STATERR_READ_ERROR; // handle flipping if (flip) entry->flip_data(); } // call the post-load functions for (state_callback *func = m_postload_list.first(); func != NULL; func = func->next()) func->m_func(); return STATERR_NONE; }
save_error save_manager::check_file(running_machine &machine, emu_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...)) { // if we want to validate the signature, compute it UINT32 sig = 0; sig = machine.save().signature(); // seek to the beginning and read the header file.compress(FCOMPRESS_NONE); file.seek(0, SEEK_SET); UINT8 header[HEADER_SIZE]; if (file.read(header, sizeof(header)) != sizeof(header)) { if (errormsg != NULL) (*errormsg)("Could not read %s save file header",emulator_info::get_appname()); return STATERR_READ_ERROR; } // let the generic header check work out the rest return validate_header(header, gamename, sig, errormsg, ""); }