summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/corefile.cpp
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2022-04-19 14:22:04 -0400
committer AJR <ajrhacker@users.noreply.github.com>2022-04-19 14:28:45 -0400
commitb45569d964aa8fae416d2049ba70699f5b2d7837 (patch)
tree522b58375072a7b7f3acc36081de7daa9302417d /src/lib/util/corefile.cpp
parent7780f53ffd266ad7a88058ecda056e5eeea3bc9f (diff)
File handling cleanup
- Remove fgetc, fgets and ptr methods from device_image_interface. - Remove the core_file::buffer method to read an entire file into memory and rewrite emu_file::hashes to not depend on it. - Make core_in_memory_file a final class; now that buffering is gone, core_osd_file no longer subclasses it but a new superclass that retains some common methods. - Rename the offset and length methods used internally in core_file implementations to index and size due to frequent clashes with parameter names. - Convert comments in util/corefile.cpp to C++ style. - Add a new overload of the hash_collection::compute method which hashes data from a random_read stream, reading it into memory one chunk at a time. As a result, the hash_collection::begin and hash_collection::end methods have been removed as obsolete (similar methods are now used internally only). - Enhance error messages for the frontend media identifier when it encounters file errors.
Diffstat (limited to 'src/lib/util/corefile.cpp')
-rw-r--r--src/lib/util/corefile.cpp398
1 files changed, 175 insertions, 223 deletions
diff --git a/src/lib/util/corefile.cpp b/src/lib/util/corefile.cpp
index b53f68a713d..fd26ddaf40e 100644
--- a/src/lib/util/corefile.cpp
+++ b/src/lib/util/corefile.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
- corefile.c
+ corefile.cpp
File access functions.
@@ -64,7 +64,6 @@ public:
virtual int getc() override { return m_file.getc(); }
virtual int ungetc(int c) override { return m_file.ungetc(c); }
virtual char *gets(char *s, int n) override { return m_file.gets(s, n); }
- virtual void const *buffer() override { return m_file.buffer(); }
virtual int puts(std::string_view s) override { return m_file.puts(s); }
virtual int vprintf(util::format_argument_pack<std::ostream> const &args) override { return m_file.vprintf(args); }
@@ -121,15 +120,45 @@ private:
};
-class core_in_memory_file : public core_text_file
+class core_basic_file : public core_text_file
{
public:
- core_in_memory_file(std::uint32_t openflags, void const *data, std::size_t length, bool copy) noexcept
+ virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override;
+ virtual std::error_condition tell(std::uint64_t &result) noexcept override { result = m_index; return std::error_condition(); }
+ virtual std::error_condition length(std::uint64_t &result) noexcept override { result = m_size; return std::error_condition(); }
+
+ virtual bool eof() const override;
+
+protected:
+ core_basic_file(std::uint32_t openflags, std::uint64_t length) noexcept
: core_text_file(openflags)
+ , m_index(0)
+ , m_size(length)
+ {
+ }
+
+ std::uint64_t index() const noexcept { return m_index; }
+ void add_offset(std::size_t increment) noexcept { m_index += increment; m_size = (std::max)(m_size, m_index); }
+ std::uint64_t size() const noexcept { return m_size; }
+ void set_size(std::uint64_t value) noexcept { m_size = value; }
+
+ static std::size_t safe_buffer_copy(
+ void const *source, std::size_t sourceoffs, std::size_t sourcelen,
+ void *dest, std::size_t destoffs, std::size_t destlen) noexcept;
+
+
+private:
+ std::uint64_t m_index; // current file offset
+ std::uint64_t m_size; // total file length
+};
+
+class core_in_memory_file final : public core_basic_file
+{
+public:
+ core_in_memory_file(std::uint32_t openflags, void const *data, std::size_t length, bool copy) noexcept
+ : core_basic_file(openflags, length)
, m_data_allocated(false)
, m_data(copy ? nullptr : data)
- , m_offset(0)
- , m_length(length)
{
if (copy)
{
@@ -141,10 +170,6 @@ public:
~core_in_memory_file() override { purge(); }
- virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override;
- virtual std::error_condition tell(std::uint64_t &result) noexcept override { result = m_offset; return std::error_condition(); }
- virtual std::error_condition length(std::uint64_t &result) noexcept override { result = m_length; return std::error_condition(); }
-
virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override;
virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override;
@@ -153,29 +178,16 @@ public:
virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0; return std::errc::bad_file_descriptor; }
virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0; return std::errc::bad_file_descriptor; }
- virtual bool eof() const override;
-
- virtual void const *buffer() override { return m_data; }
+ void const *buffer() const { return m_data; }
virtual std::error_condition truncate(std::uint64_t offset) override;
protected:
- core_in_memory_file(std::uint32_t openflags, std::uint64_t length) noexcept
- : core_text_file(openflags)
- , m_data_allocated(false)
- , m_data(nullptr)
- , m_offset(0)
- , m_length(length)
- {
- }
-
- bool is_loaded() const noexcept { return nullptr != m_data; }
-
void *allocate() noexcept
{
- if (m_data || (std::numeric_limits<std::size_t>::max() < m_length))
+ if (m_data || (std::numeric_limits<std::size_t>::max() < size()))
return nullptr;
- void *data = malloc(m_length);
+ void *data = malloc(size());
if (data)
{
m_data_allocated = true;
@@ -192,28 +204,17 @@ protected:
m_data = nullptr;
}
- std::uint64_t offset() const noexcept { return m_offset; }
- void add_offset(std::size_t increment) noexcept { m_offset += increment; m_length = (std::max)(m_length, m_offset); }
- std::uint64_t length() const noexcept { return m_length; }
- void set_length(std::uint64_t value) noexcept { m_length = value; }
-
- static std::size_t safe_buffer_copy(
- void const *source, std::size_t sourceoffs, std::size_t sourcelen,
- void *dest, std::size_t destoffs, std::size_t destlen) noexcept;
-
private:
bool m_data_allocated; // was the data allocated by us?
void const * m_data; // file data, if RAM-based
- std::uint64_t m_offset; // current file offset
- std::uint64_t m_length; // total file length
};
-class core_osd_file final : public core_in_memory_file
+class core_osd_file final : public core_basic_file
{
public:
core_osd_file(std::uint32_t openmode, osd_file::ptr &&file, std::uint64_t length)
- : core_in_memory_file(openmode, length)
+ : core_basic_file(openmode, length)
, m_file(std::move(file))
{
}
@@ -227,12 +228,9 @@ public:
virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override;
virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override;
- virtual void const *buffer() override;
-
virtual std::error_condition truncate(std::uint64_t offset) override;
protected:
-
bool is_buffered(std::uint64_t offset) const noexcept { return (offset >= m_bufferbase) && (offset < (m_bufferbase + m_bufferbytes)); }
private:
@@ -246,13 +244,13 @@ private:
-/***************************************************************************
- core_text_file
-***************************************************************************/
+//**************************************************************************
+// core_text_file
+//**************************************************************************
-/*-------------------------------------------------
- getc - read a character from a file
--------------------------------------------------*/
+//-------------------------------------------------
+// getc - read a character from a file
+//-------------------------------------------------
int core_text_file::getc()
{
@@ -406,10 +404,10 @@ int core_text_file::getc()
}
-/*-------------------------------------------------
- ungetc - put back a character read from a
- file
--------------------------------------------------*/
+//-------------------------------------------------
+// ungetc - put back a character read from a
+// file
+//-------------------------------------------------
int core_text_file::ungetc(int c)
{
@@ -419,9 +417,9 @@ int core_text_file::ungetc(int c)
}
-/*-------------------------------------------------
- gets - read a line from a text file
--------------------------------------------------*/
+//-------------------------------------------------
+// gets - read a line from a text file
+//-------------------------------------------------
char *core_text_file::gets(char *s, int n)
{
@@ -466,9 +464,9 @@ char *core_text_file::gets(char *s, int n)
}
-/*-------------------------------------------------
- puts - write a string to a text file
--------------------------------------------------*/
+//-------------------------------------------------
+// puts - write a string to a text file
+//-------------------------------------------------
int core_text_file::puts(std::string_view s)
{
@@ -535,9 +533,9 @@ int core_text_file::puts(std::string_view s)
}
-/*-------------------------------------------------
- vprintf - vfprintf to a text file
--------------------------------------------------*/
+//-------------------------------------------------
+// vprintf - vfprintf to a text file
+//-------------------------------------------------
int core_text_file::vprintf(util::format_argument_pack<std::ostream> const &args)
{
@@ -550,15 +548,15 @@ int core_text_file::vprintf(util::format_argument_pack<std::ostream> const &args
-/***************************************************************************
- core_in_memory_file
-***************************************************************************/
+//**************************************************************************
+// core_basic_file
+//**************************************************************************
-/*-------------------------------------------------
- seek - seek within a file
--------------------------------------------------*/
+//-------------------------------------------------
+// seek - seek within a file
+//-------------------------------------------------
-std::error_condition core_in_memory_file::seek(std::int64_t offset, int whence) noexcept
+std::error_condition core_basic_file::seek(std::int64_t offset, int whence) noexcept
{
// flush any buffered char
clear_putback(); // TODO: report errors; also, should the argument check happen before this?
@@ -569,33 +567,33 @@ std::error_condition core_in_memory_file::seek(std::int64_t offset, int whence)
case SEEK_SET:
if (0 > offset)
return std::errc::invalid_argument;
- m_offset = offset;
+ m_index = offset;
return std::error_condition();
case SEEK_CUR:
if (0 > offset)
{
- if (std::uint64_t(-offset) > m_offset)
+ if (std::uint64_t(-offset) > m_index)
return std::errc::invalid_argument;
}
- else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_offset)
+ else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_index)
{
return std::errc::invalid_argument;
}
- m_offset += offset;
+ m_index += offset;
return std::error_condition();
case SEEK_END:
if (0 > offset)
{
- if (std::uint64_t(-offset) > m_length)
+ if (std::uint64_t(-offset) > m_size)
return std::errc::invalid_argument;
}
- else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_length)
+ else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_size)
{
return std::errc::invalid_argument;
}
- m_offset = m_length + offset;
+ m_index = m_size + offset;
return std::error_condition();
default:
@@ -604,35 +602,63 @@ std::error_condition core_in_memory_file::seek(std::int64_t offset, int whence)
}
-/*-------------------------------------------------
- eof - return 1 if we're at the end of file
--------------------------------------------------*/
+//-------------------------------------------------
+// eof - return true if we're at the end of file
+//-------------------------------------------------
-bool core_in_memory_file::eof() const
+bool core_basic_file::eof() const
{
// check for buffered chars
if (has_putback())
return false;
// if the offset == length, we're at EOF
- return (m_offset >= m_length);
+ return (m_index >= m_size);
}
-/*-------------------------------------------------
- read - read from a file
--------------------------------------------------*/
+//-------------------------------------------------
+// safe_buffer_copy - copy safely from one
+// bounded buffer to another
+//-------------------------------------------------
+
+std::size_t core_basic_file::safe_buffer_copy(
+ void const *source, std::size_t sourceoffs, std::size_t sourcelen,
+ void *dest, std::size_t destoffs, std::size_t destlen) noexcept
+{
+ auto const sourceavail = sourcelen - sourceoffs;
+ auto const destavail = destlen - destoffs;
+ auto const bytes_to_copy = (std::min)(sourceavail, destavail);
+ if (bytes_to_copy > 0)
+ {
+ std::memcpy(
+ reinterpret_cast<std::uint8_t *>(dest) + destoffs,
+ reinterpret_cast<std::uint8_t const *>(source) + sourceoffs,
+ bytes_to_copy);
+ }
+ return bytes_to_copy;
+}
+
+
+
+//**************************************************************************
+// core_in_memory_file
+//**************************************************************************
+
+//-------------------------------------------------
+// read - read from a file
+//-------------------------------------------------
std::error_condition core_in_memory_file::read(void *buffer, std::size_t length, std::size_t &actual) noexcept
{
clear_putback();
// handle RAM-based files
- if (m_offset < m_length)
- actual = safe_buffer_copy(m_data, std::size_t(m_offset), std::size_t(m_length), buffer, 0, length);
+ if (index() < size())
+ actual = safe_buffer_copy(m_data, std::size_t(index()), std::size_t(size()), buffer, 0, length);
else
actual = 0U;
- m_offset += actual;
+ add_offset(actual);
return std::error_condition();
}
@@ -641,60 +667,36 @@ std::error_condition core_in_memory_file::read_at(std::uint64_t offset, void *bu
clear_putback();
// handle RAM-based files
- if (offset < m_length)
- actual = safe_buffer_copy(m_data, std::size_t(offset), std::size_t(m_length), buffer, 0, length);
+ if (offset < size())
+ actual = safe_buffer_copy(m_data, std::size_t(offset), std::size_t(size()), buffer, 0, length);
else
actual = 0U;
return std::error_condition();
}
-/*-------------------------------------------------
- truncate - truncate a file
--------------------------------------------------*/
+//-------------------------------------------------
+// truncate - truncate a file
+//-------------------------------------------------
std::error_condition core_in_memory_file::truncate(std::uint64_t offset)
{
- if (m_length < offset)
+ if (size() < offset)
return std::errc::io_error; // TODO: revisit this error code
// adjust to new length and offset
- set_length(offset);
+ set_size(offset);
return std::error_condition();
}
-/*-------------------------------------------------
- safe_buffer_copy - copy safely from one
- bounded buffer to another
--------------------------------------------------*/
-
-std::size_t core_in_memory_file::safe_buffer_copy(
- void const *source, std::size_t sourceoffs, std::size_t sourcelen,
- void *dest, std::size_t destoffs, std::size_t destlen) noexcept
-{
- auto const sourceavail = sourcelen - sourceoffs;
- auto const destavail = destlen - destoffs;
- auto const bytes_to_copy = (std::min)(sourceavail, destavail);
- if (bytes_to_copy > 0)
- {
- std::memcpy(
- reinterpret_cast<std::uint8_t *>(dest) + destoffs,
- reinterpret_cast<std::uint8_t const *>(source) + sourceoffs,
- bytes_to_copy);
- }
- return bytes_to_copy;
-}
-
-
-
-/***************************************************************************
- core_osd_file
-***************************************************************************/
+//**************************************************************************
+// core_osd_file
+//**************************************************************************
-/*-------------------------------------------------
- closes a file
--------------------------------------------------*/
+//-------------------------------------------------
+// closes a file
+//-------------------------------------------------
core_osd_file::~core_osd_file()
{
@@ -702,15 +704,15 @@ core_osd_file::~core_osd_file()
}
-/*-------------------------------------------------
- read - read from a file
--------------------------------------------------*/
+//-------------------------------------------------
+// read - read from a file
+//-------------------------------------------------
std::error_condition core_osd_file::read(void *buffer, std::size_t length, std::size_t &actual) noexcept
{
// since osd_file works like pread/pwrite, implement in terms of read_at
// core_osd_file is declared final, so a derived class can't interfere
- std::error_condition err = read_at(offset(), buffer, length, actual);
+ std::error_condition err = read_at(index(), buffer, length, actual);
add_offset(actual);
return err;
}
@@ -718,8 +720,11 @@ std::error_condition core_osd_file::read(void *buffer, std::size_t length, std::
std::error_condition core_osd_file::read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept
{
- if (!m_file || is_loaded())
- return core_in_memory_file::read_at(offset, buffer, length, actual);
+ if (!m_file)
+ {
+ actual = 0U;
+ return std::errc::bad_file_descriptor;
+ }
// flush any buffered char
clear_putback();
@@ -768,55 +773,15 @@ std::error_condition core_osd_file::read_at(std::uint64_t offset, void *buffer,
}
-/*-------------------------------------------------
- buffer - return a pointer to the file buffer;
- if it doesn't yet exist, load the file into
- RAM first
--------------------------------------------------*/
-
-void const *core_osd_file::buffer()
-{
- // if we already have data, just return it
- if (!is_loaded() && length())
- {
- // allocate some memory
- void *const buf = allocate();
- if (!buf)
- return nullptr;
-
- // read the file
- std::uint64_t bytes_read = 0;
- std::uint64_t remaining = length();
- std::uint8_t *ptr = reinterpret_cast<std::uint8_t *>(buf);
- while (remaining)
- {
- std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), remaining);
- std::uint32_t read_length;
- std::error_condition const filerr = m_file->read(ptr, bytes_read, chunk, read_length);
- if (filerr || !read_length)
- {
- purge();
- return core_in_memory_file::buffer();
- }
- bytes_read += read_length;
- remaining -= read_length;
- ptr += read_length;
- }
- m_file.reset(); // close the file because we don't need it anymore
- }
- return core_in_memory_file::buffer();
-}
-
-
-/*-------------------------------------------------
- write - write to a file
--------------------------------------------------*/
+//-------------------------------------------------
+// write - write to a file
+//-------------------------------------------------
std::error_condition core_osd_file::write(void const *buffer, std::size_t length, std::size_t &actual) noexcept
{
// since osd_file works like pread/pwrite, implement in terms of write_at
// core_osd_file is declared final, so a derived class can't interfere
- std::error_condition err = write_at(offset(), buffer, length, actual);
+ std::error_condition err = write_at(index(), buffer, length, actual);
add_offset(actual);
return err;
}
@@ -824,10 +789,6 @@ std::error_condition core_osd_file::write(void const *buffer, std::size_t length
std::error_condition core_osd_file::write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept
{
- // can't write to RAM-based stuff
- if (is_loaded())
- return core_in_memory_file::write_at(offset, buffer, length, actual);
-
// flush any buffered char
clear_putback();
@@ -849,50 +810,41 @@ std::error_condition core_osd_file::write_at(std::uint64_t offset, void const *b
buffer = reinterpret_cast<std::uint8_t const *>(buffer) + bytes_written;
length -= bytes_written;
actual += bytes_written;
- set_length((std::max)(this->length(), offset));
+ set_size((std::max)(size(), offset));
}
return std::error_condition();
}
-/*-------------------------------------------------
- truncate - truncate a file
--------------------------------------------------*/
+//-------------------------------------------------
+// truncate - truncate a file
+//-------------------------------------------------
std::error_condition core_osd_file::truncate(std::uint64_t offset)
{
- if (is_loaded())
- return core_in_memory_file::truncate(offset);
-
// truncate file
std::error_condition err = m_file->truncate(offset);
if (err)
return err;
// and adjust to new length and offset
- set_length(offset);
+ set_size(offset);
return std::error_condition();
}
-/*-------------------------------------------------
- flush - flush file buffers
--------------------------------------------------*/
+//-------------------------------------------------
+// flush - flush file buffers
+//-------------------------------------------------
std::error_condition core_osd_file::finalize() noexcept
{
- if (is_loaded())
- return core_in_memory_file::finalize();
-
return std::error_condition();
}
std::error_condition core_osd_file::flush() noexcept
{
- if (is_loaded())
- return core_in_memory_file::flush();
-
// flush any buffered char
clear_putback();
@@ -906,14 +858,14 @@ std::error_condition core_osd_file::flush() noexcept
-/***************************************************************************
- core_file
-***************************************************************************/
+//**************************************************************************
+// core_file
+//**************************************************************************
-/*-------------------------------------------------
- open - open a file for access and
- return an error code
--------------------------------------------------*/
+//-------------------------------------------------
+// open - open a file for access and
+// return an error code
+//-------------------------------------------------
std::error_condition core_file::open(std::string_view filename, std::uint32_t openflags, ptr &file) noexcept
{
@@ -931,10 +883,10 @@ std::error_condition core_file::open(std::string_view filename, std::uint32_t op
}
-/*-------------------------------------------------
- open_ram - open a RAM-based buffer for file-
- like access and return an error code
--------------------------------------------------*/
+//-------------------------------------------------
+// open_ram - open a RAM-based buffer for file-
+// like access and return an error code
+//-------------------------------------------------
std::error_condition core_file::open_ram(void const *data, std::size_t length, std::uint32_t openflags, ptr &file) noexcept
{
@@ -959,11 +911,11 @@ std::error_condition core_file::open_ram(void const *data, std::size_t length, s
}
-/*-------------------------------------------------
- open_ram_copy - open a copy of a RAM-based
- buffer for file-like access and return an
- error code
--------------------------------------------------*/
+//-------------------------------------------------
+// open_ram_copy - open a copy of a RAM-based
+// buffer for file-like access and return an
+// error code
+//-------------------------------------------------
std::error_condition core_file::open_ram_copy(void const *data, std::size_t length, std::uint32_t openflags, ptr &file) noexcept
{
@@ -979,7 +931,7 @@ std::error_condition core_file::open_ram_copy(void const *data, std::size_t leng
if (std::uint64_t(length) != length)
return std::errc::file_too_large;
- ptr result(new (std::nothrow) core_in_memory_file(openflags, data, length, true));
+ std::unique_ptr<core_in_memory_file> result(new (std::nothrow) core_in_memory_file(openflags, data, length, true));
if (!result || !result->buffer())
return std::errc::not_enough_memory;
@@ -988,10 +940,10 @@ std::error_condition core_file::open_ram_copy(void const *data, std::size_t leng
}
-/*-------------------------------------------------
- open_proxy - open a proxy to an existing file
- object and return an error code
--------------------------------------------------*/
+//-------------------------------------------------
+// open_proxy - open a proxy to an existing file
+// object and return an error code
+//-------------------------------------------------
std::error_condition core_file::open_proxy(core_file &file, ptr &proxy) noexcept
{
@@ -1004,20 +956,20 @@ std::error_condition core_file::open_proxy(core_file &file, ptr &proxy) noexcept
}
-/*-------------------------------------------------
- closes a file
--------------------------------------------------*/
+//-------------------------------------------------
+// closes a file
+//-------------------------------------------------
core_file::~core_file()
{
}
-/*-------------------------------------------------
- load - open a file with the specified
- filename, read it into memory, and return a
- pointer
--------------------------------------------------*/
+//-------------------------------------------------
+// load - open a file with the specified
+// filename, read it into memory, and return a
+// pointer
+//-------------------------------------------------
std::error_condition core_file::load(std::string_view filename, void **data, std::uint32_t &length) noexcept
{