/* * mptStringBuffer.h * ----------------- * Purpose: Various functions for "fixing" char array strings for writing to or * reading from module files, or for securing char arrays in general. * 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/string/buffer.hpp" #include "mptString.h" #include #include #include OPENMPT_NAMESPACE_BEGIN namespace mpt { namespace String { enum ReadWriteMode : uint8 { // Reading / Writing: Standard null-terminated string handling. nullTerminated = 1, // Reading: Source string is not guaranteed to be null-terminated (if it fills the whole char array). // Writing: Destination string is not guaranteed to be null-terminated (if it fills the whole char array). maybeNullTerminated = 2, // Reading: String may contain null characters anywhere. They should be treated as spaces. // Writing: A space-padded string is written. spacePadded = 3, // Reading: String may contain null characters anywhere. The last character is ignored (it is supposed to be 0). // Writing: A space-padded string with a trailing null is written. spacePaddedNull = 4, }; namespace detail { std::string ReadStringBuffer(String::ReadWriteMode mode, const char *srcBuffer, std::size_t srcSize); void WriteStringBuffer(String::ReadWriteMode mode, char *destBuffer, const std::size_t destSize, const char *srcBuffer, const std::size_t srcSize); } // namespace detail } // namespace String namespace String { using mpt::ReadTypedBuf; using mpt::WriteTypedBuf; } // namespace String namespace String { using mpt::ReadAutoBuf; using mpt::WriteAutoBuf; } // namespace String template class StringModeBufRefImpl { private: Tchar * buf; std::size_t size; String::ReadWriteMode mode; public: // cppcheck false-positive // cppcheck-suppress uninitMemberVar StringModeBufRefImpl(Tchar * buf_, std::size_t size_, String::ReadWriteMode mode_) : buf(buf_) , size(size_) , mode(mode_) { static_assert(sizeof(Tchar) == 1); } StringModeBufRefImpl(const StringModeBufRefImpl &) = delete; StringModeBufRefImpl(StringModeBufRefImpl &&) = default; StringModeBufRefImpl & operator = (const StringModeBufRefImpl &) = delete; StringModeBufRefImpl & operator = (StringModeBufRefImpl &&) = delete; operator std::string () const { return String::detail::ReadStringBuffer(mode, buf, size); } bool empty() const { return String::detail::ReadStringBuffer(mode, buf, size).empty(); } StringModeBufRefImpl & operator = (const std::string & str) { String::detail::WriteStringBuffer(mode, buf, size, str.data(), str.size()); return *this; } }; template class StringModeBufRefImpl { private: const Tchar * buf; std::size_t size; String::ReadWriteMode mode; public: // cppcheck false-positive // cppcheck-suppress uninitMemberVar StringModeBufRefImpl(const Tchar * buf_, std::size_t size_, String::ReadWriteMode mode_) : buf(buf_) , size(size_) , mode(mode_) { static_assert(sizeof(Tchar) == 1); } StringModeBufRefImpl(const StringModeBufRefImpl &) = delete; StringModeBufRefImpl(StringModeBufRefImpl &&) = default; StringModeBufRefImpl & operator = (const StringModeBufRefImpl &) = delete; StringModeBufRefImpl & operator = (StringModeBufRefImpl &&) = delete; operator std::string () const { return String::detail::ReadStringBuffer(mode, buf, size); } bool empty() const { return String::detail::ReadStringBuffer(mode, buf, size).empty(); } }; namespace String { template inline StringModeBufRefImpl::type> ReadBuf(String::ReadWriteMode mode, const std::array &buf) { return StringModeBufRefImpl::type>(buf.data(), size, mode); } template inline StringModeBufRefImpl::type> ReadBuf(String::ReadWriteMode mode, const Tchar (&buf)[size]) { return StringModeBufRefImpl::type>(buf, size, mode); } template inline StringModeBufRefImpl::type> ReadBuf(String::ReadWriteMode mode, const Tchar * buf, std::size_t size) { return StringModeBufRefImpl::type>(buf, size, mode); } template inline StringModeBufRefImpl WriteBuf(String::ReadWriteMode mode, std::array &buf) { return StringModeBufRefImpl(buf.data(), size, mode); } template inline StringModeBufRefImpl WriteBuf(String::ReadWriteMode mode, Tchar (&buf)[size]) { return StringModeBufRefImpl(buf, size, mode); } template inline StringModeBufRefImpl WriteBuf(String::ReadWriteMode mode, Tchar * buf, std::size_t size) { return StringModeBufRefImpl(buf, size, mode); } } // namespace String template struct modecharbuf { public: using Tchar = char; using char_type = Tchar; using string_type = std::basic_string; public: Tchar buf[len]; public: modecharbuf() = default; modecharbuf(const modecharbuf &) = default; modecharbuf(modecharbuf &&) = default; modecharbuf & operator = (const modecharbuf &) = default; modecharbuf & operator = (modecharbuf &&) = default; operator string_type () const { return mpt::String::ReadBuf(mode, buf); } bool empty() const { return mpt::String::ReadBuf(mode, buf).empty(); } modecharbuf & operator = (const string_type & str) { mpt::String::WriteBuf(mode, buf) = str; return *this; } }; // see MPT_BINARY_STRUCT template constexpr bool declare_binary_safe(const typename mpt::modecharbuf &) { return true; } //struct is_binary_safe> : public std::true_type { }; static_assert(sizeof(mpt::modecharbuf<7, mpt::String::ReadWriteMode::nullTerminated>) == 7); static_assert(alignof(mpt::modecharbuf<7, mpt::String::ReadWriteMode::nullTerminated>) == 1); static_assert(std::is_standard_layout>::value); #ifdef MODPLUG_TRACKER #if MPT_OS_WINDOWS namespace String { using mpt::ReadWinBuf; using mpt::WriteWinBuf; } // namespace String #if defined(MPT_WITH_MFC) namespace String { using mpt::ReadCStringBuf; using mpt::WriteCStringBuf; } // namespace String #endif // MPT_WITH_MFC #endif // MPT_OS_WINDOWS #endif // MODPLUG_TRACKER namespace String { #if MPT_COMPILER_MSVC #pragma warning(push) #pragma warning(disable:4127) // conditional expression is constant #endif // MPT_COMPILER_MSVC // Sets last character to null in given char array. // Size of the array must be known at compile time. template void SetNullTerminator(char (&buffer)[size]) { static_assert(size > 0); buffer[size - 1] = 0; } inline void SetNullTerminator(char *buffer, size_t size) { MPT_ASSERT(size > 0); buffer[size - 1] = 0; } #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template void SetNullTerminator(wchar_t (&buffer)[size]) { static_assert(size > 0); buffer[size - 1] = 0; } inline void SetNullTerminator(wchar_t *buffer, size_t size) { MPT_ASSERT(size > 0); buffer[size - 1] = 0; } #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_COMPILER_MSVC #pragma warning(pop) #endif // MPT_COMPILER_MSVC } // namespace String } // namespace mpt OPENMPT_NAMESPACE_END template struct mpt::make_string_type> { using type = std::basic_string::type>; }; template struct mpt::make_string_view_type> { using type = std::basic_string_view::type>; }; template struct mpt::make_string_type> { using type = std::string; }; template struct mpt::make_string_view_type> { using type = std::string_view; };