diff options
Diffstat (limited to 'src/lib/util')
-rw-r--r-- | src/lib/util/cdrom.cpp | 12 | ||||
-rw-r--r-- | src/lib/util/chd.cpp | 68 | ||||
-rw-r--r-- | src/lib/util/chd.h | 10 | ||||
-rw-r--r-- | src/lib/util/corefile.cpp | 1642 | ||||
-rw-r--r-- | src/lib/util/corefile.h | 127 | ||||
-rw-r--r-- | src/lib/util/flac.cpp | 14 | ||||
-rw-r--r-- | src/lib/util/flac.h | 12 | ||||
-rw-r--r-- | src/lib/util/options.cpp | 4 | ||||
-rw-r--r-- | src/lib/util/options.h | 2 | ||||
-rw-r--r-- | src/lib/util/palette.cpp | 8 | ||||
-rw-r--r-- | src/lib/util/palette.h | 2 | ||||
-rw-r--r-- | src/lib/util/png.cpp | 62 | ||||
-rw-r--r-- | src/lib/util/png.h | 12 | ||||
-rw-r--r-- | src/lib/util/strformat.h | 178 | ||||
-rw-r--r-- | src/lib/util/vecstream.h | 27 | ||||
-rw-r--r-- | src/lib/util/xmlfile.cpp | 30 | ||||
-rw-r--r-- | src/lib/util/xmlfile.h | 4 | ||||
-rw-r--r-- | src/lib/util/zippath.cpp | 12 | ||||
-rw-r--r-- | src/lib/util/zippath.h | 2 |
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 ----- */ |