/* * FileReader.h * ------------ * Purpose: A basic class for transparent reading of memory-based files. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/io_read/filecursor.hpp" #include "mpt/io_read/filecursor_filename_traits.hpp" #include "mpt/io_read/filecursor_traits_filedata.hpp" #include "mpt/io_read/filecursor_traits_memory.hpp" #include "mpt/io_read/filereader.hpp" #include "openmpt/base/Types.hpp" #include "mptPathString.h" #include "mptStringBuffer.h" #include #include #include #include #include #include #include #include "FileReaderFwd.h" OPENMPT_NAMESPACE_BEGIN namespace FileReaderExt { // Read a string of length srcSize into fixed-length char array destBuffer using a given read mode. // The file cursor is advanced by "srcSize" bytes. // Returns true if at least one byte could be read or 0 bytes were requested. template bool ReadString(TFileCursor &f, char (&destBuffer)[destSize], const typename TFileCursor::pos_type srcSize) { typename TFileCursor::PinnedView source = f.ReadPinnedView(srcSize); // Make sure the string is cached properly. typename TFileCursor::pos_type realSrcSize = source.size(); // In case fewer bytes are available mpt::String::WriteAutoBuf(destBuffer) = mpt::String::ReadBuf(mode, mpt::byte_cast(source.data()), realSrcSize); return (realSrcSize > 0 || srcSize == 0); } // Read a string of length srcSize into a std::string dest using a given read mode. // The file cursor is advanced by "srcSize" bytes. // Returns true if at least one character could be read or 0 characters were requested. template bool ReadString(TFileCursor &f, std::string &dest, const typename TFileCursor::pos_type srcSize) { dest.clear(); typename TFileCursor::PinnedView source = f.ReadPinnedView(srcSize); // Make sure the string is cached properly. typename TFileCursor::pos_type realSrcSize = source.size(); // In case fewer bytes are available dest = mpt::String::ReadBuf(mode, mpt::byte_cast(source.data()), realSrcSize); return (realSrcSize > 0 || srcSize == 0); } // Read a string of length srcSize into a mpt::charbuf dest using a given read mode. // The file cursor is advanced by "srcSize" bytes. // Returns true if at least one character could be read or 0 characters were requested. template bool ReadString(TFileCursor &f, mpt::charbuf &dest, const typename TFileCursor::pos_type srcSize) { typename TFileCursor::PinnedView source = f.ReadPinnedView(srcSize); // Make sure the string is cached properly. typename TFileCursor::pos_type realSrcSize = source.size(); // In case fewer bytes are available dest = mpt::String::ReadBuf(mode, mpt::byte_cast(source.data()), realSrcSize); return (realSrcSize > 0 || srcSize == 0); } // Read a charset encoded string of length srcSize into a mpt::ustring dest using a given read mode. // The file cursor is advanced by "srcSize" bytes. // Returns true if at least one character could be read or 0 characters were requested. template bool ReadString(TFileCursor &f, mpt::ustring &dest, mpt::Charset charset, const typename TFileCursor::pos_type srcSize) { dest.clear(); typename TFileCursor::PinnedView source = f.ReadPinnedView(srcSize); // Make sure the string is cached properly. typename TFileCursor::pos_type realSrcSize = source.size(); // In case fewer bytes are available dest = mpt::ToUnicode(charset, mpt::String::ReadBuf(mode, mpt::byte_cast(source.data()), realSrcSize)); return (realSrcSize > 0 || srcSize == 0); } // Read a string with a preprended length field of type Tsize (must be a packed<*,*> type) into a std::string dest using a given read mode. // The file cursor is advanced by the string length. // Returns true if the size field could be read and at least one character could be read or 0 characters were requested. template bool ReadSizedString(TFileCursor &f, char (&destBuffer)[destSize], const typename TFileCursor::pos_type maxLength = std::numeric_limits::max()) { static_assert(mpt::is_binary_safe::value); Tsize srcSize; if(!mpt::IO::FileReader::Read(f, srcSize)) { return false; } return FileReaderExt::ReadString(f, destBuffer, std::min(static_cast(srcSize), maxLength)); } // Read a string with a preprended length field of type Tsize (must be a packed<*,*> type) into a std::string dest using a given read mode. // The file cursor is advanced by the string length. // Returns true if the size field could be read and at least one character could be read or 0 characters were requested. template bool ReadSizedString(TFileCursor &f, std::string &dest, const typename TFileCursor::pos_type maxLength = std::numeric_limits::max()) { static_assert(mpt::is_binary_safe::value); Tsize srcSize; if(!mpt::IO::FileReader::Read(f, srcSize)) { return false; } return FileReaderExt::ReadString(f, dest, std::min(static_cast(srcSize), maxLength)); } // Read a string with a preprended length field of type Tsize (must be a packed<*,*> type) into a mpt::charbuf dest using a given read mode. // The file cursor is advanced by the string length. // Returns true if the size field could be read and at least one character could be read or 0 characters were requested. template bool ReadSizedString(TFileCursor &f, mpt::charbuf &dest, const typename TFileCursor::pos_type maxLength = std::numeric_limits::max()) { static_assert(mpt::is_binary_safe::value); Tsize srcSize; if(!mpt::IO::FileReader::Read(f, srcSize)) { return false; } return FileReaderExt::ReadString(f, dest, std::min(static_cast(srcSize), maxLength)); } } // namespace FileReaderExt namespace detail { template using FileCursor = mpt::IO::FileCursor; template class FileReader : public FileCursor { private: using traits_type = Ttraits; using filename_traits_type = Tfilenametraits; public: using pos_type = typename traits_type::pos_type; using off_t = pos_type; using data_type = typename traits_type::data_type; using ref_data_type = typename traits_type::ref_data_type; using shared_data_type = typename traits_type::shared_data_type; using value_data_type = typename traits_type::value_data_type; using shared_filename_type = typename filename_traits_type::shared_filename_type; public: // Initialize invalid file reader object. FileReader() { return; } FileReader(const FileCursor &other) : FileCursor(other) { return; } FileReader(FileCursor &&other) : FileCursor(std::move(other)) { return; } // Initialize file reader object with pointer to data and data length. template explicit FileReader(mpt::span bytedata, shared_filename_type filename = shared_filename_type{}) : FileCursor(bytedata, std::move(filename)) { return; } // Initialize file reader object based on an existing file reader object window. explicit FileReader(value_data_type other, shared_filename_type filename = shared_filename_type{}) : FileCursor(std::move(other), std::move(filename)) { return; } public: template bool Read(T &target) { return mpt::IO::FileReader::Read(*this, target); } template T ReadIntLE() { return mpt::IO::FileReader::ReadIntLE(*this); } template T ReadIntBE() { return mpt::IO::FileReader::ReadIntLE(*this); } template T ReadTruncatedIntLE(pos_type size) { return mpt::IO::FileReader::ReadTruncatedIntLE(*this, size); } template T ReadSizedIntLE(pos_type size) { return mpt::IO::FileReader::ReadSizedIntLE(*this, size); } uint32 ReadUint32LE() { return mpt::IO::FileReader::ReadUint32LE(*this); } uint32 ReadUint32BE() { return mpt::IO::FileReader::ReadUint32BE(*this); } int32 ReadInt32LE() { return mpt::IO::FileReader::ReadInt32LE(*this); } int32 ReadInt32BE() { return mpt::IO::FileReader::ReadInt32BE(*this); } uint32 ReadUint24LE() { return mpt::IO::FileReader::ReadUint24LE(*this); } uint32 ReadUint24BE() { return mpt::IO::FileReader::ReadUint24BE(*this); } uint16 ReadUint16LE() { return mpt::IO::FileReader::ReadUint16LE(*this); } uint16 ReadUint16BE() { return mpt::IO::FileReader::ReadUint16BE(*this); } int16 ReadInt16LE() { return mpt::IO::FileReader::ReadInt16LE(*this); } int16 ReadInt16BE() { return mpt::IO::FileReader::ReadInt16BE(*this); } char ReadChar() { return mpt::IO::FileReader::ReadChar(*this); } uint8 ReadUint8() { return mpt::IO::FileReader::ReadUint8(*this); } int8 ReadInt8() { return mpt::IO::FileReader::ReadInt8(*this); } float ReadFloatLE() { return mpt::IO::FileReader::ReadFloatLE(*this); } float ReadFloatBE() { return mpt::IO::FileReader::ReadFloatBE(*this); } double ReadDoubleLE() { return mpt::IO::FileReader::ReadDoubleLE(*this); } double ReadDoubleBE() { return mpt::IO::FileReader::ReadDoubleBE(*this); } template bool ReadStruct(T &target) { return mpt::IO::FileReader::ReadStruct(*this, target); } template size_t ReadStructPartial(T &target, size_t partialSize = sizeof(T)) { return mpt::IO::FileReader::ReadStructPartial(*this, target, partialSize); } bool ReadNullString(std::string &dest, const pos_type maxLength = std::numeric_limits::max()) { return mpt::IO::FileReader::ReadNullString(*this, dest, maxLength); } bool ReadLine(std::string &dest, const pos_type maxLength = std::numeric_limits::max()) { return mpt::IO::FileReader::ReadLine(*this, dest, maxLength); } template bool ReadArray(T (&destArray)[destSize]) { return mpt::IO::FileReader::ReadArray(*this, destArray); } template bool ReadArray(std::array &destArray) { return mpt::IO::FileReader::ReadArray(*this, destArray); } template std::array ReadArray() { return mpt::IO::FileReader::ReadArray(*this); } template bool ReadVector(std::vector &destVector, size_t destSize) { return mpt::IO::FileReader::ReadVector(*this, destVector, destSize); } template bool ReadMagic(const char (&magic)[N]) { return mpt::IO::FileReader::ReadMagic(*this, magic); } template bool ReadVarInt(T &target) { return mpt::IO::FileReader::ReadVarInt(*this, target); } template using Item = mpt::IO::FileReader::Chunk; template using ChunkList = mpt::IO::FileReader::ChunkList; template Item ReadNextChunk(off_t alignment) { return mpt::IO::FileReader::ReadNextChunk(*this, alignment); } template ChunkList ReadChunks(off_t alignment) { return mpt::IO::FileReader::ReadChunks(*this, alignment); } template ChunkList ReadChunksUntil(off_t alignment, decltype(T().GetID()) stopAtID) { return mpt::IO::FileReader::ReadChunksUntil(*this, alignment, stopAtID); } template bool ReadString(char (&destBuffer)[destSize], const pos_type srcSize) { return FileReaderExt::ReadString(*this, destBuffer, srcSize); } template bool ReadString(std::string &dest, const pos_type srcSize) { return FileReaderExt::ReadString(*this, dest, srcSize); } template bool ReadString(mpt::charbuf &dest, const pos_type srcSize) { return FileReaderExt::ReadString(*this, dest, srcSize); } template bool ReadString(mpt::ustring &dest, mpt::Charset charset, const pos_type srcSize) { return FileReaderExt::ReadString(*this, dest, charset, srcSize); } template bool ReadSizedString(char (&destBuffer)[destSize], const pos_type maxLength = std::numeric_limits::max()) { return FileReaderExt::ReadSizedString(*this, destBuffer, maxLength); } template bool ReadSizedString(std::string &dest, const pos_type maxLength = std::numeric_limits::max()) { return FileReaderExt::ReadSizedString(*this, dest, maxLength); } template bool ReadSizedString(mpt::charbuf &dest, const pos_type maxLength = std::numeric_limits::max()) { return FileReaderExt::ReadSizedString(*this, dest, maxLength); } }; } // namespace detail using FileCursor = detail::FileCursor>; using FileReader = detail::FileReader>; using ChunkReader = FileReader; using MemoryFileCursor = detail::FileCursor; using MemoryFileReader = detail::FileReader; OPENMPT_NAMESPACE_END