#pragma once
#include "BuildSettings.h"
#include "mptString.h"
#include <algorithm>
#include <string>
#include <vector>
OPENMPT_NAMESPACE_BEGIN
namespace mpt
{
namespace String
{
enum ReadWriteMode
{
nullTerminated,
maybeNullTerminated,
spacePadded,
spacePaddedNull
};
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);
}
}
template <typename Tstring, typename Tchar>
class StringBufRefImpl
{
private:
Tchar * buf;
std::size_t size;
public:
explicit StringBufRefImpl(Tchar * buf, std::size_t size)
: buf(buf)
, size(size)
{
MPT_STATIC_ASSERT(sizeof(Tchar) == sizeof(typename Tstring::value_type));
MPT_ASSERT(size > 0);
}
StringBufRefImpl(const StringBufRefImpl &) = delete;
StringBufRefImpl(StringBufRefImpl &&) = default;
StringBufRefImpl & operator = (const StringBufRefImpl &) = delete;
StringBufRefImpl & operator = (StringBufRefImpl &&) = delete;
operator Tstring () const
{
std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; return Tstring(buf, buf + len);
}
StringBufRefImpl & operator = (const Tstring & str)
{
std::fill(buf, buf + size, Tchar('\0'));
std::copy(str.data(), str.data() + std::min(str.length(), size - 1), buf);
std::fill(buf + std::min(str.length(), size - 1), buf + size, Tchar('\0'));
return *this;
}
};
template <typename Tstring, typename Tchar>
class StringBufRefImpl<Tstring, const Tchar>
{
private:
const Tchar * buf;
std::size_t size;
public:
explicit StringBufRefImpl(const Tchar * buf, std::size_t size)
: buf(buf)
, size(size)
{
MPT_STATIC_ASSERT(sizeof(Tchar) == sizeof(typename Tstring::value_type));
MPT_ASSERT(size > 0);
}
StringBufRefImpl(const StringBufRefImpl &) = delete;
StringBufRefImpl(StringBufRefImpl &&) = default;
StringBufRefImpl & operator = (const StringBufRefImpl &) = delete;
StringBufRefImpl & operator = (StringBufRefImpl &&) = delete;
operator Tstring () const
{
std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; return Tstring(buf, buf + len);
}
};
namespace String {
template <typename Tstring, typename Tchar, std::size_t size>
inline StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type> ReadTypedBuf(Tchar (&buf)[size])
{
return StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type>(buf, size);
}
template <typename Tstring, typename Tchar>
inline StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type> ReadTypedBuf(Tchar * buf, std::size_t size)
{
return StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type>(buf, size);
}
template <typename Tstring, typename Tchar, std::size_t size>
inline StringBufRefImpl<Tstring, Tchar> WriteTypedBuf(Tchar (&buf)[size])
{
return StringBufRefImpl<Tstring, Tchar>(buf, size);
}
template <typename Tstring, typename Tchar>
inline StringBufRefImpl<Tstring, Tchar> WriteTypedBuf(Tchar * buf, std::size_t size)
{
return StringBufRefImpl<Tstring, Tchar>(buf, size);
}
}
namespace String {
template <typename Tchar, std::size_t size>
inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type> ReadAutoBuf(Tchar (&buf)[size])
{
return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type>(buf, size);
}
template <typename Tchar>
inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type> ReadAutoBuf(Tchar * buf, std::size_t size)
{
return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type>(buf, size);
}
template <typename Tchar, std::size_t size>
inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar> WriteAutoBuf(Tchar (&buf)[size])
{
return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar>(buf, size);
}
template <typename Tchar>
inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar> WriteAutoBuf(Tchar * buf, std::size_t size)
{
return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar>(buf, size);
}
}
template <typename Tchar>
class StringModeBufRefImpl
{
private:
Tchar * buf;
std::size_t size;
String::ReadWriteMode mode;
public:
StringModeBufRefImpl(Tchar * buf, std::size_t size, String::ReadWriteMode mode)
: buf(buf)
, size(size)
, mode(mode)
{
MPT_STATIC_ASSERT(sizeof(Tchar) == 1);
MPT_ASSERT(size > 0);
}
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);
}
StringModeBufRefImpl & operator = (const std::string & str)
{
String::detail::WriteStringBuffer(mode, buf, size, str.data(), str.size());
return *this;
}
};
template <typename Tchar>
class StringModeBufRefImpl<const Tchar>
{
private:
const Tchar * buf;
std::size_t size;
String::ReadWriteMode mode;
public:
StringModeBufRefImpl(const Tchar * buf, std::size_t size, String::ReadWriteMode mode)
: buf(buf)
, size(size)
, mode(mode)
{
MPT_STATIC_ASSERT(sizeof(Tchar) == 1);
MPT_ASSERT(size > 0);
}
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);
}
};
namespace String {
template <typename Tchar, std::size_t size>
inline StringModeBufRefImpl<typename std::add_const<Tchar>::type> ReadBuf(String::ReadWriteMode mode, Tchar (&buf)[size])
{
return StringModeBufRefImpl<typename std::add_const<Tchar>::type>(buf, size, mode);
}
template <typename Tchar>
inline StringModeBufRefImpl<typename std::add_const<Tchar>::type> ReadBuf(String::ReadWriteMode mode, Tchar * buf, std::size_t size)
{
return StringModeBufRefImpl<typename std::add_const<Tchar>::type>(buf, size, mode);
}
template <typename Tchar, std::size_t size>
inline StringModeBufRefImpl<Tchar> WriteBuf(String::ReadWriteMode mode, Tchar (&buf)[size])
{
return StringModeBufRefImpl<Tchar>(buf, size, mode);
}
template <typename Tchar>
inline StringModeBufRefImpl<Tchar> WriteBuf(String::ReadWriteMode mode, Tchar * buf, std::size_t size)
{
return StringModeBufRefImpl<Tchar>(buf, size, mode);
}
}
#ifdef MODPLUG_TRACKER
#if MPT_OS_WINDOWS
namespace String {
template <typename Tchar, std::size_t size>
inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type> ReadWinBuf(Tchar (&buf)[size])
{
return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type>(buf, size);
}
template <typename Tchar>
inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type> ReadWinBuf(Tchar * buf, std::size_t size)
{
return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type>(buf, size);
}
template <typename Tchar, std::size_t size>
inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar> WriteWinBuf(Tchar (&buf)[size])
{
return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar>(buf, size);
}
template <typename Tchar>
inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar> WriteWinBuf(Tchar * buf, std::size_t size)
{
return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar>(buf, size);
}
}
#if defined(_MFC_VER)
template <typename Tchar>
class CStringBufRefImpl
{
private:
Tchar * buf;
std::size_t size;
public:
explicit CStringBufRefImpl(Tchar * buf, std::size_t size)
: buf(buf)
, size(size)
{
MPT_ASSERT(size > 0);
}
CStringBufRefImpl(const CStringBufRefImpl &) = delete;
CStringBufRefImpl(CStringBufRefImpl &&) = default;
CStringBufRefImpl & operator = (const CStringBufRefImpl &) = delete;
CStringBufRefImpl & operator = (CStringBufRefImpl &&) = delete;
operator CString () const
{
std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; return CString(buf, mpt::saturate_cast<int>(len));
}
CStringBufRefImpl & operator = (const CString & str)
{
std::fill(buf, buf + size, Tchar('\0'));
std::copy(str.GetString(), str.GetString() + std::min(static_cast<std::size_t>(str.GetLength()), size - 1), buf);
buf[size - 1] = Tchar('\0');
return *this;
}
};
template <typename Tchar>
class CStringBufRefImpl<const Tchar>
{
private:
const Tchar * buf;
std::size_t size;
public:
explicit CStringBufRefImpl(const Tchar * buf, std::size_t size)
: buf(buf)
, size(size)
{
MPT_ASSERT(size > 0);
}
CStringBufRefImpl(const CStringBufRefImpl &) = delete;
CStringBufRefImpl(CStringBufRefImpl &&) = default;
CStringBufRefImpl & operator = (const CStringBufRefImpl &) = delete;
CStringBufRefImpl & operator = (CStringBufRefImpl &&) = delete;
operator CString () const
{
std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; return CString(buf, mpt::saturate_cast<int>(len));
}
};
namespace String {
template <typename Tchar, std::size_t size>
inline CStringBufRefImpl<typename std::add_const<Tchar>::type> ReadCStringBuf(Tchar (&buf)[size])
{
return CStringBufRefImpl<typename std::add_const<Tchar>::type>(buf, size);
}
template <typename Tchar>
inline CStringBufRefImpl<typename std::add_const<Tchar>::type> ReadCStringBuf(Tchar * buf, std::size_t size)
{
return CStringBufRefImpl<typename std::add_const<Tchar>::type>(buf, size);
}
template <typename Tchar, std::size_t size>
inline CStringBufRefImpl<Tchar> WriteCStringBuf(Tchar (&buf)[size])
{
return CStringBufRefImpl<Tchar>(buf, size);
}
template <typename Tchar>
inline CStringBufRefImpl<Tchar> WriteCStringBuf(Tchar * buf, std::size_t size)
{
return CStringBufRefImpl<Tchar>(buf, size);
}
}
#endif
#endif
#endif
namespace String
{
#if MPT_COMPILER_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
template <size_t size>
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;
}
template <size_t size>
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;
}
template <size_t size>
void FixNullString(char (&buffer)[size])
{
STATIC_ASSERT(size > 0);
SetNullTerminator(buffer);
size_t pos = 0;
while(pos < size && buffer[pos] != '\0')
{
pos++;
}
while(pos < size)
{
buffer[pos++] = '\0';
}
}
inline void FixNullString(std::string & str)
{
for(std::size_t i = 0; i < str.length(); ++i)
{
if(str[i] == '\0')
{
str.resize(i);
break;
}
}
}
template <ReadWriteMode mode, typename Tbyte>
void Read(std::string &dest, const Tbyte *srcBuffer, size_t srcSize)
{
const char *src = mpt::byte_cast<const char*>(srcBuffer);
dest.clear();
try
{
dest = mpt::String::detail::ReadStringBuffer(mode, src, srcSize);
} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
{
MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
}
}
template <ReadWriteMode mode, typename Tbyte>
void Read(mpt::ustring &dest, mpt::Charset charset, const Tbyte *srcBuffer, size_t srcSize)
{
std::string tmp;
Read<mode>(tmp, srcBuffer, srcSize);
dest = mpt::ToUnicode(charset, tmp);
}
template <ReadWriteMode mode, size_t srcSize, typename Tbyte>
void Read(std::string &dest, const Tbyte (&srcBuffer)[srcSize])
{
STATIC_ASSERT(srcSize > 0);
Read<mode>(dest, srcBuffer, srcSize);
}
template <ReadWriteMode mode, size_t srcSize, typename Tbyte>
void Read(mpt::ustring &dest, mpt::Charset charset, const Tbyte(&srcBuffer)[srcSize])
{
std::string tmp;
Read<mode>(tmp, srcBuffer);
dest = mpt::ToUnicode(charset, tmp);
}
template <ReadWriteMode mode, size_t destSize, typename Tbyte>
void Read(char (&destBuffer)[destSize], const Tbyte *srcBuffer, size_t srcSize)
{
STATIC_ASSERT(destSize > 0);
char *dst = destBuffer;
const char *src = mpt::byte_cast<const char*>(srcBuffer);
if(mode == nullTerminated || mode == spacePaddedNull)
{
if(srcSize > 0)
{
srcSize -= 1;
}
}
if(mode == nullTerminated || mode == maybeNullTerminated)
{
dst = std::copy(src, std::find(src, src + std::min(srcSize, destSize - 1), '\0'), dst);
} else if(mode == spacePadded || mode == spacePaddedNull)
{
std::size_t lengthWithoutNullOrSpace = 0;
for(std::size_t pos = 0; pos < srcSize; ++pos)
{
char c = srcBuffer[pos];
if(c != '\0' && c != ' ')
{
lengthWithoutNullOrSpace = pos + 1;
}
if(c == '\0')
{
c = ' ';
}
if(pos < destSize - 1)
{
destBuffer[pos] = c;
}
}
std::size_t destLength = std::min(lengthWithoutNullOrSpace, destSize - 1);
dst += destLength;
}
std::fill(dst, destBuffer + destSize, '\0');
}
template <ReadWriteMode mode, size_t destSize, size_t srcSize, typename Tbyte>
void Read(char (&destBuffer)[destSize], const Tbyte (&srcBuffer)[srcSize])
{
STATIC_ASSERT(destSize > 0);
STATIC_ASSERT(srcSize > 0);
Read<mode, destSize>(destBuffer, srcBuffer, srcSize);
}
template <ReadWriteMode mode>
void Write(char *destBuffer, const size_t destSize, const char *srcBuffer, const size_t srcSize)
{
MPT_ASSERT(destSize > 0);
mpt::String::detail::WriteStringBuffer(mode, destBuffer, destSize, srcBuffer, srcSize);
}
template <ReadWriteMode mode>
void Write(std::vector<char> &destBuffer, const char *srcBuffer, const size_t srcSize)
{
MPT_ASSERT(destBuffer.size() > 0);
Write<mode>(destBuffer.data(), destBuffer.size(), srcBuffer, srcSize);
}
template <ReadWriteMode mode, size_t destSize>
void Write(char (&destBuffer)[destSize], const char *srcBuffer, const size_t srcSize)
{
STATIC_ASSERT(destSize > 0);
Write<mode>(destBuffer, destSize, srcBuffer, srcSize);
}
template <ReadWriteMode mode, size_t destSize, size_t srcSize>
void Write(char (&destBuffer)[destSize], const char (&srcBuffer)[srcSize])
{
STATIC_ASSERT(destSize > 0);
STATIC_ASSERT(srcSize > 0);
Write<mode, destSize>(destBuffer, srcBuffer, srcSize);
}
template <ReadWriteMode mode>
void Write(char *destBuffer, const size_t destSize, const std::string &src)
{
MPT_ASSERT(destSize > 0);
Write<mode>(destBuffer, destSize, src.c_str(), src.length());
}
template <ReadWriteMode mode>
void Write(std::vector<char> &destBuffer, const std::string &src)
{
MPT_ASSERT(destBuffer.size() > 0);
Write<mode>(destBuffer, src.c_str(), src.length());
}
template <ReadWriteMode mode, size_t destSize>
void Write(char (&destBuffer)[destSize], const std::string &src)
{
STATIC_ASSERT(destSize > 0);
Write<mode, destSize>(destBuffer, src.c_str(), src.length());
}
template <size_t destSize>
void CopyN(char (&destBuffer)[destSize], const char *srcBuffer, const size_t srcSize = std::numeric_limits<size_t>::max())
{
const size_t copySize = std::min(destSize - 1u, srcSize);
std::strncpy(destBuffer, srcBuffer, copySize);
destBuffer[copySize] = '\0';
}
static inline void CopyN(std::string &dest, const char *srcBuffer, const size_t srcSize = std::numeric_limits<size_t>::max())
{
dest.assign(srcBuffer, srcBuffer + mpt::strnlen(srcBuffer, srcSize));
}
template <size_t destSize, size_t srcSize>
void Copy(char (&destBuffer)[destSize], const char (&srcBuffer)[srcSize])
{
CopyN(destBuffer, srcBuffer, srcSize);
}
template <size_t destSize>
void Copy(char (&destBuffer)[destSize], const std::string &src)
{
CopyN(destBuffer, src.c_str(), src.length());
}
template <size_t srcSize>
void Copy(std::string &dest, const char (&srcBuffer)[srcSize])
{
CopyN(dest, srcBuffer, srcSize);
}
static inline void Copy(std::string &dest, const std::string &src)
{
dest.assign(src);
}
#if MPT_COMPILER_MSVC
#pragma warning(pop)
#endif
}
}
OPENMPT_NAMESPACE_END