// license:BSD-3-Clause // copyright-holders:Aaron Giles /*************************************************************************** fileio.h Core file I/O interface functions and definitions. ***************************************************************************/ #ifndef MAME_EMU_FILEIO_H #define MAME_EMU_FILEIO_H #pragma once #include "corefile.h" #include "hash.h" #include #include #include #include #include #include // some systems use macros for getc/putc rather than functions #ifdef getc #undef getc #endif //************************************************************************** // TYPE DEFINITIONS //************************************************************************** // ======================> path_iterator // helper class for iterating over configured paths class path_iterator { public: // constructors path_iterator(std::string &&searchpath); path_iterator(std::string const &searchpath); path_iterator(path_iterator &&that); path_iterator(path_iterator const &that); template path_iterator(T &&searchpath, std::enable_if_t::value, int> = 0) : path_iterator(std::string(std::forward(searchpath))) { } // TODO: this doesn't work with C arrays (only vector, std::array, etc.) template path_iterator(T &&paths, std::enable_if_t::value_type>::value, int> = 0) : path_iterator(concatenate_paths(std::forward(paths))) { m_separator = '\0'; } // assignment operators path_iterator &operator=(path_iterator &&that); path_iterator &operator=(path_iterator const &that); // main interface bool next(std::string &buffer); void reset(); private: // helpers template static std::string concatenate_paths(T &&paths) { std::string result; auto it(std::begin(paths)); if (std::end(paths) != it) { result.append(*it); ++it; } while (std::end(paths) != it) { result.append(1, '\0'); result.append(*it); ++it; } return result; } // internal state std::string m_searchpath; std::string::const_iterator m_current; char m_separator; bool m_is_first; }; // ======================> file_enumerator // iterate over all files in all paths specified in the searchpath class file_enumerator { public: // construction/destruction template file_enumerator(T &&... args) : m_iterator(std::forward(args)...) { } file_enumerator(file_enumerator &&) = default; file_enumerator(file_enumerator const &) = delete; file_enumerator &operator=(file_enumerator &&) = default; file_enumerator &operator=(file_enumerator const &) = delete; // iterator const osd::directory::entry *next(const char *subdir = nullptr); private: // internal state path_iterator m_iterator; osd::directory::ptr m_curdir; std::string m_pathbuffer; }; // ======================> emu_file class emu_file { enum empty_t { EMPTY }; using searchpath_vector = std::vector >; public: // file open/creation emu_file(u32 openflags); template emu_file(T &&searchpath, std::enable_if_t::value, u32> openflags) : emu_file(path_iterator(std::forward(searchpath)), openflags) { } template emu_file(T &&searchpath, U &&x, V &&y, W &&... z) : emu_file(0U, EMPTY) { m_iterator.reserve(sizeof...(W) + 1); m_mediapaths.reserve(sizeof...(W) + 1); set_searchpaths(std::forward(searchpath), std::forward(x), std::forward(y), std::forward(z)...); } virtual ~emu_file(); // getters operator util::core_file &(); bool is_open() const { return bool(m_file); } const char *filename() const { return m_filename.c_str(); } const char *fullpath() const { return m_fullpath.c_str(); } u32 openflags() const { return m_openflags; } util::hash_collection &hashes(std::string_view types); // setters void remove_on_close() { m_remove_on_close = true; } void set_openflags(u32 openflags) { assert(!m_file); m_openflags = openflags; } void set_restrict_to_mediapath(int rtmp) { m_restrict_to_mediapath = rtmp; } // open/close std::error_condition open(std::string &&name); std::error_condition open(std::string &&name, u32 crc); std::error_condition open(std::string_view name) { return open(std::string(name)); } std::error_condition open(std::string_view name, u32 crc) { return open(std::string(name), crc); } std::error_condition open(const char *name) { return open(std::string(name)); } std::error_condition open(const char *name, u32 crc) { return open(std::string(name), crc); } std::error_condition open_next(); std::error_condition open_ram(const void *data, u32 length); void close(); // position std::error_condition seek(s64 offset, int whence); u64 tell(); bool eof(); u64 size(); // reading u32 read(void *buffer, u32 length); int getc(); int ungetc(int c); char *gets(char *s, int n); // writing u32 write(const void *buffer, u32 length); int puts(std::string_view s); int vprintf(util::format_argument_pack const &args); template int printf(Format &&fmt, Params &&...args) { return vprintf(util::make_format_argument_pack(std::forward(fmt), std::forward(args)...)); } // buffers void flush(); private: emu_file(u32 openflags, empty_t); emu_file(path_iterator &&searchpath, u32 openflags); template void set_searchpaths(T &&searchpath, u32 openflags) { m_iterator.emplace_back(searchpath, ""); m_mediapaths.emplace_back(std::forward(searchpath), ""); m_openflags = openflags; } template void set_searchpaths(T &&searchpath, U &&x, V &&y, W &&... z) { m_iterator.emplace_back(searchpath, ""); m_mediapaths.emplace_back(std::forward(searchpath), ""); set_searchpaths(std::forward(x), std::forward(y), std::forward(z)...); } bool part_of_mediapath(const std::string &path); std::error_condition compressed_file_ready(); // internal helpers std::error_condition attempt_zipped(); std::error_condition load_zipped_file(); // internal state std::string m_filename; // original filename provided std::string m_fullpath; // full filename util::core_file::ptr m_file; // core file pointer searchpath_vector m_iterator; // iterator for paths searchpath_vector m_mediapaths; // media-path iterator bool m_first; // true if this is the start of iteration u32 m_crc; // file's CRC u32 m_openflags; // flags we used for the open util::hash_collection m_hashes; // collection of hashes std::unique_ptr m_zipfile; // ZIP file pointer std::vector m_zipdata; // ZIP file data u64 m_ziplength; // ZIP file length bool m_remove_on_close; // flag: remove the file when closing int m_restrict_to_mediapath; // flag: restrict to paths inside the media-path }; extern template path_iterator::path_iterator(char *&, int); extern template path_iterator::path_iterator(char * const &, int); extern template path_iterator::path_iterator(char const *&, int); extern template path_iterator::path_iterator(char const * const &, int); extern template path_iterator::path_iterator(std::vector &, int); extern template path_iterator::path_iterator(const std::vector &, int); extern template emu_file::emu_file(std::string &, u32); extern template emu_file::emu_file(const std::string &, u32); extern template emu_file::emu_file(char *&, u32); extern template emu_file::emu_file(char * const &, u32); extern template emu_file::emu_file(char const *&, u32); extern template emu_file::emu_file(char const * const &, u32); extern template emu_file::emu_file(std::vector &, u32); extern template emu_file::emu_file(const std::vector &, u32); #endif // MAME_EMU_FILEIO_H