From a5072bfd810ee0f841a644475fd2e811a37a592e Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Tue, 8 Mar 2016 19:37:57 +1100 Subject: Fix complete failure to read zlib compressed data, handle EOF better in compressed files (nw) Fix bug causing crash in pathological case of zero-frame INP file [Vas Crabb] --- src/emu/ioport.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/emu/ioport.cpp') diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp index a9ac5682b04..9ae33a85a1e 100644 --- a/src/emu/ioport.cpp +++ b/src/emu/ioport.cpp @@ -3447,7 +3447,8 @@ void ioport_manager::playback_end(const char *message) machine().popmessage("Playback Ended\nReason: %s", message); // display speed stats - m_playback_accumulated_speed /= m_playback_accumulated_frames; + if (m_playback_accumulated_speed > 0) + m_playback_accumulated_speed /= m_playback_accumulated_frames; osd_printf_info("Total playback frames: %d\n", UINT32(m_playback_accumulated_frames)); osd_printf_info("Average recorded speed: %d%%\n", UINT32((m_playback_accumulated_speed * 200 + 1) >> 21)); -- cgit v1.2.3-70-g09d2 From 46bb97d9b4b85055beb7235b821b1395e22cb2b9 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Tue, 8 Mar 2016 22:41:57 +1100 Subject: Wrap up INP header I/O --- src/emu/ioport.cpp | 57 +++++++++++++------------- src/emu/ioport.h | 118 +++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 133 insertions(+), 42 deletions(-) (limited to 'src/emu/ioport.cpp') diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp index 9ae33a85a1e..2b00cabb94b 100644 --- a/src/emu/ioport.cpp +++ b/src/emu/ioport.cpp @@ -103,6 +103,9 @@ #include #include + +namespace { + // temporary: set this to 1 to enable the originally defined behavior that // a field specified via PORT_MODIFY which intersects a previously-defined // field completely wipes out the previous definition @@ -142,7 +145,6 @@ struct char_info }; - //************************************************************************** // INLINE FUNCTIONS //************************************************************************** @@ -186,10 +188,10 @@ inline INT32 apply_scale(INT32 value, INT64 scale) //************************************************************************** // XML attributes for the different types -static const char *const seqtypestrings[] = { "standard", "increment", "decrement" }; +const char *const seqtypestrings[] = { "standard", "increment", "decrement" }; // master character info table -static const char_info charinfo[] = +const char_info charinfo[] = { { 0x0008, "Backspace", nullptr }, // Backspace { 0x0009, "Tab", " " }, // Tab @@ -489,7 +491,7 @@ static const char_info charinfo[] = // COMMON SHARED STRINGS //************************************************************************** -static const struct +const struct { UINT32 id; const char *string; @@ -616,6 +618,11 @@ static const struct { INPUT_STRING_None, "None" }, }; +} // anonymous namespace + + +std::uint8_t const inp_header::MAGIC[inp_header::OFFS_BASETIME - inp_header::OFFS_MAGIC] = { 'M', 'A', 'M', 'E', 'I', 'N', 'P', 0 }; + //************************************************************************** @@ -3404,25 +3411,25 @@ time_t ioport_manager::playback_init() assert_always(filerr == FILERR_NONE, "Failed to open file for playback"); // read the header and verify that it is a modern version; if not, print an error - UINT8 header[INP_HEADER_SIZE]; - if (m_playback_file.read(header, sizeof(header)) != sizeof(header)) + inp_header header; + if (!header.read(m_playback_file)) fatalerror("Input file is corrupt or invalid (missing header)\n"); - if (memcmp(header, "MAMEINP\0", 8) != 0) + if (!header.check_magic()) fatalerror("Input file invalid or in an older, unsupported format\n"); - if (header[0x10] != INP_HEADER_MAJVERSION) + if (header.get_majversion() != inp_header::MAJVERSION) fatalerror("Input file format version mismatch\n"); // output info to console osd_printf_info("Input file: %s\n", filename); - osd_printf_info("INP version %d.%d\n", header[0x10], header[0x11]); - time_t basetime = header[0x08] | (header[0x09] << 8) | (header[0x0a] << 16) | (header[0x0b] << 24) | - ((UINT64)header[0x0c] << 32) | ((UINT64)header[0x0d] << 40) | ((UINT64)header[0x0e] << 48) | ((UINT64)header[0x0f] << 56); + osd_printf_info("INP version %u.%u\n", header.get_majversion(), header.get_minversion()); + time_t basetime = header.get_basetime(); osd_printf_info("Created %s\n", ctime(&basetime)); - osd_printf_info("Recorded using %s\n", header + 0x20); + osd_printf_info("Recorded using %s\n", header.get_appdesc().c_str()); // verify the header against the current game - if (memcmp(machine().system().name, header + 0x14, strlen(machine().system().name) + 1) != 0) - osd_printf_info("Input file is for machine '%s', not for current machine '%s'\n", header + 0x14, machine().system().name); + std::string const sysname = header.get_sysname(); + if (sysname != machine().system().name) + osd_printf_info("Input file is for machine '%s', not for current machine '%s'\n", sysname.c_str(), machine().system().name); // enable compression m_playback_file.compress(FCOMPRESS_MEDIUM); @@ -3583,23 +3590,15 @@ void ioport_manager::record_init() machine().base_datetime(systime); // fill in the header - UINT8 header[INP_HEADER_SIZE] = { 0 }; - memcpy(header, "MAMEINP\0", 8); - header[0x08] = systime.time >> 0; - header[0x09] = systime.time >> 8; - header[0x0a] = systime.time >> 16; - header[0x0b] = systime.time >> 24; - header[0x0c] = systime.time >> 32; - header[0x0d] = systime.time >> 40; - header[0x0e] = systime.time >> 48; - header[0x0f] = systime.time >> 56; - header[0x10] = INP_HEADER_MAJVERSION; - header[0x11] = INP_HEADER_MINVERSION; - strcpy((char *)header + 0x14, machine().system().name); - sprintf((char *)header + 0x20, "%s %s", emulator_info::get_appname(), build_version); + inp_header header; + header.set_magic(); + header.set_basetime(systime.time); + header.set_version(); + header.set_sysname(machine().system().name); + header.set_appdesc(util::string_format("%s %s", emulator_info::get_appname(), build_version)); // write it - m_record_file.write(header, sizeof(header)); + header.write(m_record_file); // enable compression m_record_file.compress(FCOMPRESS_MEDIUM); diff --git a/src/emu/ioport.h b/src/emu/ioport.h index 57faa51bc8d..8d16f7e4fa8 100644 --- a/src/emu/ioport.h +++ b/src/emu/ioport.h @@ -17,6 +17,8 @@ #ifndef __INPTPORT_H__ #define __INPTPORT_H__ +#include +#include #include @@ -34,11 +36,6 @@ const ioport_value IP_ACTIVE_LOW = 0xffffffff; // maximum number of players supported const int MAX_PLAYERS = 8; -// INP file parameters -const UINT32 INP_HEADER_SIZE = 64; -const UINT32 INP_HEADER_MAJVERSION = 3; -const UINT32 INP_HEADER_MINVERSION = 0; - // unicode constants const unicode_char UCHAR_PRIVATE = 0x100000; const unicode_char UCHAR_SHIFT_1 = UCHAR_PRIVATE + 0; @@ -697,15 +694,110 @@ typedef delegate ioport_charqueue_empty_delegate; // ======================> inp_header // header at the front of INP files -struct inp_header +class inp_header { - char header[8]; // +00: 8 byte header - must be "MAMEINP\0" - UINT64 basetime; // +08: base time of recording - UINT8 majversion; // +10: major INP version - UINT8 minversion; // +11: minor INP version - UINT8 reserved[2]; // +12: must be zero - char gamename[12]; // +14: game name string, NULL-terminated - char version[32]; // +20: system version string, NULL-terminated +public: + // parameters + static constexpr unsigned MAJVERSION = 3; + static constexpr unsigned MINVERSION = 0; + + bool read(emu_file &f) + { + return f.read(m_data, sizeof(m_data)) == sizeof(m_data); + } + bool write(emu_file &f) const + { + return f.write(m_data, sizeof(m_data)) == sizeof(m_data); + } + + bool check_magic() const + { + return 0 == std::memcmp(MAGIC, m_data + OFFS_MAGIC, OFFS_BASETIME - OFFS_MAGIC); + } + std::uint64_t get_basetime() const + { + return + (std::uint64_t(m_data[OFFS_BASETIME + 0]) << (0 * 8)) | + (std::uint64_t(m_data[OFFS_BASETIME + 1]) << (1 * 8)) | + (std::uint64_t(m_data[OFFS_BASETIME + 2]) << (2 * 8)) | + (std::uint64_t(m_data[OFFS_BASETIME + 3]) << (3 * 8)) | + (std::uint64_t(m_data[OFFS_BASETIME + 4]) << (4 * 8)) | + (std::uint64_t(m_data[OFFS_BASETIME + 5]) << (5 * 8)) | + (std::uint64_t(m_data[OFFS_BASETIME + 6]) << (6 * 8)) | + (std::uint64_t(m_data[OFFS_BASETIME + 7]) << (7 * 8)); + } + unsigned get_majversion() const + { + return m_data[OFFS_MAJVERSION]; + } + unsigned get_minversion() const + { + return m_data[OFFS_MINVERSION]; + } + std::string get_sysname() const + { + return get_string(); + } + std::string get_appdesc() const + { + return get_string(); + } + + void set_magic() + { + std::memcpy(m_data + OFFS_MAGIC, MAGIC, OFFS_BASETIME - OFFS_MAGIC); + } + void set_basetime(std::uint64_t time) + { + m_data[OFFS_BASETIME + 0] = std::uint8_t((time >> (0 * 8)) & 0x00ff); + m_data[OFFS_BASETIME + 1] = std::uint8_t((time >> (1 * 8)) & 0x00ff); + m_data[OFFS_BASETIME + 2] = std::uint8_t((time >> (2 * 8)) & 0x00ff); + m_data[OFFS_BASETIME + 3] = std::uint8_t((time >> (3 * 8)) & 0x00ff); + m_data[OFFS_BASETIME + 4] = std::uint8_t((time >> (4 * 8)) & 0x00ff); + m_data[OFFS_BASETIME + 5] = std::uint8_t((time >> (5 * 8)) & 0x00ff); + m_data[OFFS_BASETIME + 6] = std::uint8_t((time >> (6 * 8)) & 0x00ff); + m_data[OFFS_BASETIME + 7] = std::uint8_t((time >> (7 * 8)) & 0x00ff); + } + void set_version() + { + m_data[OFFS_MAJVERSION] = MAJVERSION; + m_data[OFFS_MINVERSION] = MINVERSION; + } + void set_sysname(std::string const &name) + { + set_string(name); + } + void set_appdesc(std::string const &desc) + { + set_string(desc); + } + +private: + template void set_string(std::string const &str) + { + std::size_t const used = (std::min)(str.size() + 1, END - BEGIN); + std::memcpy(m_data + BEGIN, str.c_str(), used); + if ((END - BEGIN) > used) + std::memset(m_data + BEGIN + used, 0, (END - BEGIN) - used); + } + template std::string get_string() const + { + char const *const begin = reinterpret_cast(m_data + BEGIN); + return std::string(begin, std::find(begin, reinterpret_cast(m_data + END), '\0')); + } + + static constexpr std::size_t OFFS_MAGIC = 0x00; // 0x08 bytes + static constexpr std::size_t OFFS_BASETIME = 0x08; // 0x08 bytes (little-endian binary integer) + static constexpr std::size_t OFFS_MAJVERSION = 0x10; // 0x01 bytes (binary integer) + static constexpr std::size_t OFFS_MINVERSION = 0x11; // 0x01 bytes (binary integer) + // 0x02 bytes reserved + static constexpr std::size_t OFFS_SYSNAME = 0x14; // 0x0c bytes (ASCII) + static constexpr std::size_t OFFS_APPDESC = 0x20; // 0x20 bytes (ASCII) + static constexpr std::size_t OFFS_END = 0x40; + + static std::uint8_t const MAGIC[OFFS_BASETIME - OFFS_MAGIC]; + + std::uint8_t m_data[OFFS_END]; }; -- cgit v1.2.3-70-g09d2