summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util')
-rw-r--r--src/lib/util/cdrom.cpp12
-rw-r--r--src/lib/util/chd.cpp68
-rw-r--r--src/lib/util/chd.h10
-rw-r--r--src/lib/util/corefile.cpp1642
-rw-r--r--src/lib/util/corefile.h127
-rw-r--r--src/lib/util/flac.cpp14
-rw-r--r--src/lib/util/flac.h12
-rw-r--r--src/lib/util/options.cpp4
-rw-r--r--src/lib/util/options.h2
-rw-r--r--src/lib/util/palette.cpp8
-rw-r--r--src/lib/util/palette.h2
-rw-r--r--src/lib/util/png.cpp62
-rw-r--r--src/lib/util/png.h12
-rw-r--r--src/lib/util/strformat.h178
-rw-r--r--src/lib/util/vecstream.h27
-rw-r--r--src/lib/util/xmlfile.cpp30
-rw-r--r--src/lib/util/xmlfile.h4
-rw-r--r--src/lib/util/zippath.cpp12
-rw-r--r--src/lib/util/zippath.h2
19 files changed, 1231 insertions, 997 deletions
diff --git a/src/lib/util/cdrom.cpp b/src/lib/util/cdrom.cpp
index 10a1828d5e4..8bdf4af6c0f 100644
--- a/src/lib/util/cdrom.cpp
+++ b/src/lib/util/cdrom.cpp
@@ -115,7 +115,7 @@ struct cdrom_file
/** @brief Information describing the track. */
chdcd_track_input_info track_info; /* track info */
/** @brief The fhandle[ CD maximum tracks]. */
- core_file * fhandle[CD_MAX_TRACKS];/* file handle */
+ util::core_file::ptr fhandle[CD_MAX_TRACKS];/* file handle */
};
@@ -244,7 +244,7 @@ cdrom_file *cdrom_open(const char *inputfile)
for (i = 0; i < file->cdtoc.numtrks; i++)
{
- file_error filerr = core_fopen(file->track_info.track[i].fname.c_str(), OPEN_FLAG_READ, &file->fhandle[i]);
+ file_error filerr = util::core_file::open(file->track_info.track[i].fname.c_str(), OPEN_FLAG_READ, file->fhandle[i]);
if (filerr != FILERR_NONE)
{
fprintf(stderr, "Unable to open file: %s\n", file->track_info.track[i].fname.c_str());
@@ -418,7 +418,7 @@ void cdrom_close(cdrom_file *file)
{
for (int i = 0; i < file->cdtoc.numtrks; i++)
{
- core_fclose(file->fhandle[i]);
+ file->fhandle[i].reset();
}
}
@@ -474,7 +474,7 @@ chd_error read_partial_sector(cdrom_file *file, void *dest, UINT32 lbasector, UI
else
{
// else read from the appropriate file
- core_file *srcfile = file->fhandle[tracknum];
+ util::core_file &srcfile = *file->fhandle[tracknum];
UINT64 sourcefileoffset = file->track_info.track[tracknum].offset;
int bytespersector = file->cdtoc.tracks[tracknum].datasize + file->cdtoc.tracks[tracknum].subsize;
@@ -483,8 +483,8 @@ chd_error read_partial_sector(cdrom_file *file, void *dest, UINT32 lbasector, UI
// printf("Reading sector %d from track %d at offset %lld\n", chdsector, tracknum, sourcefileoffset);
- core_fseek(srcfile, sourcefileoffset, SEEK_SET);
- core_fread(srcfile, dest, length);
+ srcfile.seek(sourcefileoffset, SEEK_SET);
+ srcfile.read(dest, length);
needswap = file->track_info.track[tracknum].swap;
}
diff --git a/src/lib/util/chd.cpp b/src/lib/util/chd.cpp
index 3419f404c09..93a1b34ba29 100644
--- a/src/lib/util/chd.cpp
+++ b/src/lib/util/chd.cpp
@@ -190,8 +190,8 @@ inline void chd_file::file_read(UINT64 offset, void *dest, UINT32 length)
throw CHDERR_NOT_OPEN;
// seek and read
- core_fseek(m_file, offset, SEEK_SET);
- UINT32 count = core_fread(m_file, dest, length);
+ m_file->seek(offset, SEEK_SET);
+ UINT32 count = m_file->read(dest, length);
if (count != length)
throw CHDERR_READ_ERROR;
}
@@ -209,8 +209,8 @@ inline void chd_file::file_write(UINT64 offset, const void *source, UINT32 lengt
throw CHDERR_NOT_OPEN;
// seek and write
- core_fseek(m_file, offset, SEEK_SET);
- UINT32 count = core_fwrite(m_file, source, length);
+ m_file->seek(offset, SEEK_SET);
+ UINT32 count = m_file->write(source, length);
if (count != length)
throw CHDERR_WRITE_ERROR;
}
@@ -229,10 +229,10 @@ inline UINT64 chd_file::file_append(const void *source, UINT32 length, UINT32 al
throw CHDERR_NOT_OPEN;
// seek to the end and align if necessary
- core_fseek(m_file, 0, SEEK_END);
+ m_file->seek(0, SEEK_END);
if (alignment != 0)
{
- UINT64 offset = core_ftell(m_file);
+ UINT64 offset = m_file->tell();
UINT32 delta = offset % alignment;
if (delta != 0)
{
@@ -243,7 +243,7 @@ inline UINT64 chd_file::file_append(const void *source, UINT32 length, UINT32 al
while (delta != 0)
{
UINT32 bytes_to_write = MIN(sizeof(buffer), delta);
- UINT32 count = core_fwrite(m_file, buffer, bytes_to_write);
+ UINT32 count = m_file->write(buffer, bytes_to_write);
if (count != bytes_to_write)
throw CHDERR_WRITE_ERROR;
delta -= bytes_to_write;
@@ -252,8 +252,8 @@ inline UINT64 chd_file::file_append(const void *source, UINT32 length, UINT32 al
}
// write the real data
- UINT64 offset = core_ftell(m_file);
- UINT32 count = core_fwrite(m_file, source, length);
+ UINT64 offset = m_file->tell();
+ UINT32 count = m_file->write(source, length);
if (count != length)
throw CHDERR_READ_ERROR;
return offset;
@@ -567,7 +567,7 @@ void chd_file::set_parent_sha1(sha1_t parent)
}
/**
- * @fn chd_error chd_file::create(core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 unitbytes, chd_codec_type compression[4])
+ * @fn chd_error chd_file::create(util::core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 unitbytes, chd_codec_type compression[4])
*
* @brief -------------------------------------------------
* create - create a new file with no parent using an existing opened file handle
@@ -582,7 +582,7 @@ void chd_file::set_parent_sha1(sha1_t parent)
* @return A chd_error.
*/
-chd_error chd_file::create(core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 unitbytes, chd_codec_type compression[4])
+chd_error chd_file::create(util::core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 unitbytes, chd_codec_type compression[4])
{
// make sure we don't already have a file open
if (m_file != nullptr)
@@ -602,7 +602,7 @@ chd_error chd_file::create(core_file &file, UINT64 logicalbytes, UINT32 hunkbyte
}
/**
- * @fn chd_error chd_file::create(core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, chd_codec_type compression[4], chd_file &parent)
+ * @fn chd_error chd_file::create(util::core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, chd_codec_type compression[4], chd_file &parent)
*
* @brief -------------------------------------------------
* create - create a new file with a parent using an existing opened file handle
@@ -617,7 +617,7 @@ chd_error chd_file::create(core_file &file, UINT64 logicalbytes, UINT32 hunkbyte
* @return A chd_error.
*/
-chd_error chd_file::create(core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, chd_codec_type compression[4], chd_file &parent)
+chd_error chd_file::create(util::core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, chd_codec_type compression[4], chd_file &parent)
{
// make sure we don't already have a file open
if (m_file != nullptr)
@@ -659,21 +659,25 @@ chd_error chd_file::create(const char *filename, UINT64 logicalbytes, UINT32 hun
return CHDERR_ALREADY_OPEN;
// create the new file
- core_file *file = nullptr;
- file_error filerr = core_fopen(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &file);
+ util::core_file::ptr file;
+ const file_error filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file);
if (filerr != FILERR_NONE)
return CHDERR_FILE_NOT_FOUND;
// create the file normally, then claim the file
- chd_error chderr = create(*file, logicalbytes, hunkbytes, unitbytes, compression);
+ const chd_error chderr = create(*file, logicalbytes, hunkbytes, unitbytes, compression);
m_owns_file = true;
// if an error happened, close and delete the file
if (chderr != CHDERR_NONE)
{
- core_fclose(file);
+ file.reset();
osd_rmfile(filename);
}
+ else
+ {
+ file.release();
+ }
return chderr;
}
@@ -700,21 +704,25 @@ chd_error chd_file::create(const char *filename, UINT64 logicalbytes, UINT32 hun
return CHDERR_ALREADY_OPEN;
// create the new file
- core_file *file = nullptr;
- file_error filerr = core_fopen(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &file);
+ util::core_file::ptr file;
+ const file_error filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file);
if (filerr != FILERR_NONE)
return CHDERR_FILE_NOT_FOUND;
// create the file normally, then claim the file
- chd_error chderr = create(*file, logicalbytes, hunkbytes, compression, parent);
+ const chd_error chderr = create(*file, logicalbytes, hunkbytes, compression, parent);
m_owns_file = true;
// if an error happened, close and delete the file
if (chderr != CHDERR_NONE)
{
- core_fclose(file);
+ file.reset();
osd_rmfile(filename);
}
+ else
+ {
+ file.release();
+ }
return chderr;
}
@@ -739,27 +747,25 @@ chd_error chd_file::open(const char *filename, bool writeable, chd_file *parent)
return CHDERR_ALREADY_OPEN;
// open the file
- UINT32 openflags = writeable ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_READ;
- core_file *file = nullptr;
- file_error filerr = core_fopen(filename, openflags, &file);
+ const UINT32 openflags = writeable ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_READ;
+ util::core_file::ptr file;
+ const file_error filerr = util::core_file::open(filename, openflags, file);
if (filerr != FILERR_NONE)
return CHDERR_FILE_NOT_FOUND;
// now open the CHD
chd_error err = open(*file, writeable, parent);
if (err != CHDERR_NONE)
- {
- core_fclose(file);
return err;
- }
// we now own this file
+ file.release();
m_owns_file = true;
return err;
}
/**
- * @fn chd_error chd_file::open(core_file &file, bool writeable, chd_file *parent)
+ * @fn chd_error chd_file::open(util::core_file &file, bool writeable, chd_file *parent)
*
* @brief -------------------------------------------------
* open - open an existing file for read or read/write
@@ -772,7 +778,7 @@ chd_error chd_file::open(const char *filename, bool writeable, chd_file *parent)
* @return A chd_error.
*/
-chd_error chd_file::open(core_file &file, bool writeable, chd_file *parent)
+chd_error chd_file::open(util::core_file &file, bool writeable, chd_file *parent)
{
// make sure we don't already have a file open
if (m_file != nullptr)
@@ -796,8 +802,8 @@ chd_error chd_file::open(core_file &file, bool writeable, chd_file *parent)
void chd_file::close()
{
// reset file characteristics
- if (m_owns_file && m_file != nullptr)
- core_fclose(m_file);
+ if (m_owns_file && m_file)
+ delete m_file;
m_file = nullptr;
m_owns_file = false;
m_allow_reads = false;
diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h
index d9a1dd57f51..ee8a03f5d17 100644
--- a/src/lib/util/chd.h
+++ b/src/lib/util/chd.h
@@ -304,7 +304,7 @@ public:
virtual ~chd_file();
// operators
- operator core_file *() { return m_file; }
+ operator util::core_file &() { return *m_file; }
// getters
bool opened() const { return (m_file != nullptr); }
@@ -328,13 +328,13 @@ public:
// file create
chd_error create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 unitbytes, chd_codec_type compression[4]);
- chd_error create(core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 unitbytes, chd_codec_type compression[4]);
+ chd_error create(util::core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 unitbytes, chd_codec_type compression[4]);
chd_error create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, chd_codec_type compression[4], chd_file &parent);
- chd_error create(core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, chd_codec_type compression[4], chd_file &parent);
+ chd_error create(util::core_file &file, UINT64 logicalbytes, UINT32 hunkbytes, chd_codec_type compression[4], chd_file &parent);
// file open
chd_error open(const char *filename, bool writeable = false, chd_file *parent = nullptr);
- chd_error open(core_file &file, bool writeable = false, chd_file *parent = nullptr);
+ chd_error open(util::core_file &file, bool writeable = false, chd_file *parent = nullptr);
// file close
void close();
@@ -401,7 +401,7 @@ private:
static int CLIB_DECL metadata_hash_compare(const void *elem1, const void *elem2);
// file characteristics
- core_file * m_file; // handle to the open core file
+ util::core_file * m_file; // handle to the open core file
bool m_owns_file; // flag indicating if this file should be closed on chd_close()
bool m_allow_reads; // permit reads from this CHD?
bool m_allow_writes; // permit writes to this CHD?
diff --git a/src/lib/util/corefile.cpp b/src/lib/util/corefile.cpp
index 25978afdb2c..64169a606fc 100644
--- a/src/lib/util/corefile.cpp
+++ b/src/lib/util/corefile.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
corefile.c
@@ -8,17 +8,24 @@
***************************************************************************/
-#include <assert.h>
-
#include "corefile.h"
+
#include "unicode.h"
+#include "vecstream.h"
+
#include <zlib.h>
-#include <stdarg.h>
+#include <algorithm>
+#include <cassert>
+#include <cstring>
#include <ctype.h>
+namespace util {
+
+namespace {
+
/***************************************************************************
VALIDATION
***************************************************************************/
@@ -30,613 +37,513 @@
/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-#define FILE_BUFFER_SIZE 512
-
-#define OPEN_FLAG_HAS_CRC 0x10000
-
-
-
-/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
-enum text_file_type
-{
- TFT_OSD = 0, /* OSD depdendent encoding format used when BOMs missing */
- TFT_UTF8, /* UTF-8 */
- TFT_UTF16BE, /* UTF-16 (big endian) */
- TFT_UTF16LE, /* UTF-16 (little endian) */
- TFT_UTF32BE, /* UTF-32 (UCS-4) (big endian) */
- TFT_UTF32LE /* UTF-32 (UCS-4) (little endian) */
-};
-
-
-struct zlib_data
-{
- z_stream stream;
- UINT8 buffer[1024];
- UINT64 realoffset;
- UINT64 nextoffset;
-};
-
-
-struct core_file
+class zlib_data
{
- osd_file * file; /* OSD file handle */
- zlib_data * zdata; /* compression data */
- UINT32 openflags; /* flags we were opened with */
- UINT8 data_allocated; /* was the data allocated by us? */
- UINT8 * data; /* file data, if RAM-based */
- UINT64 offset; /* current file offset */
- UINT64 length; /* total file length */
- text_file_type text_type; /* text output format */
- char back_chars[UTF8_CHAR_MAX]; /* buffer to hold characters for ungetc */
- int back_char_head; /* head of ungetc buffer */
- int back_char_tail; /* tail of ungetc buffer */
- UINT64 bufferbase; /* base offset of internal buffer */
- UINT32 bufferbytes; /* bytes currently loaded into buffer */
- UINT8 buffer[FILE_BUFFER_SIZE]; /* buffer data */
-};
-
-
-
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-/* misc helpers */
-static UINT32 safe_buffer_copy(const void *source, UINT32 sourceoffs, UINT32 sourcelen, void *dest, UINT32 destoffs, UINT32 destlen);
-static file_error osd_or_zlib_read(core_file *file, void *buffer, UINT64 offset, UINT32 length, UINT32 *actual);
-static file_error osd_or_zlib_write(core_file *file, const void *buffer, UINT64 offset, UINT32 length, UINT32 *actual);
-
-
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-
-/*-------------------------------------------------
- is_directory_separator - is a given character
- a directory separator? The following logic
- works for most platforms
--------------------------------------------------*/
+public:
+ typedef std::unique_ptr<zlib_data> ptr;
-static inline int is_directory_separator(char c)
-{
- return (c == '\\' || c == '/' || c == ':');
-}
-
-
-
-/***************************************************************************
- FILE OPEN/CLOSE
-***************************************************************************/
+ static int start_compression(int level, std::uint64_t offset, ptr &data)
+ {
+ ptr result(new zlib_data(offset));
+ result->reset_output();
+ auto const zerr = deflateInit(&result->m_stream, level);
+ result->m_compress = (Z_OK == zerr);
+ if (result->m_compress) data = std::move(result);
+ return zerr;
+ }
+ static int start_decompression(std::uint64_t offset, ptr &data)
+ {
+ ptr result(new zlib_data(offset));
+ auto const zerr = inflateInit(&result->m_stream);
+ result->m_decompress = (Z_OK == zerr);
+ if (result->m_decompress) data = std::move(result);
+ return zerr;
+ }
-/*-------------------------------------------------
- core_fopen - open a file for access and
- return an error code
--------------------------------------------------*/
+ ~zlib_data()
+ {
+ if (m_compress) deflateEnd(&m_stream);
+ else if (m_decompress) inflateEnd(&m_stream);
+ }
-file_error core_fopen(const char *filename, UINT32 openflags, core_file **file)
-{
- file_error filerr = FILERR_NOT_FOUND;
+ std::size_t buffer_size() const { return sizeof(m_buffer); }
+ void const *buffer_data() const { return m_buffer; }
+ void *buffer_data() { return m_buffer; }
- /* allocate the file itself */
- *file = (core_file *)malloc(sizeof(**file));
- if (*file == nullptr)
- return FILERR_OUT_OF_MEMORY;
- memset(*file, 0, sizeof(**file));
+ // general-purpose output buffer manipulation
+ bool output_full() const { return 0 == m_stream.avail_out; }
+ std::size_t output_space() const { return m_stream.avail_out; }
+ void set_output(void *data, std::uint32_t size)
+ {
+ m_stream.next_out = reinterpret_cast<Bytef *>(data);
+ m_stream.avail_out = size;
+ }
- /* attempt to open the file */
- filerr = osd_open(filename, openflags, &(*file)->file, &(*file)->length);
- (*file)->openflags = openflags;
+ // working with output to the internal buffer
+ bool has_output() const { return m_stream.avail_out != sizeof(m_buffer); }
+ std::size_t output_size() const { return sizeof(m_buffer) - m_stream.avail_out; }
+ void reset_output()
+ {
+ m_stream.next_out = m_buffer;
+ m_stream.avail_out = sizeof(m_buffer);
+ }
- /* handle errors and return */
- if (filerr != FILERR_NONE)
+ // general-purpose input buffer manipulation
+ bool has_input() const { return 0 != m_stream.avail_in; }
+ std::size_t input_size() const { return m_stream.avail_in; }
+ void set_input(void const *data, std::uint32_t size)
{
- core_fclose(*file);
- *file = nullptr;
+ m_stream.next_in = const_cast<Bytef *>(reinterpret_cast<Bytef const *>(data));
+ m_stream.avail_in = size;
}
- return filerr;
-}
+ // working with input from the internal buffer
+ void reset_input(std::uint32_t size)
+ {
+ m_stream.next_in = m_buffer;
+ m_stream.avail_in = size;
+ }
-/*-------------------------------------------------
- core_fopen_ram_internal - open a RAM-based buffer
- for file-like access, possibly copying the data,
- and return an error code
--------------------------------------------------*/
+ int compress() { assert(m_compress); return deflate(&m_stream, Z_NO_FLUSH); }
+ int finalise() { assert(m_compress); return deflate(&m_stream, Z_FINISH); }
+ int decompress() { assert(m_decompress); return inflate(&m_stream, Z_SYNC_FLUSH); }
-static file_error core_fopen_ram_internal(const void *data, size_t length, int copy_buffer, UINT32 openflags, core_file **file)
-{
- /* can only do this for read access */
- if ((openflags & OPEN_FLAG_WRITE) != 0)
- return FILERR_INVALID_ACCESS;
- if ((openflags & OPEN_FLAG_CREATE) != 0)
- return FILERR_INVALID_ACCESS;
+ std::uint64_t realoffset() const { return m_realoffset; }
+ void add_realoffset(std::uint32_t increment) { m_realoffset += increment; }
- /* allocate the file itself */
- *file = (core_file *)malloc(sizeof(**file) + (copy_buffer ? length : 0));
- if (*file == nullptr)
- return FILERR_OUT_OF_MEMORY;
- memset(*file, 0, sizeof(**file));
+ bool is_nextoffset(std::uint64_t value) const { return m_nextoffset == value; }
+ void add_nextoffset(std::uint32_t increment) { m_nextoffset += increment; }
- /* copy the buffer, if we're asked to */
- if (copy_buffer)
+private:
+ zlib_data(std::uint64_t offset)
+ : m_compress(false)
+ , m_decompress(false)
+ , m_realoffset(offset)
+ , m_nextoffset(offset)
{
- void *dest = ((UINT8 *) *file) + sizeof(**file);
- memcpy(dest, data, length);
- data = dest;
+ m_stream.zalloc = Z_NULL;
+ m_stream.zfree = Z_NULL;
+ m_stream.opaque = Z_NULL;
+ m_stream.avail_in = m_stream.avail_out = 0;
}
- /* claim the buffer */
- (*file)->data = (UINT8 *)data;
- (*file)->length = length;
- (*file)->openflags = openflags;
-
- return FILERR_NONE;
-}
-
+ bool m_compress, m_decompress;
+ z_stream m_stream;
+ std::uint8_t m_buffer[1024];
+ std::uint64_t m_realoffset;
+ std::uint64_t m_nextoffset;
+};
-/*-------------------------------------------------
- core_fopen_ram - open a RAM-based buffer for
- file-like access and return an error code
--------------------------------------------------*/
-file_error core_fopen_ram(const void *data, size_t length, UINT32 openflags, core_file **file)
+class core_proxy_file : public core_file
{
- return core_fopen_ram_internal(data, length, FALSE, openflags, file);
-}
-
+public:
+ core_proxy_file(core_file &file) : m_file(file) { }
+ virtual ~core_proxy_file() override { }
+ virtual file_error compress(int level) override { return m_file.compress(level); }
+
+ virtual int seek(std::int64_t offset, int whence) override { return m_file.seek(offset, whence); }
+ virtual std::uint64_t tell() const override { return m_file.tell(); }
+ virtual bool eof() const override { return m_file.eof(); }
+ virtual std::uint64_t size() const override { return m_file.size(); }
+
+ virtual std::uint32_t read(void *buffer, std::uint32_t length) override { return m_file.read(buffer, length); }
+ 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 const void *buffer() override { return m_file.buffer(); }
+
+ virtual std::uint32_t write(const void *buffer, std::uint32_t length) override { return m_file.write(buffer, length); }
+ virtual int puts(const char *s) override { return m_file.puts(s); }
+ virtual int vprintf(util::format_argument_pack<std::ostream> const &args) override { return m_file.vprintf(args); }
+ virtual file_error truncate(std::uint64_t offset) override { return m_file.truncate(offset); }
+
+ virtual file_error flush() override { return m_file.flush(); }
+
+private:
+ core_file &m_file;
+};
-/*-------------------------------------------------
- core_fopen_ram_copy - open a copy of a RAM-based
- buffer for file-like access and return an error code
--------------------------------------------------*/
-file_error core_fopen_ram_copy(const void *data, size_t length, UINT32 openflags, core_file **file)
+class core_text_file : public core_file
{
- return core_fopen_ram_internal(data, length, TRUE, openflags, file);
-}
-
+public:
+ enum class text_file_type
+ {
+ OSD, // OSD dependent encoding format used when BOMs missing
+ UTF8, // UTF-8
+ UTF16BE, // UTF-16 (big endian)
+ UTF16LE, // UTF-16 (little endian)
+ UTF32BE, // UTF-32 (UCS-4) (big endian)
+ UTF32LE // UTF-32 (UCS-4) (little endian)
+ };
+
+ virtual int getc() override;
+ virtual int ungetc(int c) override;
+ virtual char *gets(char *s, int n) override;
+ virtual int puts(char const *s) override;
+ virtual int vprintf(util::format_argument_pack<std::ostream> const &args) override;
+
+protected:
+ core_text_file(std::uint32_t openflags)
+ : m_openflags(openflags)
+ , m_text_type(text_file_type::OSD)
+ , m_back_char_head(0)
+ , m_back_char_tail(0)
+ , m_printf_buffer()
+ {
+ }
-/*-------------------------------------------------
- core_fclose - closes a file
--------------------------------------------------*/
+ bool read_access() const { return 0U != (m_openflags & OPEN_FLAG_READ); }
+ bool write_access() const { return 0U != (m_openflags & OPEN_FLAG_WRITE); }
+ bool no_bom() const { return 0U != (m_openflags & OPEN_FLAG_NO_BOM); }
-void core_fclose(core_file *file)
-{
- /* close files and free memory */
- if (file->zdata != nullptr)
- core_fcompress(file, FCOMPRESS_NONE);
- if (file->file != nullptr)
- osd_close(file->file);
- if (file->data != nullptr && file->data_allocated)
- free(file->data);
- free(file);
-}
+ bool has_putback() const { return m_back_char_head != m_back_char_tail; }
+ void clear_putback() { m_back_char_head = m_back_char_tail = 0; }
+private:
+ std::uint32_t const m_openflags; // flags we were opened with
+ text_file_type m_text_type; // text output format
+ char m_back_chars[UTF8_CHAR_MAX]; // buffer to hold characters for ungetc
+ int m_back_char_head; // head of ungetc buffer
+ int m_back_char_tail; // tail of ungetc buffer
+ ovectorstream m_printf_buffer; // persistent buffer for formatted output
+};
-/*-------------------------------------------------
- core_fcompress - enable/disable streaming file
- compression via zlib; level is 0 to disable
- compression, or up to 9 for max compression
--------------------------------------------------*/
-file_error core_fcompress(core_file *file, int level)
+class core_in_memory_file : public core_text_file
{
- file_error result = FILERR_NONE;
-
- /* can only do this for read-only and write-only cases */
- if ((file->openflags & OPEN_FLAG_WRITE) != 0 && (file->openflags & OPEN_FLAG_READ) != 0)
- return FILERR_INVALID_ACCESS;
-
- /* if we have been compressing, flush and free the data */
- if (file->zdata != nullptr && level == FCOMPRESS_NONE)
+public:
+ core_in_memory_file(std::uint32_t openflags, void const *data, std::size_t length, bool copy)
+ : core_text_file(openflags)
+ , m_data_allocated(false)
+ , m_data(copy ? nullptr : data)
+ , m_offset(0)
+ , m_length(length)
{
- int zerr = Z_OK;
-
- /* flush any remaining data if we are writing */
- while ((file->openflags & OPEN_FLAG_WRITE) != 0 && zerr != Z_STREAM_END)
+ if (copy)
{
- UINT32 actualdata;
- file_error filerr;
-
- /* deflate some more */
- zerr = deflate(&file->zdata->stream, Z_FINISH);
- if (zerr != Z_STREAM_END && zerr != Z_OK)
- {
- result = FILERR_INVALID_DATA;
- break;
- }
-
- /* write the data */
- if (file->zdata->stream.avail_out != sizeof(file->zdata->buffer))
- {
- filerr = osd_write(file->file, file->zdata->buffer, file->zdata->realoffset, sizeof(file->zdata->buffer) - file->zdata->stream.avail_out, &actualdata);
- if (filerr != FILERR_NONE)
- break;
- file->zdata->realoffset += actualdata;
- file->zdata->stream.next_out = file->zdata->buffer;
- file->zdata->stream.avail_out = sizeof(file->zdata->buffer);
- }
+ void *const buf = allocate();
+ if (buf) std::memcpy(buf, data, length);
}
+ }
- /* end the appropriate operation */
- if ((file->openflags & OPEN_FLAG_WRITE) != 0)
- deflateEnd(&file->zdata->stream);
- else
- inflateEnd(&file->zdata->stream);
+ ~core_in_memory_file() override { purge(); }
+ virtual file_error compress(int level) override { return FILERR_INVALID_ACCESS; }
- /* free memory */
- free(file->zdata);
- file->zdata = nullptr;
- }
+ virtual int seek(std::int64_t offset, int whence) override;
+ virtual std::uint64_t tell() const override { return m_offset; }
+ virtual bool eof() const override;
+ virtual std::uint64_t size() const override { return m_length; }
- /* if we are just starting to compress, allocate a new buffer */
- if (file->zdata == nullptr && level > FCOMPRESS_NONE)
- {
- int zerr;
+ virtual std::uint32_t read(void *buffer, std::uint32_t length) override;
+ virtual void const *buffer() override { return m_data; }
- /* allocate memory */
- file->zdata = (zlib_data *)malloc(sizeof(*file->zdata));
- if (file->zdata == nullptr)
- return FILERR_OUT_OF_MEMORY;
- memset(file->zdata, 0, sizeof(*file->zdata));
+ virtual std::uint32_t write(void const *buffer, std::uint32_t length) override { return 0; }
+ virtual file_error truncate(std::uint64_t offset) override;
+ virtual file_error flush() override { clear_putback(); return FILERR_NONE; }
- /* initialize the stream and compressor */
- if ((file->openflags & OPEN_FLAG_WRITE) != 0)
- {
- file->zdata->stream.next_out = file->zdata->buffer;
- file->zdata->stream.avail_out = sizeof(file->zdata->buffer);
- zerr = deflateInit(&file->zdata->stream, level);
- }
- else
- zerr = inflateInit(&file->zdata->stream);
+protected:
+ core_in_memory_file(std::uint32_t openflags, std::uint64_t length)
+ : core_text_file(openflags)
+ , m_data_allocated(false)
+ , m_data(nullptr)
+ , m_offset(0)
+ , m_length(length)
+ {
+ }
- /* on error, return an error */
- if (zerr != Z_OK)
+ bool is_loaded() const { return nullptr != m_data; }
+ void *allocate()
+ {
+ if (m_data) return nullptr;
+ void *data = malloc(m_length);
+ if (data)
{
- free(file->zdata);
- file->zdata = nullptr;
- return FILERR_OUT_OF_MEMORY;
+ m_data_allocated = true;
+ m_data = data;
}
-
- /* flush buffers */
- file->bufferbytes = 0;
-
- /* set the initial offset */
- file->zdata->realoffset = file->offset;
- file->zdata->nextoffset = file->offset;
+ return data;
+ }
+ void purge()
+ {
+ if (m_data && m_data_allocated) free(const_cast<void *>(m_data));
+ m_data_allocated = false;
+ m_data = nullptr;
}
- return result;
-}
-
+ std::uint64_t offset() const { return m_offset; }
+ void add_offset(std::uint32_t increment) { m_offset += increment; m_length = (std::max)(m_length, m_offset); }
+ std::uint64_t length() const { return m_length; }
+ void set_length(std::uint64_t value) { m_length = value; m_offset = (std::min)(m_offset, m_length); }
+ 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);
-/***************************************************************************
- FILE POSITIONING
-***************************************************************************/
+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
+};
-/*-------------------------------------------------
- core_fseek - seek within a file
--------------------------------------------------*/
-int core_fseek(core_file *file, INT64 offset, int whence)
+class core_osd_file : public core_in_memory_file
{
- int err = 0;
-
- /* error if compressing */
- if (file->zdata != nullptr)
- return 1;
-
- /* flush any buffered char */
- file->back_char_head = 0;
- file->back_char_tail = 0;
-
- /* switch off the relative location */
- switch (whence)
+public:
+ core_osd_file(std::uint32_t openmode, osd_file *file, std::uint64_t length)
+ : core_in_memory_file(openmode, length)
+ , m_file(file)
+ , m_zdata()
+ , m_bufferbase(0)
+ , m_bufferbytes(0)
{
- case SEEK_SET:
- file->offset = offset;
- break;
-
- case SEEK_CUR:
- file->offset += offset;
- break;
-
- case SEEK_END:
- file->offset = file->length + offset;
- break;
}
- return err;
-}
+ ~core_osd_file() override;
+ virtual file_error compress(int level) override;
-/*-------------------------------------------------
- core_ftell - return the current file position
--------------------------------------------------*/
+ virtual int seek(std::int64_t offset, int whence) override;
-UINT64 core_ftell(core_file *file)
-{
- /* return the current offset */
- return file->offset;
-}
+ virtual std::uint32_t read(void *buffer, std::uint32_t length) override;
+ virtual void const *buffer() override;
+ virtual std::uint32_t write(void const *buffer, std::uint32_t length) override;
+ virtual file_error truncate(std::uint64_t offset) override;
+ virtual file_error flush() override;
-/*-------------------------------------------------
- core_feof - return 1 if we're at the end
- of file
--------------------------------------------------*/
+protected:
-int core_feof(core_file *file)
-{
- /* check for buffered chars */
- if (file->back_char_head != file->back_char_tail)
- return 0;
+ bool is_buffered() const { return (offset() >= m_bufferbase) && (offset() < (m_bufferbase + m_bufferbytes)); }
- /* if the offset == length, we're at EOF */
- return (file->offset >= file->length);
-}
+private:
+ static constexpr std::size_t FILE_BUFFER_SIZE = 512;
+ file_error osd_or_zlib_read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual);
+ file_error osd_or_zlib_write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual);
-/*-------------------------------------------------
- core_fsize - returns the size of a file
--------------------------------------------------*/
-
-UINT64 core_fsize(core_file *file)
-{
- return file->length;
-}
+ osd_file * m_file; // OSD file handle
+ zlib_data::ptr m_zdata; // compression data
+ std::uint64_t m_bufferbase; // base offset of internal buffer
+ std::uint32_t m_bufferbytes; // bytes currently loaded into buffer
+ std::uint8_t m_buffer[FILE_BUFFER_SIZE]; // buffer data
+};
/***************************************************************************
- FILE READ
+ INLINE FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
- core_fread - read from a file
+ is_directory_separator - is a given character
+ a directory separator? The following logic
+ works for most platforms
-------------------------------------------------*/
-UINT32 core_fread(core_file *file, void *buffer, UINT32 length)
+inline int is_directory_separator(char c)
{
- UINT32 bytes_read = 0;
-
- /* flush any buffered char */
- file->back_char_head = 0;
- file->back_char_tail = 0;
-
- /* handle real files */
- if (file->file && file->data == nullptr)
- {
- /* if we're within the buffer, consume that first */
- if (file->offset >= file->bufferbase && file->offset < file->bufferbase + file->bufferbytes)
- bytes_read += safe_buffer_copy(file->buffer, file->offset - file->bufferbase, file->bufferbytes, buffer, bytes_read, length);
-
- /* if we've got a small amount left, read it into the buffer first */
- if (bytes_read < length)
- {
- if (length - bytes_read < sizeof(file->buffer) / 2)
- {
- /* read as much as makes sense into the buffer */
- file->bufferbase = file->offset + bytes_read;
- file->bufferbytes = 0;
- osd_or_zlib_read(file, file->buffer, file->bufferbase, sizeof(file->buffer), &file->bufferbytes);
-
- /* do a bounded copy from the buffer to the destination */
- bytes_read += safe_buffer_copy(file->buffer, 0, file->bufferbytes, buffer, bytes_read, length);
- }
-
- /* read the remainder directly from the file */
- else
- {
- UINT32 new_bytes_read = 0;
- osd_or_zlib_read(file, (UINT8 *)buffer + bytes_read, file->offset + bytes_read, length - bytes_read, &new_bytes_read);
- bytes_read += new_bytes_read;
- }
- }
- }
+ return (c == '\\' || c == '/' || c == ':');
+}
- /* handle RAM-based files */
- else
- bytes_read += safe_buffer_copy(file->data, (UINT32)file->offset, file->length, buffer, bytes_read, length);
- /* return the number of bytes read */
- file->offset += bytes_read;
- return bytes_read;
-}
+/***************************************************************************
+ core_text_file
+***************************************************************************/
/*-------------------------------------------------
- core_fgetc - read a character from a file
+ getc - read a character from a file
-------------------------------------------------*/
-int core_fgetc(core_file *file)
+int core_text_file::getc()
{
int result;
- /* refresh buffer, if necessary */
- if (file->back_char_head == file->back_char_tail)
+ // refresh buffer, if necessary
+ if (m_back_char_head == m_back_char_tail)
{
- utf16_char utf16_buffer[UTF16_CHAR_MAX];
- char utf8_buffer[UTF8_CHAR_MAX];
- char default_buffer[16];
- unicode_char uchar = (unicode_char) ~0;
- int readlen, charlen;
-
- /* do we need to check the byte order marks? */
- if (file->offset == 0)
+ // do we need to check the byte order marks?
+ if (tell() == 0)
{
- UINT8 bom[4];
+ std::uint8_t bom[4];
int pos = 0;
- if (core_fread(file, bom, 4) == 4)
+ if (read(bom, 4) == 4)
{
if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf)
{
- file->text_type = TFT_UTF8;
+ m_text_type = text_file_type::UTF8;
pos = 3;
}
else if (bom[0] == 0x00 && bom[1] == 0x00 && bom[2] == 0xfe && bom[3] == 0xff)
{
- file->text_type = TFT_UTF32BE;
+ m_text_type = text_file_type::UTF32BE;
pos = 4;
}
else if (bom[0] == 0xff && bom[1] == 0xfe && bom[2] == 0x00 && bom[3] == 0x00)
{
- file->text_type = TFT_UTF32LE;
+ m_text_type = text_file_type::UTF32LE;
pos = 4;
}
else if (bom[0] == 0xfe && bom[1] == 0xff)
{
- file->text_type = TFT_UTF16BE;
+ m_text_type = text_file_type::UTF16BE;
pos = 2;
}
else if (bom[0] == 0xff && bom[1] == 0xfe)
{
- file->text_type = TFT_UTF16LE;
+ m_text_type = text_file_type::UTF16LE;
pos = 2;
}
else
{
- file->text_type = TFT_OSD;
+ m_text_type = text_file_type::OSD;
pos = 0;
}
}
- core_fseek(file, pos, SEEK_SET);
+ seek(pos, SEEK_SET);
}
- /* fetch the next character */
- switch (file->text_type)
+ // fetch the next character
+ utf16_char utf16_buffer[UTF16_CHAR_MAX];
+ unicode_char uchar = unicode_char(~0);
+ switch (m_text_type)
{
- default:
- case TFT_OSD:
- readlen = core_fread(file, default_buffer, sizeof(default_buffer));
+ default:
+ case text_file_type::OSD:
+ {
+ char default_buffer[16];
+ auto const readlen = read(default_buffer, sizeof(default_buffer));
if (readlen > 0)
{
- charlen = osd_uchar_from_osdchar(&uchar, default_buffer, readlen / sizeof(default_buffer[0]));
- core_fseek(file, (INT64) (charlen * sizeof(default_buffer[0])) - readlen, SEEK_CUR);
+ auto const charlen = osd_uchar_from_osdchar(&uchar, default_buffer, readlen / sizeof(default_buffer[0]));
+ seek(std::int64_t(charlen * sizeof(default_buffer[0])) - readlen, SEEK_CUR);
}
- break;
+ }
+ break;
- case TFT_UTF8:
- readlen = core_fread(file, utf8_buffer, sizeof(utf8_buffer));
+ case text_file_type::UTF8:
+ {
+ char utf8_buffer[UTF8_CHAR_MAX];
+ auto const readlen = read(utf8_buffer, sizeof(utf8_buffer));
if (readlen > 0)
{
- charlen = uchar_from_utf8(&uchar, utf8_buffer, readlen / sizeof(utf8_buffer[0]));
- core_fseek(file, (INT64) (charlen * sizeof(utf8_buffer[0])) - readlen, SEEK_CUR);
+ auto const charlen = uchar_from_utf8(&uchar, utf8_buffer, readlen / sizeof(utf8_buffer[0]));
+ seek(std::int64_t(charlen * sizeof(utf8_buffer[0])) - readlen, SEEK_CUR);
}
- break;
+ }
+ break;
- case TFT_UTF16BE:
- readlen = core_fread(file, utf16_buffer, sizeof(utf16_buffer));
+ case text_file_type::UTF16BE:
+ {
+ auto const readlen = read(utf16_buffer, sizeof(utf16_buffer));
if (readlen > 0)
{
- charlen = uchar_from_utf16be(&uchar, utf16_buffer, readlen / sizeof(utf16_buffer[0]));
- core_fseek(file, (INT64) (charlen * sizeof(utf16_buffer[0])) - readlen, SEEK_CUR);
+ auto const charlen = uchar_from_utf16be(&uchar, utf16_buffer, readlen / sizeof(utf16_buffer[0]));
+ seek(std::int64_t(charlen * sizeof(utf16_buffer[0])) - readlen, SEEK_CUR);
}
- break;
+ }
+ break;
- case TFT_UTF16LE:
- readlen = core_fread(file, utf16_buffer, sizeof(utf16_buffer));
+ case text_file_type::UTF16LE:
+ {
+ auto const readlen = read(utf16_buffer, sizeof(utf16_buffer));
if (readlen > 0)
{
- charlen = uchar_from_utf16le(&uchar, utf16_buffer, readlen / sizeof(utf16_buffer[0]));
- core_fseek(file, (INT64) (charlen * sizeof(utf16_buffer[0])) - readlen, SEEK_CUR);
+ auto const charlen = uchar_from_utf16le(&uchar, utf16_buffer, readlen / sizeof(utf16_buffer[0]));
+ seek(std::int64_t(charlen * sizeof(utf16_buffer[0])) - readlen, SEEK_CUR);
}
- break;
+ }
+ break;
- case TFT_UTF32BE:
- if (core_fread(file, &uchar, sizeof(uchar)) == sizeof(uchar))
- uchar = BIG_ENDIANIZE_INT32(uchar);
- break;
+ case text_file_type::UTF32BE:
+ if (read(&uchar, sizeof(uchar)) == sizeof(uchar))
+ uchar = BIG_ENDIANIZE_INT32(uchar);
+ break;
- case TFT_UTF32LE:
- if (core_fread(file, &uchar, sizeof(uchar)) == sizeof(uchar))
- uchar = LITTLE_ENDIANIZE_INT32(uchar);
- break;
+ case text_file_type::UTF32LE:
+ if (read(&uchar, sizeof(uchar)) == sizeof(uchar))
+ uchar = LITTLE_ENDIANIZE_INT32(uchar);
+ break;
}
if (uchar != ~0)
{
- /* place the new character in the ring buffer */
- file->back_char_head = 0;
- file->back_char_tail = utf8_from_uchar(file->back_chars, ARRAY_LENGTH(file->back_chars), uchar);
-/* assert(file->back_char_tail != -1);*/
+ // place the new character in the ring buffer
+ m_back_char_head = 0;
+ m_back_char_tail = utf8_from_uchar(m_back_chars, ARRAY_LENGTH(m_back_chars), uchar);
+ //assert(file->back_char_tail != -1);
}
}
- /* now read from the ring buffer */
- if (file->back_char_head != file->back_char_tail)
+ // now read from the ring buffer
+ if (m_back_char_head == m_back_char_tail)
+ result = EOF;
+ else
{
- result = file->back_chars[file->back_char_head++];
- file->back_char_head %= ARRAY_LENGTH(file->back_chars);
+ result = m_back_chars[m_back_char_head++];
+ m_back_char_head %= ARRAY_LENGTH(m_back_chars);
}
- else
- result = EOF;
return result;
}
/*-------------------------------------------------
- core_ungetc - put back a character read from
- a file
+ ungetc - put back a character read from a
+ file
-------------------------------------------------*/
-int core_ungetc(int c, core_file *file)
+int core_text_file::ungetc(int c)
{
- file->back_chars[file->back_char_tail++] = (char) c;
- file->back_char_tail %= ARRAY_LENGTH(file->back_chars);
+ m_back_chars[m_back_char_tail++] = char(c);
+ m_back_char_tail %= ARRAY_LENGTH(m_back_chars);
return c;
}
/*-------------------------------------------------
- core_fgets - read a line from a text file
+ gets - read a line from a text file
-------------------------------------------------*/
-char *core_fgets(char *s, int n, core_file *file)
+char *core_text_file::gets(char *s, int n)
{
char *cur = s;
- /* loop while we have characters */
+ // loop while we have characters
while (n > 0)
{
- int c = core_fgetc(file);
+ int const c = getc();
if (c == EOF)
break;
-
- /* if there's a CR, look for an LF afterwards */
- if (c == 0x0d)
+ else if (c == 0x0d) // if there's a CR, look for an LF afterwards
{
- int c2 = core_fgetc(file);
+ int const c2 = getc();
if (c2 != 0x0a)
- core_ungetc(c2, file);
+ ungetc(c2);
*cur++ = 0x0d;
n--;
break;
}
-
- /* if there's an LF, reinterp as a CR for consistency */
- else if (c == 0x0a)
+ else if (c == 0x0a) // if there's an LF, reinterp as a CR for consistency
{
*cur++ = 0x0d;
n--;
break;
}
-
- /* otherwise, pop the character in and continue */
- *cur++ = c;
- n--;
+ else // otherwise, pop the character in and continue
+ {
+ *cur++ = c;
+ n--;
+ }
}
- /* if we put nothing in, return NULL */
+ // if we put nothing in, return NULL
if (cur == s)
return nullptr;
@@ -648,335 +555,414 @@ char *core_fgets(char *s, int n, core_file *file)
/*-------------------------------------------------
- core_fbuffer - return a pointer to the file
- buffer; if it doesn't yet exist, load the
- file into RAM first
+ puts - write a line to a text file
-------------------------------------------------*/
-const void *core_fbuffer(core_file *file)
+int core_text_file::puts(char const *s)
{
- file_error filerr;
- UINT32 read_length;
-
- /* if we already have data, just return it */
- if (file->data != nullptr || !file->length)
- return file->data;
+ char convbuf[1024];
+ char *pconvbuf = convbuf;
+ int count = 0;
- /* allocate some memory */
- file->data = (UINT8 *)malloc(file->length);
- if (file->data == nullptr)
- return nullptr;
- file->data_allocated = TRUE;
+ // is this the beginning of the file? if so, write a byte order mark
+ if (tell() == 0 && !no_bom())
+ {
+ *pconvbuf++ = char(0xef);
+ *pconvbuf++ = char(0xbb);
+ *pconvbuf++ = char(0xbf);
+ }
- /* read the file */
- filerr = osd_or_zlib_read(file, file->data, 0, file->length, &read_length);
- if (filerr != FILERR_NONE || read_length != file->length)
+ // convert '\n' to platform dependant line endings
+ while (*s != '\0')
{
- free(file->data);
- file->data = nullptr;
- return nullptr;
+ if (*s == '\n')
+ {
+ if (CRLF == 1) // CR only
+ *pconvbuf++ = 13;
+ else if (CRLF == 2) // LF only
+ *pconvbuf++ = 10;
+ else if (CRLF == 3) // CR+LF
+ {
+ *pconvbuf++ = 13;
+ *pconvbuf++ = 10;
+ }
+ }
+ else
+ *pconvbuf++ = *s;
+ s++;
+
+ // if we overflow, break into chunks
+ if (pconvbuf >= convbuf + ARRAY_LENGTH(convbuf) - 10)
+ {
+ count += write(convbuf, pconvbuf - convbuf);
+ pconvbuf = convbuf;
+ }
}
- /* close the file because we don't need it anymore */
- osd_close(file->file);
- file->file = nullptr;
- return file->data;
+ // final flush
+ if (pconvbuf != convbuf)
+ count += write(convbuf, pconvbuf - convbuf);
+
+ return count;
}
/*-------------------------------------------------
- core_fload - open a file with the specified
- filename, read it into memory, and return a
- pointer
+ vprintf - vfprintf to a text file
-------------------------------------------------*/
-file_error core_fload(const char *filename, void **data, UINT32 *length)
+int core_text_file::vprintf(util::format_argument_pack<std::ostream> const &args)
{
- core_file *file = nullptr;
- file_error err;
- UINT64 size;
+ m_printf_buffer.reserve(1024);
+ m_printf_buffer.seekp(0, ovectorstream::beg);
+ util::stream_format<std::ostream, std::ostream>(m_printf_buffer, args);
+ m_printf_buffer.put('\0');
+ return puts(&m_printf_buffer.vec()[0]);
+}
- /* attempt to open the file */
- err = core_fopen(filename, OPEN_FLAG_READ, &file);
- if (err != FILERR_NONE)
- return err;
- /* get the size */
- size = core_fsize(file);
- if ((UINT32)size != size)
- {
- core_fclose(file);
- return FILERR_OUT_OF_MEMORY;
- }
- /* allocate memory */
- *data = osd_malloc(size);
- if (length != nullptr)
- *length = (UINT32)size;
+/***************************************************************************
+ core_in_memory_file
+***************************************************************************/
+
+/*-------------------------------------------------
+ seek - seek within a file
+-------------------------------------------------*/
+
+int core_in_memory_file::seek(std::int64_t offset, int whence)
+{
+ // flush any buffered char
+ clear_putback();
- /* read the data */
- if (core_fread(file, *data, size) != size)
+ // switch off the relative location
+ switch (whence)
{
- core_fclose(file);
- free(*data);
- return FILERR_FAILURE;
+ case SEEK_SET:
+ m_offset = offset;
+ break;
+
+ case SEEK_CUR:
+ m_offset += offset;
+ break;
+
+ case SEEK_END:
+ m_offset = m_length + offset;
+ break;
}
+ return 0;
+}
- /* close the file and return data */
- core_fclose(file);
- return FILERR_NONE;
+
+/*-------------------------------------------------
+ eof - return 1 if we're at the end of file
+-------------------------------------------------*/
+
+bool core_in_memory_file::eof() const
+{
+ // check for buffered chars
+ if (has_putback())
+ return 0;
+
+ // if the offset == length, we're at EOF
+ return (m_offset >= m_length);
}
-file_error core_fload(const char *filename, dynamic_buffer &data)
+
+/*-------------------------------------------------
+ read - read from a file
+-------------------------------------------------*/
+
+std::uint32_t core_in_memory_file::read(void *buffer, std::uint32_t length)
{
- core_file *file = nullptr;
- file_error err;
- UINT64 size;
+ clear_putback();
- /* attempt to open the file */
- err = core_fopen(filename, OPEN_FLAG_READ, &file);
- if (err != FILERR_NONE)
- return err;
+ // handle RAM-based files
+ auto const bytes_read = safe_buffer_copy(m_data, std::size_t(m_offset), std::size_t(m_length), buffer, 0, length);
+ m_offset += bytes_read;
+ return bytes_read;
+}
- /* get the size */
- size = core_fsize(file);
- if ((UINT32)size != size)
- {
- core_fclose(file);
- return FILERR_OUT_OF_MEMORY;
- }
- /* allocate memory */
- data.resize(size);
+/*-------------------------------------------------
+ truncate - truncate a file
+-------------------------------------------------*/
- /* read the data */
- if (core_fread(file, &data[0], size) != size)
- {
- core_fclose(file);
- data.clear();
+file_error core_in_memory_file::truncate(std::uint64_t offset)
+{
+ if (m_length < offset)
return FILERR_FAILURE;
- }
- /* close the file and return data */
- core_fclose(file);
+ // adjust to new length and offset
+ set_length(offset);
return FILERR_NONE;
}
-
-/***************************************************************************
- FILE WRITE
-***************************************************************************/
-
/*-------------------------------------------------
- core_fwrite - write to a file
+ safe_buffer_copy - copy safely from one
+ bounded buffer to another
-------------------------------------------------*/
-UINT32 core_fwrite(core_file *file, const void *buffer, UINT32 length)
+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)
{
- UINT32 bytes_written = 0;
+ 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;
+}
- /* can't write to RAM-based stuff */
- if (file->data != nullptr)
- return 0;
- /* flush any buffered char */
- file->back_char_head = 0;
- file->back_char_tail = 0;
- /* invalidate any buffered data */
- file->bufferbytes = 0;
+/***************************************************************************
+ core_osd_file
+***************************************************************************/
- /* do the write */
- osd_or_zlib_write(file, buffer, file->offset, length, &bytes_written);
+/*-------------------------------------------------
+ closes a file
+-------------------------------------------------*/
- /* return the number of bytes read */
- file->offset += bytes_written;
- file->length = MAX(file->length, file->offset);
- return bytes_written;
+core_osd_file::~core_osd_file()
+{
+ // close files and free memory
+ if (m_zdata)
+ compress(FCOMPRESS_NONE);
+ if (m_file)
+ osd_close(m_file);
}
/*-------------------------------------------------
- core_fputs - write a line to a text file
+ compress - enable/disable streaming file
+ compression via zlib; level is 0 to disable
+ compression, or up to 9 for max compression
-------------------------------------------------*/
-int core_fputs(core_file *f, const char *s)
+file_error core_osd_file::compress(int level)
{
- char convbuf[1024];
- char *pconvbuf = convbuf;
- int count = 0;
+ file_error result = FILERR_NONE;
- /* is this the beginning of the file? if so, write a byte order mark */
- if (f->offset == 0 && !(f->openflags & OPEN_FLAG_NO_BOM))
- {
- *pconvbuf++ = (char)0xef;
- *pconvbuf++ = (char)0xbb;
- *pconvbuf++ = (char)0xbf;
- }
+ // can only do this for read-only and write-only cases
+ if (read_access() && write_access())
+ return FILERR_INVALID_ACCESS;
- /* convert '\n' to platform dependant line endings */
- while (*s != 0)
+ // if we have been compressing, flush and free the data
+ if (m_zdata && (level == FCOMPRESS_NONE))
{
- if (*s == '\n')
+ int zerr = Z_OK;
+
+ // flush any remaining data if we are writing
+ while (write_access() && (zerr != Z_STREAM_END))
{
- if (CRLF == 1) /* CR only */
- *pconvbuf++ = 13;
- else if (CRLF == 2) /* LF only */
- *pconvbuf++ = 10;
- else if (CRLF == 3) /* CR+LF */
+ // deflate some more
+ zerr = m_zdata->finalise();
+ if ((zerr != Z_STREAM_END) && (zerr != Z_OK))
{
- *pconvbuf++ = 13;
- *pconvbuf++ = 10;
+ result = FILERR_INVALID_DATA;
+ break;
}
- }
- else
- *pconvbuf++ = *s;
- s++;
- /* if we overflow, break into chunks */
- if (pconvbuf >= convbuf + ARRAY_LENGTH(convbuf) - 10)
- {
- count += core_fwrite(f, convbuf, pconvbuf - convbuf);
- pconvbuf = convbuf;
+ // write the data
+ if (m_zdata->has_output())
+ {
+ std::uint32_t actualdata;
+ auto const filerr = osd_write(m_file, m_zdata->buffer_data(), m_zdata->realoffset(), m_zdata->output_size(), &actualdata);
+ if (filerr != FILERR_NONE)
+ break;
+ m_zdata->add_realoffset(actualdata);
+ m_zdata->reset_output();
+ }
}
+
+ // free memory
+ m_zdata.reset();
}
- /* final flush */
- if (pconvbuf != convbuf)
- count += core_fwrite(f, convbuf, pconvbuf - convbuf);
+ // if we are just starting to compress, allocate a new buffer
+ if (!m_zdata && (level > FCOMPRESS_NONE))
+ {
+ int zerr;
- return count;
-}
+ // initialize the stream and compressor
+ if (write_access())
+ zerr = zlib_data::start_compression(level, offset(), m_zdata);
+ else
+ zerr = zlib_data::start_decompression(offset(), m_zdata);
+ // on error, return an error
+ if (zerr != Z_OK)
+ return FILERR_OUT_OF_MEMORY;
-/*-------------------------------------------------
- core_vfprintf - vfprintf to a text file
--------------------------------------------------*/
+ // flush buffers
+ m_bufferbytes = 0;
+ }
-int core_vfprintf(core_file *f, const char *fmt, va_list va)
-{
- char buf[1024];
- vsnprintf(buf, sizeof(buf), fmt, va);
- return core_fputs(f, buf);
+ return result;
}
/*-------------------------------------------------
- core_fprintf - vfprintf to a text file
+ seek - seek within a file
-------------------------------------------------*/
-int CLIB_DECL core_fprintf(core_file *f, const char *fmt, ...)
+int core_osd_file::seek(std::int64_t offset, int whence)
{
- int rc;
- va_list va;
- va_start(va, fmt);
- rc = core_vfprintf(f, fmt, va);
- va_end(va);
- return rc;
+ // error if compressing
+ if (m_zdata)
+ return 1;
+ else
+ return core_in_memory_file::seek(offset, whence);
}
/*-------------------------------------------------
- core_truncate - truncate a file
+ read - read from a file
-------------------------------------------------*/
-file_error core_truncate(core_file *f, UINT64 offset)
+std::uint32_t core_osd_file::read(void *buffer, std::uint32_t length)
{
- file_error err;
+ if (!m_file || is_loaded())
+ return core_in_memory_file::read(buffer, length);
- /* truncate file */
- err = osd_truncate(f->file, offset);
- if (err != FILERR_NONE)
- return err;
+ // flush any buffered char
+ clear_putback();
- /* and adjust to new length and offset */
- f->length = offset;
- f->offset = MIN(f->offset, f->length);
+ std::uint32_t bytes_read = 0;
- return FILERR_NONE;
+ // if we're within the buffer, consume that first
+ if (is_buffered())
+ bytes_read += safe_buffer_copy(m_buffer, offset() - m_bufferbase, m_bufferbytes, buffer, bytes_read, length);
+
+ // if we've got a small amount left, read it into the buffer first
+ if (bytes_read < length)
+ {
+ if ((length - bytes_read) < (sizeof(m_buffer) / 2))
+ {
+ // read as much as makes sense into the buffer
+ m_bufferbase = offset() + bytes_read;
+ m_bufferbytes = 0;
+ osd_or_zlib_read(m_buffer, m_bufferbase, sizeof(m_buffer), m_bufferbytes);
+
+ // do a bounded copy from the buffer to the destination
+ bytes_read += safe_buffer_copy(m_buffer, 0, m_bufferbytes, buffer, bytes_read, length);
+ }
+ else
+ {
+ // read the remainder directly from the file
+ std::uint32_t new_bytes_read = 0;
+ osd_or_zlib_read(reinterpret_cast<std::uint8_t *>(buffer) + bytes_read, offset() + bytes_read, length - bytes_read, new_bytes_read);
+ bytes_read += new_bytes_read;
+ }
+ }
+
+ // return the number of bytes read
+ add_offset(bytes_read);
+ return bytes_read;
}
/*-------------------------------------------------
- core_truncate - flush write buffer
+ buffer - return a pointer to the file buffer;
+ if it doesn't yet exist, load the file into
+ RAM first
-------------------------------------------------*/
-file_error core_fflush(core_file *f)
+void const *core_osd_file::buffer()
{
- return osd_fflush(f->file);
+ // if we already have data, just return it
+ if (!is_loaded() && length())
+ {
+ // allocate some memory
+ void *buf = allocate();
+ if (!buf) return nullptr;
+
+ // read the file
+ std::uint32_t read_length = 0;
+ auto const filerr = osd_or_zlib_read(buf, 0, length(), read_length);
+ if ((filerr != FILERR_NONE) || (read_length != length()))
+ purge();
+ else
+ {
+ // close the file because we don't need it anymore
+ osd_close(m_file);
+ m_file = nullptr;
+ }
+ }
+ return core_in_memory_file::buffer();
}
-
-/***************************************************************************
- FILENAME UTILITIES
-***************************************************************************/
-
/*-------------------------------------------------
- core_filename_extract_base - extract the base
- name from a filename; note that this makes
- assumptions about path separators
+ write - write to a file
-------------------------------------------------*/
-std::string core_filename_extract_base(const char *name, bool strip_extension)
+std::uint32_t core_osd_file::write(void const *buffer, std::uint32_t length)
{
- /* find the start of the name */
- const char *start = name + strlen(name);
- while (start > name && !is_directory_separator(start[-1]))
- start--;
+ // can't write to RAM-based stuff
+ if (is_loaded())
+ return core_in_memory_file::write(buffer, length);
- /* copy the rest into an astring */
- std::string result(start);
+ // flush any buffered char
+ clear_putback();
- /* chop the extension if present */
- if (strip_extension)
- result = result.substr(0, result.find_last_of('.'));
- return result;
+ // invalidate any buffered data
+ m_bufferbytes = 0;
+
+ // do the write
+ std::uint32_t bytes_written = 0;
+ osd_or_zlib_write(buffer, offset(), length, bytes_written);
+
+ // return the number of bytes written
+ add_offset(bytes_written);
+ return bytes_written;
}
/*-------------------------------------------------
- core_filename_ends_with - does the given
- filename end with the specified extension?
+ truncate - truncate a file
-------------------------------------------------*/
-int core_filename_ends_with(const char *filename, const char *extension)
+file_error core_osd_file::truncate(std::uint64_t offset)
{
- int namelen = strlen(filename);
- int extlen = strlen(extension);
- int matches = TRUE;
+ if (is_loaded())
+ return core_in_memory_file::truncate(offset);
- /* work backwards checking for a match */
- while (extlen > 0)
- if (tolower((UINT8)filename[--namelen]) != tolower((UINT8)extension[--extlen]))
- {
- matches = FALSE;
- break;
- }
+ // truncate file
+ auto const err = osd_truncate(m_file, offset);
+ if (err != FILERR_NONE)
+ return err;
- return matches;
+ // and adjust to new length and offset
+ set_length(offset);
+ return FILERR_NONE;
}
-
-/***************************************************************************
- MISC HELPERS
-***************************************************************************/
-
/*-------------------------------------------------
- safe_buffer_copy - copy safely from one
- bounded buffer to another
+ flush - flush file buffers
-------------------------------------------------*/
-static UINT32 safe_buffer_copy(const void *source, UINT32 sourceoffs, UINT32 sourcelen, void *dest, UINT32 destoffs, UINT32 destlen)
+file_error core_osd_file::flush()
{
- UINT32 sourceavail = sourcelen - sourceoffs;
- UINT32 destavail = destlen - destoffs;
- UINT32 bytes_to_copy = MIN(sourceavail, destavail);
- if (bytes_to_copy > 0)
- memcpy((UINT8 *)dest + destoffs, (const UINT8 *)source + sourceoffs, bytes_to_copy);
- return bytes_to_copy;
+ if (is_loaded())
+ return core_in_memory_file::flush();
+
+ // flush any buffered char
+ clear_putback();
+
+ // invalidate any buffered data
+ m_bufferbytes = 0;
+
+ return osd_fflush(m_file);
}
@@ -985,51 +971,48 @@ static UINT32 safe_buffer_copy(const void *source, UINT32 sourceoffs, UINT32 sou
handles zlib-compressed data
-------------------------------------------------*/
-static file_error osd_or_zlib_read(core_file *file, void *buffer, UINT64 offset, UINT32 length, UINT32 *actual)
+file_error core_osd_file::osd_or_zlib_read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual)
{
- /* if no compression, just pass through */
- if (file->zdata == nullptr)
- return osd_read(file->file, buffer, offset, length, actual);
+ // if no compression, just pass through
+ if (!m_zdata)
+ return osd_read(m_file, buffer, offset, length, &actual);
- /* if the offset doesn't match the next offset, fail */
- if (offset != file->zdata->nextoffset)
+ // if the offset doesn't match the next offset, fail
+ if (!m_zdata->is_nextoffset(offset))
return FILERR_INVALID_ACCESS;
- /* set up the destination */
- file->zdata->stream.next_out = (Bytef *)buffer;
- file->zdata->stream.avail_out = length;
- while (file->zdata->stream.avail_out != 0)
+ // set up the destination
+ file_error filerr = FILERR_NONE;
+ m_zdata->set_output(buffer, length);
+ while (!m_zdata->output_full())
{
- file_error filerr;
- UINT32 actualdata;
- int zerr = Z_OK;
-
- /* if we didn't make progress, report an error or the end */
- if (file->zdata->stream.avail_in != 0)
- zerr = inflate(&file->zdata->stream, Z_SYNC_FLUSH);
- if (zerr != Z_OK)
+ // if we didn't make progress, report an error or the end
+ if (m_zdata->has_input())
{
- *actual = length - file->zdata->stream.avail_out;
- file->zdata->nextoffset += *actual;
- return (zerr == Z_STREAM_END) ? FILERR_NONE : FILERR_INVALID_DATA;
+ auto const zerr = m_zdata->decompress();
+ if (Z_OK != zerr)
+ {
+ if (Z_STREAM_END != zerr) filerr = FILERR_INVALID_DATA;
+ break;
+ }
}
- /* fetch more data if needed */
- if (file->zdata->stream.avail_in == 0)
+ // fetch more data if needed
+ if (!m_zdata->has_input())
{
- filerr = osd_read(file->file, file->zdata->buffer, file->zdata->realoffset, sizeof(file->zdata->buffer), &actualdata);
- if (filerr != FILERR_NONE)
- return filerr;
- file->zdata->realoffset += actualdata;
- file->zdata->stream.next_in = file->zdata->buffer;
- file->zdata->stream.avail_in = sizeof(file->zdata->buffer);
+ std::uint32_t actualdata = 0;
+ filerr = osd_read(m_file, m_zdata->buffer_data(), m_zdata->realoffset(), m_zdata->buffer_size(), &actualdata);
+ if (filerr != FILERR_NONE) break;
+ m_zdata->add_realoffset(actualdata);
+ m_zdata->reset_input(actualdata);
+ if (!m_zdata->has_input()) break;
}
}
- /* we read everything */
- *actual = length;
- file->zdata->nextoffset += *actual;
- return FILERR_NONE;
+ // adjust everything
+ actual = length - m_zdata->output_space();
+ m_zdata->add_nextoffset(actual);
+ return filerr;
}
@@ -1039,61 +1022,294 @@ static file_error osd_or_zlib_read(core_file *file, void *buffer, UINT64 offset,
-------------------------------------------------*/
/**
- * @fn static file_error osd_or_zlib_write(core_file *file, const void *buffer, UINT64 offset, UINT32 length, UINT32 *actual)
+ * @fn file_error osd_or_zlib_write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t actual)
*
* @brief OSD or zlib write.
*
- * @param [in,out] file If non-null, the file.
* @param buffer The buffer.
* @param offset The offset.
* @param length The length.
- * @param [in,out] actual If non-null, the actual.
+ * @param [in,out] actual The actual.
*
* @return A file_error.
*/
-static file_error osd_or_zlib_write(core_file *file, const void *buffer, UINT64 offset, UINT32 length, UINT32 *actual)
+file_error core_osd_file::osd_or_zlib_write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual)
{
- /* if no compression, just pass through */
- if (file->zdata == nullptr)
- return osd_write(file->file, buffer, offset, length, actual);
+ // if no compression, just pass through
+ if (!m_zdata)
+ return osd_write(m_file, buffer, offset, length, &actual);
- /* if the offset doesn't match the next offset, fail */
- if (offset != file->zdata->nextoffset)
+ // if the offset doesn't match the next offset, fail
+ if (!m_zdata->is_nextoffset(offset))
return FILERR_INVALID_ACCESS;
- /* set up the source */
- file->zdata->stream.next_in = (Bytef *)buffer;
- file->zdata->stream.avail_in = length;
- while (file->zdata->stream.avail_in != 0)
+ // set up the source
+ m_zdata->set_input(buffer, length);
+ while (m_zdata->has_input())
{
- file_error filerr;
- UINT32 actualdata;
- int zerr;
-
- /* if we didn't make progress, report an error or the end */
- zerr = deflate(&file->zdata->stream, Z_NO_FLUSH);
+ // if we didn't make progress, report an error or the end
+ auto const zerr = m_zdata->compress();
if (zerr != Z_OK)
{
- *actual = length - file->zdata->stream.avail_in;
- file->zdata->nextoffset += *actual;
+ actual = length - m_zdata->input_size();
+ m_zdata->add_nextoffset(actual);
return FILERR_INVALID_DATA;
}
- /* write more data if we are full up */
- if (file->zdata->stream.avail_out == 0)
+ // write more data if we are full up
+ if (m_zdata->output_full())
{
- filerr = osd_write(file->file, file->zdata->buffer, file->zdata->realoffset, sizeof(file->zdata->buffer), &actualdata);
+ std::uint32_t actualdata = 0;
+ auto const filerr = osd_write(m_file, m_zdata->buffer_data(), m_zdata->realoffset(), m_zdata->output_size(), &actualdata);
if (filerr != FILERR_NONE)
return filerr;
- file->zdata->realoffset += actualdata;
- file->zdata->stream.next_out = file->zdata->buffer;
- file->zdata->stream.avail_out = sizeof(file->zdata->buffer);
+ m_zdata->add_realoffset(actualdata);
+ m_zdata->reset_output();
}
}
- /* we read everything */
- *actual = length;
- file->zdata->nextoffset += *actual;
+ // we wrote everything
+ actual = length;
+ m_zdata->add_nextoffset(actual);
return FILERR_NONE;
}
+
+} // anonymous namespace
+
+
+
+/***************************************************************************
+ core_file
+***************************************************************************/
+
+/*-------------------------------------------------
+ open - open a file for access and
+ return an error code
+-------------------------------------------------*/
+
+file_error core_file::open(char const *filename, std::uint32_t openflags, ptr &file)
+{
+ // attempt to open the file
+ osd_file *f = nullptr;
+ std::uint64_t length = 0;
+ auto const filerr = osd_open(filename, openflags, &f, &length);
+ if (filerr != FILERR_NONE)
+ return filerr;
+
+ try
+ {
+ file = std::make_unique<core_osd_file>(openflags, f, length);
+ return FILERR_NONE;
+ }
+ catch (...)
+ {
+ osd_close(f);
+ return FILERR_OUT_OF_MEMORY;
+ }
+}
+
+
+/*-------------------------------------------------
+ open_ram - open a RAM-based buffer for file-
+ like access and return an error code
+-------------------------------------------------*/
+
+file_error core_file::open_ram(void const *data, std::size_t length, std::uint32_t openflags, ptr &file)
+{
+ // can only do this for read access
+ if ((openflags & OPEN_FLAG_WRITE) || (openflags & OPEN_FLAG_CREATE))
+ return FILERR_INVALID_ACCESS;
+
+ try
+ {
+ file.reset(new core_in_memory_file(openflags, data, length, false));
+ return FILERR_NONE;
+ }
+ catch (...)
+ {
+ return FILERR_OUT_OF_MEMORY;
+ }
+}
+
+
+/*-------------------------------------------------
+ open_ram_copy - open a copy of a RAM-based
+ buffer for file-like access and return an
+ error code
+-------------------------------------------------*/
+
+file_error core_file::open_ram_copy(void const *data, std::size_t length, std::uint32_t openflags, ptr &file)
+{
+ // can only do this for read access
+ if ((openflags & OPEN_FLAG_WRITE) || (openflags & OPEN_FLAG_CREATE))
+ return FILERR_INVALID_ACCESS;
+
+ try
+ {
+ ptr result(new core_in_memory_file(openflags, data, length, true));
+ if (!result->buffer())
+ return FILERR_OUT_OF_MEMORY;
+
+ file = std::move(result);
+ return FILERR_NONE;
+ }
+ catch (...)
+ {
+ return FILERR_OUT_OF_MEMORY;
+ }
+}
+
+
+/*-------------------------------------------------
+ open_proxy - open a proxy to an existing file
+ object and return an error code
+-------------------------------------------------*/
+
+file_error core_file::open_proxy(core_file &file, ptr &proxy)
+{
+ try
+ {
+ proxy = std::make_unique<core_proxy_file>(file);
+ return FILERR_NONE;
+ }
+ catch (...)
+ {
+ return FILERR_OUT_OF_MEMORY;
+ }
+}
+
+
+/*-------------------------------------------------
+ closes a file
+-------------------------------------------------*/
+
+core_file::~core_file()
+{
+}
+
+
+/*-------------------------------------------------
+ load - open a file with the specified
+ filename, read it into memory, and return a
+ pointer
+-------------------------------------------------*/
+
+file_error core_file::load(char const *filename, void **data, std::uint32_t &length)
+{
+ ptr file;
+
+ // attempt to open the file
+ auto const err = open(filename, OPEN_FLAG_READ, file);
+ if (err != FILERR_NONE)
+ return err;
+
+ // get the size
+ auto const size = file->size();
+ if (std::uint32_t(size) != size)
+ return FILERR_OUT_OF_MEMORY;
+
+ // allocate memory
+ *data = osd_malloc(size);
+ length = std::uint32_t(size);
+
+ // read the data
+ if (file->read(*data, size) != size)
+ {
+ free(*data);
+ return FILERR_FAILURE;
+ }
+
+ // close the file and return data
+ return FILERR_NONE;
+}
+
+file_error core_file::load(char const *filename, dynamic_buffer &data)
+{
+ ptr file;
+
+ // attempt to open the file
+ auto const err = open(filename, OPEN_FLAG_READ, file);
+ if (err != FILERR_NONE)
+ return err;
+
+ // get the size
+ auto const size = file->size();
+ if (std::uint32_t(size) != size)
+ return FILERR_OUT_OF_MEMORY;
+
+ // allocate memory
+ data.resize(size);
+
+ // read the data
+ if (file->read(&data[0], size) != size)
+ {
+ data.clear();
+ return FILERR_FAILURE;
+ }
+
+ // close the file and return data
+ return FILERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ protected constructor
+-------------------------------------------------*/
+
+core_file::core_file()
+{
+}
+
+} // namespace util
+
+
+
+/***************************************************************************
+ FILENAME UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ core_filename_extract_base - extract the base
+ name from a filename; note that this makes
+ assumptions about path separators
+-------------------------------------------------*/
+
+std::string core_filename_extract_base(const char *name, bool strip_extension)
+{
+ /* find the start of the name */
+ const char *start = name + strlen(name);
+ while (start > name && !util::is_directory_separator(start[-1]))
+ start--;
+
+ /* copy the rest into an astring */
+ std::string result(start);
+
+ /* chop the extension if present */
+ if (strip_extension)
+ result = result.substr(0, result.find_last_of('.'));
+ return result;
+}
+
+
+/*-------------------------------------------------
+ core_filename_ends_with - does the given
+ filename end with the specified extension?
+-------------------------------------------------*/
+
+int core_filename_ends_with(const char *filename, const char *extension)
+{
+ int namelen = strlen(filename);
+ int extlen = strlen(extension);
+ int matches = TRUE;
+
+ /* work backwards checking for a match */
+ while (extlen > 0)
+ if (tolower((UINT8)filename[--namelen]) != tolower((UINT8)extension[--extlen]))
+ {
+ matches = FALSE;
+ break;
+ }
+
+ return matches;
+}
diff --git a/src/lib/util/corefile.h b/src/lib/util/corefile.h
index 36060631f35..7ec76af7cb5 100644
--- a/src/lib/util/corefile.h
+++ b/src/lib/util/corefile.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
corefile.h
@@ -13,12 +13,16 @@
#ifndef __COREFILE_H__
#define __COREFILE_H__
-#include <stdarg.h>
#include "corestr.h"
-#include <string>
#include "coretmpl.h"
+#include "strformat.h"
+
+#include <cstdint>
+#include <memory>
+#include <string>
+namespace util {
/***************************************************************************
ADDITIONAL OPEN FLAGS
@@ -32,98 +36,107 @@
#define FCOMPRESS_MAX 9 /* maximum compression */
-
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
-struct core_file;
-
-
+class core_file
+{
+public:
+ typedef std::unique_ptr<core_file> ptr;
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
+ // ----- file open/close -----
-/* ----- file open/close ----- */
+ // open a file with the specified filename
+ static file_error open(const char *filename, std::uint32_t openflags, ptr &file);
-/* open a file with the specified filename */
-file_error core_fopen(const char *filename, UINT32 openflags, core_file **file);
+ // open a RAM-based "file" using the given data and length (read-only)
+ static file_error open_ram(const void *data, std::size_t length, std::uint32_t openflags, ptr &file);
-/* open a RAM-based "file" using the given data and length (read-only) */
-file_error core_fopen_ram(const void *data, size_t length, UINT32 openflags, core_file **file);
+ // open a RAM-based "file" using the given data and length (read-only), copying the data
+ static file_error open_ram_copy(const void *data, std::size_t length, std::uint32_t openflags, ptr &file);
-/* open a RAM-based "file" using the given data and length (read-only), copying the data */
-file_error core_fopen_ram_copy(const void *data, size_t length, UINT32 openflags, core_file **file);
+ // open a proxy "file" that forwards requests to another file object
+ static file_error open_proxy(core_file &file, ptr &proxy);
-/* close an open file */
-void core_fclose(core_file *file);
+ // close an open file
+ virtual ~core_file();
-/* enable/disable streaming file compression via zlib; level is 0 to disable compression, or up to 9 for max compression */
-file_error core_fcompress(core_file *file, int level);
+ // enable/disable streaming file compression via zlib; level is 0 to disable compression, or up to 9 for max compression
+ virtual file_error compress(int level) = 0;
+ // ----- file positioning -----
-/* ----- file positioning ----- */
+ // adjust the file pointer within the file
+ virtual int seek(std::int64_t offset, int whence) = 0;
-/* adjust the file pointer within the file */
-int core_fseek(core_file *file, INT64 offset, int whence);
+ // return the current file pointer
+ virtual std::uint64_t tell() const = 0;
-/* return the current file pointer */
-UINT64 core_ftell(core_file *file);
+ // return true if we are at the EOF
+ virtual bool eof() const = 0;
-/* return true if we are at the EOF */
-int core_feof(core_file *file);
+ // return the total size of the file
+ virtual std::uint64_t size() const = 0;
-/* return the total size of the file */
-UINT64 core_fsize(core_file *file);
+ // ----- file read -----
+ // standard binary read from a file
+ virtual std::uint32_t read(void *buffer, std::uint32_t length) = 0;
-/* ----- file read ----- */
+ // read one character from the file
+ virtual int getc() = 0;
-/* standard binary read from a file */
-UINT32 core_fread(core_file *file, void *buffer, UINT32 length);
+ // put back one character from the file
+ virtual int ungetc(int c) = 0;
-/* read one character from the file */
-int core_fgetc(core_file *file);
+ // read a full line of text from the file
+ virtual char *gets(char *s, int n) = 0;
-/* put back one character from the file */
-int core_ungetc(int c, core_file *file);
+ // get a pointer to a buffer that holds the full file data in RAM
+ // this function may cause the full file data to be read
+ virtual const void *buffer() = 0;
-/* read a full line of text from the file */
-char *core_fgets(char *s, int n, core_file *file);
+ // open a file with the specified filename, read it into memory, and return a pointer
+ static file_error load(const char *filename, void **data, std::uint32_t &length);
+ static file_error load(const char *filename, dynamic_buffer &data);
-/* get a pointer to a buffer that holds the full file data in RAM */
-/* this function may cause the full file data to be read */
-const void *core_fbuffer(core_file *file);
-/* open a file with the specified filename, read it into memory, and return a pointer */
-file_error core_fload(const char *filename, void **data, UINT32 *length);
-file_error core_fload(const char *filename, dynamic_buffer &data);
+ // ----- file write -----
+ // standard binary write to a file
+ virtual std::uint32_t write(const void *buffer, std::uint32_t length) = 0;
+ // write a line of text to the file
+ virtual int puts(const char *s) = 0;
-/* ----- file write ----- */
+ // printf-style text write to a file
+ virtual int vprintf(util::format_argument_pack<std::ostream> const &args) = 0;
+ template <typename Format, typename... Params> int printf(Format &&fmt, Params &&...args)
+ {
+ return vprintf(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
+ }
-/* standard binary write to a file */
-UINT32 core_fwrite(core_file *file, const void *buffer, UINT32 length);
+ // file truncation
+ virtual file_error truncate(std::uint64_t offset) = 0;
-/* write a line of text to the file */
-int core_fputs(core_file *f, const char *s);
+ // flush file buffers
+ virtual file_error flush() = 0;
-/* printf-style text write to a file */
-int core_vfprintf(core_file *f, const char *fmt, va_list va);
-int CLIB_DECL core_fprintf(core_file *f, const char *fmt, ...) ATTR_PRINTF(2,3);
-/* file truncation */
-file_error core_truncate(core_file *f, UINT64 offset);
+protected:
+ core_file();
+};
-/* flush file buffers */
-file_error core_fflush(core_file *f);
+} // namespace util
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
/* ----- filename utilities ----- */
diff --git a/src/lib/util/flac.cpp b/src/lib/util/flac.cpp
index f70ae709978..c66cc281931 100644
--- a/src/lib/util/flac.cpp
+++ b/src/lib/util/flac.cpp
@@ -35,7 +35,7 @@ flac_encoder::flac_encoder(void *buffer, UINT32 buflength)
}
-flac_encoder::flac_encoder(core_file &file)
+flac_encoder::flac_encoder(util::core_file &file)
{
init_common();
reset(file);
@@ -100,7 +100,7 @@ bool flac_encoder::reset(void *buffer, UINT32 buflength)
// reset - reset state with new file parameters
//-------------------------------------------------
-bool flac_encoder::reset(core_file &file)
+bool flac_encoder::reset(util::core_file &file)
{
// configure the output
m_compressed_start = nullptr;
@@ -185,7 +185,7 @@ UINT32 flac_encoder::finish()
{
// process the data and return the amount written
FLAC__stream_encoder_finish(m_encoder);
- return (m_file != nullptr) ? core_ftell(m_file) : m_compressed_offset;
+ return (m_file != nullptr) ? m_file->tell() : m_compressed_offset;
}
@@ -252,7 +252,7 @@ FLAC__StreamEncoderWriteStatus flac_encoder::write_callback(const FLAC__byte buf
{
int count = bytes - offset;
if (m_file != nullptr)
- core_fwrite(m_file, buffer, count);
+ m_file->write(buffer, count);
else
{
if (m_compressed_offset + count <= m_compressed_length)
@@ -308,7 +308,7 @@ flac_decoder::flac_decoder(const void *buffer, UINT32 length, const void *buffer
// flac_decoder - constructor
//-------------------------------------------------
-flac_decoder::flac_decoder(core_file &file)
+flac_decoder::flac_decoder(util::core_file &file)
: m_decoder(FLAC__stream_decoder_new()),
m_file(&file),
m_compressed_offset(0),
@@ -414,7 +414,7 @@ bool flac_decoder::reset(UINT32 sample_rate, UINT8 num_channels, UINT32 block_si
// reset - reset state with new file parameter
//-------------------------------------------------
-bool flac_decoder::reset(core_file &file)
+bool flac_decoder::reset(util::core_file &file)
{
m_file = &file;
m_compressed_start = nullptr;
@@ -511,7 +511,7 @@ FLAC__StreamDecoderReadStatus flac_decoder::read_callback(FLAC__byte buffer[], s
// if a file, just read
if (m_file != nullptr)
- *bytes = core_fread(m_file, buffer, expected);
+ *bytes = m_file->read(buffer, expected);
// otherwise, copy from memory
else
diff --git a/src/lib/util/flac.h b/src/lib/util/flac.h
index 563c40974e0..1f9a49b14bd 100644
--- a/src/lib/util/flac.h
+++ b/src/lib/util/flac.h
@@ -35,7 +35,7 @@ public:
// construction/destruction
flac_encoder();
flac_encoder(void *buffer, UINT32 buflength);
- flac_encoder(core_file &file);
+ flac_encoder(util::core_file &file);
~flac_encoder();
// configuration
@@ -51,7 +51,7 @@ public:
// reset
bool reset();
bool reset(void *buffer, UINT32 buflength);
- bool reset(core_file &file);
+ bool reset(util::core_file &file);
// encode a buffer
bool encode_interleaved(const INT16 *samples, UINT32 samples_per_channel, bool swap_endian = false);
@@ -68,7 +68,7 @@ private:
// internal state
FLAC__StreamEncoder * m_encoder; // actual encoder
- core_file * m_file; // output file
+ util::core_file * m_file; // output file
UINT32 m_compressed_offset; // current offset with the compressed stream
FLAC__byte * m_compressed_start; // start of compressed data
UINT32 m_compressed_length; // length of the compressed stream
@@ -93,7 +93,7 @@ public:
// construction/destruction
flac_decoder();
flac_decoder(const void *buffer, UINT32 length, const void *buffer2 = nullptr, UINT32 length2 = 0);
- flac_decoder(core_file &file);
+ flac_decoder(util::core_file &file);
~flac_decoder();
// getters (valid after reset)
@@ -108,7 +108,7 @@ public:
bool reset();
bool reset(const void *buffer, UINT32 length, const void *buffer2 = nullptr, UINT32 length2 = 0);
bool reset(UINT32 sample_rate, UINT8 num_channels, UINT32 block_size, const void *buffer, UINT32 length);
- bool reset(core_file &file);
+ bool reset(util::core_file &file);
// decode to a buffer; num_samples must be a multiple of the block size
bool decode_interleaved(INT16 *samples, UINT32 num_samples, bool swap_endian = false);
@@ -129,7 +129,7 @@ private:
// output state
FLAC__StreamDecoder * m_decoder; // actual encoder
- core_file * m_file; // output file
+ util::core_file * m_file; // output file
UINT32 m_sample_rate; // decoded sample rate
UINT8 m_channels; // decoded number of channels
UINT8 m_bits_per_sample; // decoded bits per sample
diff --git a/src/lib/util/options.cpp b/src/lib/util/options.cpp
index 56bad147bcb..9890ae46115 100644
--- a/src/lib/util/options.cpp
+++ b/src/lib/util/options.cpp
@@ -400,11 +400,11 @@ bool core_options::parse_command_line(int argc, char **argv, int priority, std::
// an INI file
//-------------------------------------------------
-bool core_options::parse_ini_file(core_file &inifile, int priority, int ignore_priority, std::string &error_string)
+bool core_options::parse_ini_file(util::core_file &inifile, int priority, int ignore_priority, std::string &error_string)
{
// loop over lines in the file
char buffer[4096];
- while (core_fgets(buffer, ARRAY_LENGTH(buffer), &inifile) != nullptr)
+ while (inifile.gets(buffer, ARRAY_LENGTH(buffer)) != nullptr)
{
// find the extent of the name
char *optionname;
diff --git a/src/lib/util/options.h b/src/lib/util/options.h
index cf58bc67222..4ffdf00ae35 100644
--- a/src/lib/util/options.h
+++ b/src/lib/util/options.h
@@ -142,7 +142,7 @@ public:
// parsing/input
bool parse_command_line(int argc, char **argv, int priority, std::string &error_string);
- bool parse_ini_file(core_file &inifile, int priority, int ignore_priority, std::string &error_string);
+ bool parse_ini_file(util::core_file &inifile, int priority, int ignore_priority, std::string &error_string);
// reverting
void revert(int priority = OPTION_PRIORITY_MAXIMUM);
diff --git a/src/lib/util/palette.cpp b/src/lib/util/palette.cpp
index bd3c2d45ede..8c61c64a470 100644
--- a/src/lib/util/palette.cpp
+++ b/src/lib/util/palette.cpp
@@ -15,9 +15,17 @@
#include <math.h>
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
const rgb_t rgb_t::black(0,0,0);
const rgb_t rgb_t::white(255,255,255);
+// the colors below are commonly used screen colors
+const rgb_t rgb_t::green(0, 255, 0);
+const rgb_t rgb_t::amber(247, 170, 0);
+
//**************************************************************************
// INLINE FUNCTIONS
diff --git a/src/lib/util/palette.h b/src/lib/util/palette.h
index 9c6703119e1..2dfbac03a45 100644
--- a/src/lib/util/palette.h
+++ b/src/lib/util/palette.h
@@ -78,6 +78,8 @@ public:
// constants
static const rgb_t black;
static const rgb_t white;
+ static const rgb_t green;
+ static const rgb_t amber;
private:
UINT32 m_data;
diff --git a/src/lib/util/png.cpp b/src/lib/util/png.cpp
index a6b269593ef..8023d350cdc 100644
--- a/src/lib/util/png.cpp
+++ b/src/lib/util/png.cpp
@@ -148,12 +148,12 @@ void png_free(png_info *pnginfo)
header at the current file location
-------------------------------------------------*/
-static png_error verify_header(core_file *fp)
+static png_error verify_header(util::core_file &fp)
{
UINT8 signature[8];
/* read 8 bytes */
- if (core_fread(fp, signature, 8) != 8)
+ if (fp.read(signature, 8) != 8)
return PNGERR_FILE_TRUNCATED;
/* return an error if we don't match */
@@ -168,18 +168,18 @@ static png_error verify_header(core_file *fp)
read_chunk - read the next PNG chunk
-------------------------------------------------*/
-static png_error read_chunk(core_file *fp, UINT8 **data, UINT32 *type, UINT32 *length)
+static png_error read_chunk(util::core_file &fp, UINT8 **data, UINT32 *type, UINT32 *length)
{
UINT32 crc, chunk_crc;
UINT8 tempbuff[4];
/* fetch the length of this chunk */
- if (core_fread(fp, tempbuff, 4) != 4)
+ if (fp.read(tempbuff, 4) != 4)
return PNGERR_FILE_TRUNCATED;
*length = fetch_32bit(tempbuff);
/* fetch the type of this chunk */
- if (core_fread(fp, tempbuff, 4) != 4)
+ if (fp.read(tempbuff, 4) != 4)
return PNGERR_FILE_TRUNCATED;
*type = fetch_32bit(tempbuff);
@@ -200,7 +200,7 @@ static png_error read_chunk(core_file *fp, UINT8 **data, UINT32 *type, UINT32 *l
return PNGERR_OUT_OF_MEMORY;
/* read the data from the file */
- if (core_fread(fp, *data, *length) != *length)
+ if (fp.read(*data, *length) != *length)
{
free(*data);
*data = nullptr;
@@ -212,7 +212,7 @@ static png_error read_chunk(core_file *fp, UINT8 **data, UINT32 *type, UINT32 *l
}
/* read the CRC */
- if (core_fread(fp, tempbuff, 4) != 4)
+ if (fp.read(tempbuff, 4) != 4)
{
free(*data);
*data = nullptr;
@@ -502,7 +502,7 @@ handle_error:
png_read_file - read a PNG from a core stream
-------------------------------------------------*/
-png_error png_read_file(core_file *fp, png_info *pnginfo)
+png_error png_read_file(util::core_file &fp, png_info *pnginfo)
{
UINT8 *chunk_data = nullptr;
png_private png;
@@ -579,7 +579,7 @@ handle_error:
bitmap
-------------------------------------------------*/
-png_error png_read_bitmap(core_file *fp, bitmap_argb32 &bitmap)
+png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap)
{
png_error result;
png_info png;
@@ -747,7 +747,7 @@ png_error png_add_text(png_info *pnginfo, const char *keyword, const char *text)
the given file
-------------------------------------------------*/
-static png_error write_chunk(core_file *fp, const UINT8 *data, UINT32 type, UINT32 length)
+static png_error write_chunk(util::core_file &fp, const UINT8 *data, UINT32 type, UINT32 length)
{
UINT8 tempbuff[8];
UINT32 crc;
@@ -758,20 +758,20 @@ static png_error write_chunk(core_file *fp, const UINT8 *data, UINT32 type, UINT
crc = crc32(0, tempbuff + 4, 4);
/* write that data */
- if (core_fwrite(fp, tempbuff, 8) != 8)
+ if (fp.write(tempbuff, 8) != 8)
return PNGERR_FILE_ERROR;
/* append the actual data */
if (length > 0)
{
- if (core_fwrite(fp, data, length) != length)
+ if (fp.write(data, length) != length)
return PNGERR_FILE_ERROR;
crc = crc32(crc, data, length);
}
/* write the CRC */
put_32bit(tempbuff, crc);
- if (core_fwrite(fp, tempbuff, 4) != 4)
+ if (fp.write(tempbuff, 4) != 4)
return PNGERR_FILE_ERROR;
return PNGERR_NONE;
@@ -783,9 +783,9 @@ static png_error write_chunk(core_file *fp, const UINT8 *data, UINT32 type, UINT
chunk to the given file by deflating it
-------------------------------------------------*/
-static png_error write_deflated_chunk(core_file *fp, UINT8 *data, UINT32 type, UINT32 length)
+static png_error write_deflated_chunk(util::core_file &fp, UINT8 *data, UINT32 type, UINT32 length)
{
- UINT64 lengthpos = core_ftell(fp);
+ UINT64 lengthpos = fp.tell();
UINT8 tempbuff[8192];
UINT32 zlength = 0;
z_stream stream;
@@ -798,7 +798,7 @@ static png_error write_deflated_chunk(core_file *fp, UINT8 *data, UINT32 type, U
crc = crc32(0, tempbuff + 4, 4);
/* write that data */
- if (core_fwrite(fp, tempbuff, 8) != 8)
+ if (fp.write(tempbuff, 8) != 8)
return PNGERR_FILE_ERROR;
/* initialize the stream */
@@ -821,7 +821,7 @@ static png_error write_deflated_chunk(core_file *fp, UINT8 *data, UINT32 type, U
if (stream.avail_out < sizeof(tempbuff))
{
int bytes = sizeof(tempbuff) - stream.avail_out;
- if (core_fwrite(fp, tempbuff, bytes) != bytes)
+ if (fp.write(tempbuff, bytes) != bytes)
{
deflateEnd(&stream);
return PNGERR_FILE_ERROR;
@@ -849,17 +849,17 @@ static png_error write_deflated_chunk(core_file *fp, UINT8 *data, UINT32 type, U
/* write the CRC */
put_32bit(tempbuff, crc);
- if (core_fwrite(fp, tempbuff, 4) != 4)
+ if (fp.write(tempbuff, 4) != 4)
return PNGERR_FILE_ERROR;
/* seek back and update the length */
- core_fseek(fp, lengthpos, SEEK_SET);
+ fp.seek(lengthpos, SEEK_SET);
put_32bit(tempbuff + 0, zlength);
- if (core_fwrite(fp, tempbuff, 4) != 4)
+ if (fp.write(tempbuff, 4) != 4)
return PNGERR_FILE_ERROR;
/* return to the end */
- core_fseek(fp, lengthpos + 8 + zlength + 4, SEEK_SET);
+ fp.seek(lengthpos + 8 + zlength + 4, SEEK_SET);
return PNGERR_NONE;
}
@@ -1006,7 +1006,7 @@ static png_error convert_bitmap_to_image_rgb(png_info *pnginfo, const bitmap_t &
chunks to the given file
-------------------------------------------------*/
-static png_error write_png_stream(core_file *fp, png_info *pnginfo, const bitmap_t &bitmap, int palette_length, const rgb_t *palette)
+static png_error write_png_stream(util::core_file &fp, png_info *pnginfo, const bitmap_t &bitmap, int palette_length, const rgb_t *palette)
{
UINT8 tempbuff[16];
png_text *text;
@@ -1061,7 +1061,7 @@ handle_error:
}
-png_error png_write_bitmap(core_file *fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette)
+png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette)
{
png_info pnginfo;
png_error error;
@@ -1074,7 +1074,7 @@ png_error png_write_bitmap(core_file *fp, png_info *info, bitmap_t &bitmap, int
}
/* write the PNG signature */
- if (core_fwrite(fp, PNG_Signature, 8) != 8)
+ if (fp.write(PNG_Signature, 8) != 8)
{
if (info == &pnginfo)
png_free(&pnginfo);
@@ -1097,7 +1097,7 @@ png_error png_write_bitmap(core_file *fp, png_info *info, bitmap_t &bitmap, int
********************************************************************************/
/**
- * @fn png_error mng_capture_start(core_file *fp, bitmap_t &bitmap, double rate)
+ * @fn png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, double rate)
*
* @brief Mng capture start.
*
@@ -1108,12 +1108,12 @@ png_error png_write_bitmap(core_file *fp, png_info *info, bitmap_t &bitmap, int
* @return A png_error.
*/
-png_error mng_capture_start(core_file *fp, bitmap_t &bitmap, double rate)
+png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, double rate)
{
UINT8 mhdr[28];
png_error error;
- if (core_fwrite(fp, MNG_Signature, 8) != 8)
+ if (fp.write(MNG_Signature, 8) != 8)
return PNGERR_FILE_ERROR;
memset(mhdr, 0, 28);
@@ -1131,7 +1131,7 @@ png_error mng_capture_start(core_file *fp, bitmap_t &bitmap, double rate)
}
/**
- * @fn png_error mng_capture_frame(core_file *fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette)
+ * @fn png_error mng_capture_frame(util::core_file &fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette)
*
* @brief Mng capture frame.
*
@@ -1144,13 +1144,13 @@ png_error mng_capture_start(core_file *fp, bitmap_t &bitmap, double rate)
* @return A png_error.
*/
-png_error mng_capture_frame(core_file *fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette)
+png_error mng_capture_frame(util::core_file &fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette)
{
return write_png_stream(fp, info, bitmap, palette_length, palette);
}
/**
- * @fn png_error mng_capture_stop(core_file *fp)
+ * @fn png_error mng_capture_stop(util::core_file &fp)
*
* @brief Mng capture stop.
*
@@ -1159,7 +1159,7 @@ png_error mng_capture_frame(core_file *fp, png_info *info, bitmap_t &bitmap, int
* @return A png_error.
*/
-png_error mng_capture_stop(core_file *fp)
+png_error mng_capture_stop(util::core_file &fp)
{
return write_chunk(fp, nullptr, MNG_CN_MEND, 0);
}
diff --git a/src/lib/util/png.h b/src/lib/util/png.h
index 52e5111d199..00522f12f5c 100644
--- a/src/lib/util/png.h
+++ b/src/lib/util/png.h
@@ -119,15 +119,15 @@ struct png_info
void png_free(png_info *pnginfo);
-png_error png_read_file(core_file *fp, png_info *pnginfo);
-png_error png_read_bitmap(core_file *fp, bitmap_argb32 &bitmap);
+png_error png_read_file(util::core_file &fp, png_info *pnginfo);
+png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap);
png_error png_expand_buffer_8bit(png_info *p);
png_error png_add_text(png_info *pnginfo, const char *keyword, const char *text);
-png_error png_write_bitmap(core_file *fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette);
+png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette);
-png_error mng_capture_start(core_file *fp, bitmap_t &bitmap, double rate);
-png_error mng_capture_frame(core_file *fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette);
-png_error mng_capture_stop(core_file *fp);
+png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, double rate);
+png_error mng_capture_frame(util::core_file &fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette);
+png_error mng_capture_stop(util::core_file &fp);
#endif /* __PNG_H__ */
diff --git a/src/lib/util/strformat.h b/src/lib/util/strformat.h
index ac7301dc6bd..8eb5f791ed0 100644
--- a/src/lib/util/strformat.h
+++ b/src/lib/util/strformat.h
@@ -185,6 +185,21 @@
#include <type_traits>
#include <utility>
+#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20150413)
+namespace std
+{
+template<class _Container>
+ inline constexpr auto
+ cbegin(const _Container& __cont) noexcept(noexcept(std::begin(__cont)))-> decltype(std::begin(__cont))
+ { return std::begin(__cont); }
+
+template<class _Container>
+ inline constexpr auto
+ cend(const _Container& __cont) noexcept(noexcept(std::end(__cont)))-> decltype(std::end(__cont))
+ { return std::end(__cont); }
+}
+#endif
+
namespace util {
namespace detail {
//**************************************************************************
@@ -1040,7 +1055,7 @@ public:
{
return (m_end && (m_end == it)) || (m_check_nul && (format_chars<char_type>::nul == *it));
}
- std::size_t size() const
+ std::size_t argument_count() const
{
return m_argument_count;
}
@@ -1096,7 +1111,7 @@ protected:
format_argument<Stream> const *arguments,
std::enable_if_t<handle_container<std::remove_reference_t<Format> >::value, std::size_t> argument_count)
: m_begin(fmt.empty() ? nullptr : &*std::cbegin(fmt))
- , m_end(fmt.empty() ? nullptr : &*std::cend(fmt))
+ , m_end(fmt.empty() ? nullptr : (m_begin + std::distance(std::cbegin(fmt), std::cend(fmt))))
, m_check_nul(true)
, m_arguments(arguments)
, m_argument_count(argument_count)
@@ -1131,6 +1146,9 @@ class format_argument_pack_impl
, public format_argument_pack<Stream>
{
public:
+ using typename format_argument_pack<Stream>::iterator;
+ using format_argument_pack<Stream>::operator[];
+
template <typename Format, typename... Params>
format_argument_pack_impl(Format &&fmt, Params &&... args)
: std::array<format_argument<Stream>, Count>({ { format_argument<Stream>(std::forward<Params>(args))... } })
@@ -1147,15 +1165,9 @@ public:
//**************************************************************************
-// ARGUMENT PACK CREATOR FUNCTIONS
+// ARGUMENT PACK CREATOR FUNCTION
//**************************************************************************
-template <typename Stream = std::ostream, typename... Params>
-inline std::array<format_argument<Stream>, sizeof...(Params)> make_format_arguments(Params &&... args)
-{
- return std::array<format_argument<Stream>, sizeof...(Params)>({ { format_argument<Stream>(std::forward<Params>(args))... } });
-}
-
template <typename Stream = std::ostream, typename Format, typename... Params>
inline format_argument_pack_impl<Stream, sizeof...(Params)> make_format_argument_pack(Format &&fmt, Params &&... args)
{
@@ -1164,54 +1176,16 @@ inline format_argument_pack_impl<Stream, sizeof...(Params)> make_format_argument
//**************************************************************************
-// FORMAT STRING PARSING HELPERS
+// FORMAT STRING PARSING HELPER
//**************************************************************************
template <typename Format>
-class format_helper_base : public format_chars<std::remove_cv_t<std::remove_reference_t<decltype(*std::cbegin(std::declval<Format>()))> > >
-{
-public:
- typedef std::remove_reference_t<decltype(std::cbegin(std::declval<Format>()))> iterator;
- static iterator begin(Format const &fmt) { return std::cbegin(fmt); }
- static bool at_end(Format const &fmt, iterator const &it) { return std::cend(fmt) == it; }
-};
-
-template <typename Character>
-class format_helper_base<Character *> : public format_chars<std::remove_cv_t<Character> >
-{
-public:
- typedef Character const *iterator;
- static iterator begin(Character const *fmt) { return fmt; }
- static bool at_end(Character const *fmt, iterator const &it) { return format_helper_base::nul == *it; }
-};
-
-template <typename Character, std::size_t Length>
-class format_helper_base<Character [Length]> : public format_chars<std::remove_cv_t<Character> >
-{
-public:
- typedef Character const *iterator;
- static iterator begin(std::remove_const_t<Character> (&fmt)[Length]) { return std::cbegin(fmt); }
- static iterator begin(std::add_const_t<Character> (&fmt)[Length]) { return std::cbegin(fmt); }
- static bool at_end(std::remove_const_t<Character> (&fmt)[Length], iterator const &it) { return (std::cend(fmt) == it) || (format_chars<Character>::nul == *it); }
- static bool at_end(std::add_const_t<Character> (&fmt)[Length], iterator const &it) { return (std::cend(fmt) == it) || (format_helper_base::nul == *it); }
-};
-
-template <typename Stream>
-class format_helper_base<format_argument_pack<Stream> > : public format_chars<typename format_argument_pack<Stream>::char_type>
-{
-public:
- typedef typename format_argument_pack<Stream>::iterator iterator;
- static iterator begin(format_argument_pack<Stream> const &fmt) { return fmt.format_begin(); }
- static bool at_end(format_argument_pack<Stream> const &fmt, iterator const &it) { return fmt.format_at_end(it); }
-};
-
-template <typename Format>
-class format_helper : public format_helper_base<Format>
+class format_helper : public format_chars<typename Format::char_type>
{
public:
static bool parse_format(
Format const &fmt,
- typename format_helper::iterator &it,
+ typename Format::iterator &it,
format_flags &flags,
int &next_position,
int &argument_position,
@@ -1219,7 +1193,7 @@ public:
int &precision_position)
{
static_assert((format_helper::nine - format_helper::zero) == 9, "Digits must be contiguous");
- assert(!format_helper::at_end(fmt, it));
+ assert(!fmt.format_at_end(it));
assert(format_helper::percent == *it);
int num;
@@ -1231,8 +1205,8 @@ public:
precision_position = -1;
// Leading zeroes are tricky - they could be a zero-pad flag or part of a position specifier
- bool const leading_zero(!format_helper::at_end(fmt, it) && (format_helper::zero == *it));
- while (!format_helper::at_end(fmt, it) && (format_helper::zero == *it)) ++it;
+ bool const leading_zero(!fmt.format_at_end(it) && (format_helper::zero == *it));
+ while (!fmt.format_at_end(it) && (format_helper::zero == *it)) ++it;
// Digits encountered at this point could be a field width or a position specifier
num = 0;
@@ -1258,7 +1232,7 @@ public:
}
// Parse flag characters
- while (!format_helper::at_end(fmt, it))
+ while (!fmt.format_at_end(it))
{
switch (*it)
{
@@ -1275,7 +1249,7 @@ public:
}
// Check for literal or parameterised field width
- if (!format_helper::at_end(fmt, it))
+ if (!fmt.format_at_end(it))
{
if (is_digit(*it))
{
@@ -1302,14 +1276,14 @@ public:
}
// Check for literal or parameterised precision
- if (!format_helper::at_end(fmt, it) && (*it == format_helper::point))
+ if (!fmt.format_at_end(it) && (*it == format_helper::point))
{
++it;
if (have_digit(fmt, it))
{
flags.set_precision(read_number(fmt, it));
}
- else if (!format_helper::at_end(fmt, it) && (format_helper::asterisk == *it))
+ else if (!fmt.format_at_end(it) && (format_helper::asterisk == *it))
{
++it;
if (have_digit(fmt, it))
@@ -1333,11 +1307,11 @@ public:
}
// Check for length modifiers
- if (!format_helper::at_end(fmt, it)) switch (*it)
+ if (!fmt.format_at_end(it)) switch (*it)
{
case format_helper::h:
++it;
- if (!format_helper::at_end(fmt, it) && (format_helper::h == *it))
+ if (!fmt.format_at_end(it) && (format_helper::h == *it))
{
++it;
flags.set_length(format_flags::length::character);
@@ -1349,7 +1323,7 @@ public:
break;
case format_helper::l:
++it;
- if (!format_helper::at_end(fmt, it) && (format_helper::l == *it))
+ if (!fmt.format_at_end(it) && (format_helper::l == *it))
{
++it;
flags.set_length(format_flags::length::long_long_integer);
@@ -1379,13 +1353,13 @@ public:
{
++it;
format_flags::length length = format_flags::length::size_type;
- if (!format_helper::at_end(fmt, it))
+ if (!fmt.format_at_end(it))
{
if ((typename format_helper::char_type(format_helper::zero) + 3) == *it)
{
- typename format_helper::iterator tmp(it);
+ typename Format::iterator tmp(it);
++tmp;
- if (!format_helper::at_end(fmt, tmp) && ((typename format_helper::char_type(format_helper::zero) + 2) == *tmp))
+ if (!fmt.format_at_end(tmp) && ((typename format_helper::char_type(format_helper::zero) + 2) == *tmp))
{
length = format_flags::length::integer_32;
it = ++tmp;
@@ -1393,9 +1367,9 @@ public:
}
else if ((typename format_helper::char_type(format_helper::zero) + 6) == *it)
{
- typename format_helper::iterator tmp(it);
+ typename Format::iterator tmp(it);
++tmp;
- if (!format_helper::at_end(fmt, tmp) && ((typename format_helper::char_type(format_helper::zero) + 4) == *tmp))
+ if (!fmt.format_at_end(tmp) && ((typename format_helper::char_type(format_helper::zero) + 4) == *tmp))
{
length = format_flags::length::integer_64;
it = ++tmp;
@@ -1414,8 +1388,8 @@ public:
}
// Now we should find a conversion specifier
- assert(!format_helper::at_end(fmt, it)); // missing conversion
- if (format_helper::at_end(fmt, it)) return false;
+ assert(!fmt.format_at_end(it)); // missing conversion
+ if (fmt.format_at_end(it)) return false;
switch (*it)
{
case format_helper::d:
@@ -1498,14 +1472,14 @@ public:
}
private:
- static bool have_dollar(Format const &fmt, typename format_helper::iterator const &it)
+ static bool have_dollar(Format const &fmt, typename Format::iterator const &it)
{
- return !format_helper::at_end(fmt, it) && (*it == format_helper::dollar);
+ return !fmt.format_at_end(it) && (*it == format_helper::dollar);
}
- static bool have_digit(Format const &fmt, typename format_helper::iterator const &it)
+ static bool have_digit(Format const &fmt, typename Format::iterator const &it)
{
- return !format_helper::at_end(fmt, it) && is_digit(*it);
+ return !fmt.format_at_end(it) && is_digit(*it);
}
static bool is_digit(typename format_helper::char_type value)
@@ -1524,7 +1498,7 @@ private:
num = (num * 10) + digit_value(digit);
}
- static int read_number(Format const &fmt, typename format_helper::iterator &it)
+ static int read_number(Format const &fmt, typename Format::iterator &it)
{
assert(have_digit(fmt, it));
int value = 0;
@@ -1538,11 +1512,11 @@ private:
// CORE FORMATTING FUNCTION
//**************************************************************************
-template <typename Stream, typename Format, typename Params>
-typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args)
+template <typename Stream, typename Base>
+typename Stream::off_type stream_format(Stream &str, format_argument_pack<Base> const &args)
{
- typedef format_helper<std::remove_cv_t<std::remove_reference_t<Format> > > format_helper;
- typedef typename format_helper::iterator iterator;
+ typedef format_helper<format_argument_pack<Base> > format_helper;
+ typedef typename format_argument_pack<Base>::iterator iterator;
class stream_preserver
{
public:
@@ -1572,21 +1546,21 @@ typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args
typename Stream::pos_type const begin(str.tellp());
stream_preserver const preserver(str);
int next_pos(1);
- iterator start = format_helper::begin(fmt);
- for (iterator it = start; !format_helper::at_end(fmt, start); )
+ iterator start = args.format_begin();
+ for (iterator it = start; !args.format_at_end(start); )
{
- while (!format_helper::at_end(fmt, it) && (format_helper::percent != *it)) ++it;
+ while (!args.format_at_end(it) && (format_helper::percent != *it)) ++it;
if (start != it)
{
str.write(&*start, it - start);
start = it;
}
- if (!format_helper::at_end(fmt, it))
+ if (!args.format_at_end(it))
{
// Try to parse a percent format specification
format_flags flags;
int arg_pos, width_pos, prec_pos;
- if (!format_helper::parse_format(fmt, it, flags, next_pos, arg_pos, width_pos, prec_pos))
+ if (!format_helper::parse_format(args, it, flags, next_pos, arg_pos, width_pos, prec_pos))
continue;
// Handle parameterised width
@@ -1594,8 +1568,8 @@ typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args
{
assert(flags.get_field_width() == 0U);
assert(0 < width_pos);
- assert(args.size() >= unsigned(width_pos));
- if ((0 < width_pos) && (args.size() >= unsigned(width_pos)))
+ assert(args.argument_count() >= unsigned(width_pos));
+ if ((0 < width_pos) && (args.argument_count() >= unsigned(width_pos)))
{
int width;
if (args[width_pos - 1].make_integer(width))
@@ -1622,8 +1596,8 @@ typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args
{
assert(flags.get_precision() < 0);
assert(0 < prec_pos);
- assert(args.size() >= unsigned(prec_pos));
- if ((0 < prec_pos) && (args.size() >= unsigned(prec_pos)))
+ assert(args.argument_count() >= unsigned(prec_pos));
+ if ((0 < prec_pos) && (args.argument_count() >= unsigned(prec_pos)))
{
int precision;
if (args[prec_pos - 1].make_integer(precision))
@@ -1648,8 +1622,8 @@ typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args
else
{
assert(0 < arg_pos);
- assert(args.size() >= unsigned(arg_pos));
- if ((0 >= arg_pos) || (args.size() < unsigned(arg_pos)))
+ assert(args.argument_count() >= unsigned(arg_pos));
+ if ((0 >= arg_pos) || (args.argument_count() < unsigned(arg_pos)))
continue;
if (format_flags::conversion::tell == flags.get_conversion())
{
@@ -1683,19 +1657,19 @@ typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args
template <typename Stream, typename Format, typename... Params>
inline typename Stream::off_type stream_format(Stream &str, Format const &fmt, Params &&... args)
{
- return detail::stream_format(str, fmt, detail::make_format_arguments<Stream>(std::forward<Params>(args)...));
+ return detail::stream_format(str, detail::make_format_argument_pack<Stream>(fmt, std::forward<Params>(args)...));
}
template <typename Stream, typename Base>
inline typename Stream::off_type stream_format(Stream &str, detail::format_argument_pack<Base> const &args)
{
- return detail::stream_format(str, args, args);
+ return detail::stream_format(str, args);
}
template <typename Stream, typename Base>
inline typename Stream::off_type stream_format(Stream &str, detail::format_argument_pack<Base> &&args)
{
- return detail::stream_format(str, args, args);
+ return detail::stream_format(str, args);
}
@@ -1722,41 +1696,41 @@ inline String string_format(std::locale const &locale, Format &&fmt, Params &&..
return str.str();
};
-template <typename String = std::string, typename Format, typename Stream>
-inline String string_format(Format &&fmt, detail::format_argument_pack<Stream> const &args)
+template <typename String = std::string, typename Stream>
+inline String string_format(detail::format_argument_pack<Stream> const &args)
{
typedef std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type> ostream;
ostream str;
- stream_format(str, std::forward<Format>(fmt), args);
+ detail::stream_format(str, args);
return str.str();
};
-template <typename String = std::string, typename Format, typename Stream>
-inline String string_format(Format &&fmt, detail::format_argument_pack<Stream> &&args)
+template <typename String = std::string, typename Stream>
+inline String string_format(detail::format_argument_pack<Stream> &&args)
{
typedef std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type> ostream;
ostream str;
- stream_format(str, std::forward<Format>(fmt), std::move(args));
+ detail::stream_format(str, std::move(args));
return str.str();
};
-template <typename String = std::string, typename Format, typename Stream>
-inline String string_format(std::locale const &locale, Format &&fmt, detail::format_argument_pack<Stream> const &args)
+template <typename String = std::string, typename Stream>
+inline String string_format(std::locale const &locale, detail::format_argument_pack<Stream> const &args)
{
typedef std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type> ostream;
ostream str;
str.imbue(locale);
- stream_format(str, std::forward<Format>(fmt), args);
+ detail::stream_format(str, args);
return str.str();
};
-template <typename String = std::string, typename Format, typename Stream>
-inline String string_format(std::locale const &locale, Format &&fmt, detail::format_argument_pack<Stream> &&args)
+template <typename String = std::string, typename Stream>
+inline String string_format(std::locale const &locale, detail::format_argument_pack<Stream> &&args)
{
typedef std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type> ostream;
ostream str;
str.imbue(locale);
- stream_format(str, std::forward<Format>(fmt), std::move(args));
+ detail::stream_format(str, std::move(args));
return str.str();
};
diff --git a/src/lib/util/vecstream.h b/src/lib/util/vecstream.h
index fb472df95cd..bf144501253 100644
--- a/src/lib/util/vecstream.h
+++ b/src/lib/util/vecstream.h
@@ -19,6 +19,10 @@
#include <algorithm>
#include <cassert>
+#include <ios>
+#include <istream>
+#include <ostream>
+#include <memory>
#include <ostream>
#include <streambuf>
#include <string>
@@ -103,15 +107,16 @@ public:
void swap(basic_vectorbuf &that)
{
+ using std::swap;
std::basic_streambuf<CharT, Traits>::swap(that);
- std::swap(m_mode, that.m_mode);
- m_storage.swap(that.m_storage);
- std::swap(m_threshold, that.m_threshold);
+ swap(m_mode, that.m_mode);
+ swap(m_storage, that.m_storage);
+ swap(m_threshold, that.m_threshold);
}
void reserve(typename vector_type::size_type size)
{
- if ((m_mode & std::ios_base::out) && (m_storage.size() < size))
+ if ((m_mode & std::ios_base::out) && (m_storage.capacity() < size))
{
m_storage.reserve(size);
adjust();
@@ -145,8 +150,8 @@ protected:
bool const out(which & std::ios_base::out);
if ((!in && !out) ||
(in && out && (std::ios_base::cur == dir)) ||
- (in && (!(m_mode & std::ios_base::in) || !this->gptr())) ||
- (out && (!(m_mode & std::ios_base::out) || !this->pptr())))
+ (in && !(m_mode & std::ios_base::in)) ||
+ (out && !(m_mode & std::ios_base::out)))
{
return pos_type(off_type(-1));
}
@@ -382,6 +387,16 @@ typedef basic_ovectorstream<wchar_t> wovectorstream;
typedef basic_vectorstream<char> vectorstream;
typedef basic_vectorstream<wchar_t> wvectorstream;
+template <typename CharT, typename Traits, typename Allocator>
+void swap(basic_vectorbuf<CharT, Traits, Allocator> &a, basic_vectorbuf<CharT, Traits, Allocator> &b) { a.swap(b); }
+
+template <typename CharT, typename Traits, typename Allocator>
+void swap(basic_ivectorstream<CharT, Traits, Allocator> &a, basic_ivectorstream<CharT, Traits, Allocator> &b) { a.swap(b); }
+template <typename CharT, typename Traits, typename Allocator>
+void swap(basic_ovectorstream<CharT, Traits, Allocator> &a, basic_ovectorstream<CharT, Traits, Allocator> &b) { a.swap(b); }
+template <typename CharT, typename Traits, typename Allocator>
+void swap(basic_vectorstream<CharT, Traits, Allocator> &a, basic_vectorstream<CharT, Traits, Allocator> &b) { a.swap(b); }
+
} // namespace util
#endif // __MAME_UTIL_VECSTREAM_H__
diff --git a/src/lib/util/xmlfile.cpp b/src/lib/util/xmlfile.cpp
index 620f12a66b3..db288b0a807 100644
--- a/src/lib/util/xmlfile.cpp
+++ b/src/lib/util/xmlfile.cpp
@@ -52,7 +52,7 @@ static xml_data_node *add_child(xml_data_node *parent, const char *name, const c
static xml_attribute_node *add_attribute(xml_data_node *node, const char *name, const char *value);
/* recursive tree operations */
-static void write_node_recursive(xml_data_node *node, int indent, core_file *file);
+static void write_node_recursive(xml_data_node *node, int indent, util::core_file &file);
static void free_node_recursive(xml_data_node *node);
@@ -139,7 +139,7 @@ xml_data_node *xml_file_create(void)
nodes
-------------------------------------------------*/
-xml_data_node *xml_file_read(core_file *file, xml_parse_options *opts)
+xml_data_node *xml_file_read(util::core_file &file, xml_parse_options *opts)
{
xml_parse_info parse_info;
int done;
@@ -154,8 +154,8 @@ xml_data_node *xml_file_read(core_file *file, xml_parse_options *opts)
char tempbuf[TEMP_BUFFER_SIZE];
/* read as much as we can */
- int bytes = core_fread(file, tempbuf, sizeof(tempbuf));
- done = core_feof(file);
+ int bytes = file.read(tempbuf, sizeof(tempbuf));
+ done = file.eof();
/* parse the data */
if (XML_Parse(parse_info.parser, tempbuf, bytes, done) == XML_STATUS_ERROR)
@@ -223,15 +223,15 @@ xml_data_node *xml_string_read(const char *string, xml_parse_options *opts)
xml_file_write - write an XML tree to a file
-------------------------------------------------*/
-void xml_file_write(xml_data_node *node, core_file *file)
+void xml_file_write(xml_data_node *node, util::core_file &file)
{
/* ensure this is a root node */
if (node->name != nullptr)
return;
/* output a simple header */
- core_fprintf(file, "<?xml version=\"1.0\"?>\n");
- core_fprintf(file, "<!-- This file is autogenerated; comments and unknown tags will be stripped -->\n");
+ file.printf("<?xml version=\"1.0\"?>\n");
+ file.printf("<!-- This file is autogenerated; comments and unknown tags will be stripped -->\n");
/* loop over children of the root and output */
for (node = node->child; node; node = node->next)
@@ -1002,7 +1002,7 @@ static xml_attribute_node *add_attribute(xml_data_node *node, const char *name,
-------------------------------------------------*/
/**
- * @fn static void write_node_recursive(xml_data_node *node, int indent, core_file *file)
+ * @fn static void write_node_recursive(xml_data_node *node, int indent, util::core_file &file)
*
* @brief Writes a node recursive.
*
@@ -1011,30 +1011,30 @@ static xml_attribute_node *add_attribute(xml_data_node *node, const char *name,
* @param [in,out] file If non-null, the file.
*/
-static void write_node_recursive(xml_data_node *node, int indent, core_file *file)
+static void write_node_recursive(xml_data_node *node, int indent, util::core_file &file)
{
xml_attribute_node *anode;
xml_data_node *child;
/* output this tag */
- core_fprintf(file, "%*s<%s", indent, "", node->name);
+ file.printf("%*s<%s", indent, "", node->name);
/* output any attributes */
for (anode = node->attribute; anode; anode = anode->next)
- core_fprintf(file, " %s=\"%s\"", anode->name, anode->value);
+ file.printf(" %s=\"%s\"", anode->name, anode->value);
/* if there are no children and no value, end the tag here */
if (node->child == nullptr && node->value == nullptr)
- core_fprintf(file, " />\n");
+ file.printf(" />\n");
/* otherwise, close this tag and output more stuff */
else
{
- core_fprintf(file, ">\n");
+ file.printf(">\n");
/* if there is a value, output that here */
if (node->value != nullptr)
- core_fprintf(file, "%*s%s\n", indent + 4, "", node->value);
+ file.printf("%*s%s\n", indent + 4, "", node->value);
/* loop over children and output them as well */
if (node->child != nullptr)
@@ -1044,7 +1044,7 @@ static void write_node_recursive(xml_data_node *node, int indent, core_file *fil
}
/* write a closing tag */
- core_fprintf(file, "%*s</%s>\n", indent, "", node->name);
+ file.printf("%*s</%s>\n", indent, "", node->name);
}
}
diff --git a/src/lib/util/xmlfile.h b/src/lib/util/xmlfile.h
index 06412abbefe..e116366643f 100644
--- a/src/lib/util/xmlfile.h
+++ b/src/lib/util/xmlfile.h
@@ -97,13 +97,13 @@ struct xml_parse_options
xml_data_node *xml_file_create(void);
/* parse an XML file into its nodes */
-xml_data_node *xml_file_read(core_file *file, xml_parse_options *opts);
+xml_data_node *xml_file_read(util::core_file &file, xml_parse_options *opts);
/* parse an XML string into its nodes */
xml_data_node *xml_string_read(const char *string, xml_parse_options *opts);
/* write an XML tree to a file */
-void xml_file_write(xml_data_node *node, core_file *file);
+void xml_file_write(xml_data_node *node, util::core_file &file);
/* free an XML file object */
void xml_file_free(xml_data_node *node);
diff --git a/src/lib/util/zippath.cpp b/src/lib/util/zippath.cpp
index 84674eb1fe2..efe7c710481 100644
--- a/src/lib/util/zippath.cpp
+++ b/src/lib/util/zippath.cpp
@@ -298,7 +298,7 @@ static file_error file_error_from_zip_error(zip_error ziperr)
-------------------------------------------------*/
/**
- * @fn static file_error create_core_file_from_zip(zip_file *zip, const zip_file_header *header, core_file *&file)
+ * @fn static file_error create_core_file_from_zip(zip_file *zip, const zip_file_header *header, util::core_file::ptr &file)
*
* @brief Creates core file from zip.
*
@@ -309,7 +309,7 @@ static file_error file_error_from_zip_error(zip_error ziperr)
* @return The new core file from zip.
*/
-static file_error create_core_file_from_zip(zip_file *zip, const zip_file_header *header, core_file *&file)
+static file_error create_core_file_from_zip(zip_file *zip, const zip_file_header *header, util::core_file::ptr &file)
{
file_error filerr;
zip_error ziperr;
@@ -329,7 +329,7 @@ static file_error create_core_file_from_zip(zip_file *zip, const zip_file_header
goto done;
}
- filerr = core_fopen_ram_copy(ptr, header->uncompressed_length, OPEN_FLAG_READ, &file);
+ filerr = util::core_file::open_ram_copy(ptr, header->uncompressed_length, OPEN_FLAG_READ, file);
if (filerr != FILERR_NONE)
goto done;
@@ -345,7 +345,7 @@ done:
-------------------------------------------------*/
/**
- * @fn file_error zippath_fopen(const char *filename, UINT32 openflags, core_file *&file, std::string &revised_path)
+ * @fn file_error zippath_fopen(const char *filename, UINT32 openflags, util::core_file::ptr &file, std::string &revised_path)
*
* @brief Zippath fopen.
*
@@ -357,7 +357,7 @@ done:
* @return A file_error.
*/
-file_error zippath_fopen(const char *filename, UINT32 openflags, core_file *&file, std::string &revised_path)
+file_error zippath_fopen(const char *filename, UINT32 openflags, util::core_file::ptr &file, std::string &revised_path)
{
file_error filerr = FILERR_NOT_FOUND;
zip_error ziperr;
@@ -421,7 +421,7 @@ file_error zippath_fopen(const char *filename, UINT32 openflags, core_file *&fil
}
if (subpath.length() == 0)
- filerr = core_fopen(filename, openflags, &file);
+ filerr = util::core_file::open(filename, openflags, file);
else
filerr = FILERR_NOT_FOUND;
diff --git a/src/lib/util/zippath.h b/src/lib/util/zippath.h
index 960b50851e7..ce40c87ba8d 100644
--- a/src/lib/util/zippath.h
+++ b/src/lib/util/zippath.h
@@ -45,7 +45,7 @@ std::string &zippath_combine(std::string &dst, const char *path1, const char *pa
/* ----- file operations ----- */
/* opens a zip path file */
-file_error zippath_fopen(const char *filename, UINT32 openflags, core_file *&file, std::string &revised_path);
+file_error zippath_fopen(const char *filename, UINT32 openflags, util::core_file::ptr &file, std::string &revised_path);
/* ----- directory operations ----- */