summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2016-03-08 22:41:57 +1100
committer Vas Crabb <vas@vastheman.com>2016-03-08 22:42:24 +1100
commit46bb97d9b4b85055beb7235b821b1395e22cb2b9 (patch)
tree2ee8377ed17a00fccc72cd5d1676ee972cab3de7
parent962125c249c7e3c9c55f7f40391a3ed33b4f5753 (diff)
Wrap up INP header I/O
-rw-r--r--src/emu/ioport.cpp57
-rw-r--r--src/emu/ioport.h118
2 files changed, 133 insertions, 42 deletions
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 <ctype.h>
#include <time.h>
+
+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 <cstdint>
+#include <cstring>
#include <time.h>
@@ -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<bool ()> 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<OFFS_SYSNAME, OFFS_APPDESC>();
+ }
+ std::string get_appdesc() const
+ {
+ return get_string<OFFS_APPDESC, OFFS_END>();
+ }
+
+ 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<OFFS_SYSNAME, OFFS_APPDESC>(name);
+ }
+ void set_appdesc(std::string const &desc)
+ {
+ set_string<OFFS_APPDESC, OFFS_END>(desc);
+ }
+
+private:
+ template <std::size_t BEGIN, std::size_t END> void set_string(std::string const &str)
+ {
+ std::size_t const used = (std::min<std::size_t>)(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::size_t BEGIN, std::size_t END> std::string get_string() const
+ {
+ char const *const begin = reinterpret_cast<char const *>(m_data + BEGIN);
+ return std::string(begin, std::find(begin, reinterpret_cast<char const *>(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];
};