|
|
@@ -1,11 +1,56 @@
|
|
|
#include "BsDataStream.h"
|
|
|
#include "BsDebug.h"
|
|
|
#include "BsException.h"
|
|
|
+#include <codecvt>
|
|
|
|
|
|
namespace BansheeEngine
|
|
|
{
|
|
|
const UINT32 DataStream::StreamTempSize = 128;
|
|
|
|
|
|
+ /**
|
|
|
+ * @brief Checks does the provided buffer has an UTF32 byte order mark
|
|
|
+ * in little endian order.
|
|
|
+ */
|
|
|
+ bool isUTF32LE(const UINT8* buffer)
|
|
|
+ {
|
|
|
+ return buffer[0] == 0xFF && buffer[1] == 0xFE && buffer[2] == 0x00 && buffer[3] == 0x00;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Checks does the provided buffer has an UTF32 byte order mark
|
|
|
+ * in big endian order.
|
|
|
+ */
|
|
|
+ bool isUTF32BE(const UINT8* buffer)
|
|
|
+ {
|
|
|
+ return buffer[0] == 0x00 && buffer[1] == 0x00 && buffer[2] == 0xFE && buffer[3] == 0xFF;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Checks does the provided buffer has an UTF16 byte order mark
|
|
|
+ * in little endian order.
|
|
|
+ */
|
|
|
+ bool isUTF16LE(const UINT8* buffer)
|
|
|
+ {
|
|
|
+ return buffer[0] == 0xFF && buffer[1] == 0xFE;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Checks does the provided buffer has an UTF16 byte order mark
|
|
|
+ * in big endian order.
|
|
|
+ */
|
|
|
+ bool isUTF16BE(const UINT8* buffer)
|
|
|
+ {
|
|
|
+ return buffer[0] == 0xFE && buffer[1] == 0xFF;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Checks does the provided buffer has an UTF8 byte order mark.
|
|
|
+ */
|
|
|
+ bool isUTF8(const UINT8* buffer)
|
|
|
+ {
|
|
|
+ return (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF);
|
|
|
+ }
|
|
|
+
|
|
|
template <typename T> DataStream& DataStream::operator>> (T& val)
|
|
|
{
|
|
|
read(static_cast<void*>(&val), sizeof(T));
|
|
|
@@ -18,11 +63,12 @@ namespace BansheeEngine
|
|
|
// Read the entire buffer - ideally in one read, but if the size of
|
|
|
// the buffer is unknown, do multiple fixed size reads.
|
|
|
size_t bufSize = (mSize > 0 ? mSize : 4096);
|
|
|
- StringStream::char_type* tempBuffer = (StringStream::char_type*)bs_alloc(bufSize);
|
|
|
+ std::stringstream::char_type* tempBuffer = (std::stringstream::char_type*)bs_alloc(bufSize);
|
|
|
|
|
|
// Ensure read from begin of stream
|
|
|
seek(0);
|
|
|
- StringStream result;
|
|
|
+
|
|
|
+ std::stringstream result;
|
|
|
while (!eof())
|
|
|
{
|
|
|
size_t numReadBytes = read(tempBuffer, bufSize);
|
|
|
@@ -30,7 +76,76 @@ namespace BansheeEngine
|
|
|
}
|
|
|
|
|
|
free(tempBuffer);
|
|
|
- return result.str();
|
|
|
+ std::string string = result.str();
|
|
|
+
|
|
|
+ UINT32 readBytes = (UINT32)string.size();
|
|
|
+ if (readBytes >= 4)
|
|
|
+ {
|
|
|
+ if (isUTF32LE((UINT8*)string.data()))
|
|
|
+ {
|
|
|
+ const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header | std::little_endian);
|
|
|
+ typedef std::codecvt_utf8<char32_t, 1114111, convMode> utf8utf32;
|
|
|
+
|
|
|
+ std::wstring_convert<utf8utf32, char32_t> conversion("?");
|
|
|
+ char32_t* start = (char32_t*)string.data();
|
|
|
+ char32_t* end = (start + (string.size() - 1) / 4);
|
|
|
+
|
|
|
+ return conversion.to_bytes(start, end).c_str();
|
|
|
+ }
|
|
|
+ else if (isUTF32BE((UINT8*)string.data()))
|
|
|
+ {
|
|
|
+ const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
|
|
|
+ typedef std::codecvt_utf8<char32_t, 1114111, convMode> utf8utf32;
|
|
|
+
|
|
|
+ std::wstring_convert<utf8utf32, char32_t> conversion("?");
|
|
|
+ char32_t* start = (char32_t*)string.data();
|
|
|
+ char32_t* end = (start + (string.size() - 1) / 4);
|
|
|
+
|
|
|
+ return conversion.to_bytes(start, end).c_str();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (readBytes >= 3)
|
|
|
+ {
|
|
|
+ if (isUTF8((UINT8*)string.data()))
|
|
|
+ {
|
|
|
+ return string.c_str() + 3;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (readBytes >= 2)
|
|
|
+ {
|
|
|
+ if (isUTF16LE((UINT8*)string.data()))
|
|
|
+ {
|
|
|
+ const std::codecvt_mode convMode = (std::codecvt_mode)(std::little_endian);
|
|
|
+ typedef std::codecvt_utf8<char16_t, 1114111, convMode> utf8utf16;
|
|
|
+
|
|
|
+ std::wstring_convert<utf8utf16, char16_t> conversion("?");
|
|
|
+ char16_t* start = (char16_t*)(string.data() + 2); // Bug?: std::consume_header seems to be ignored so I manually remove the header
|
|
|
+ char16_t* end = (start + (string.size() - 1) / 2);
|
|
|
+
|
|
|
+ return conversion.to_bytes(start, end).c_str();
|
|
|
+ }
|
|
|
+ else if (isUTF16BE((UINT8*)string.data()))
|
|
|
+ {
|
|
|
+ const std::codecvt_mode convMode = (std::codecvt_mode)(0);
|
|
|
+ typedef std::codecvt_utf8<char16_t, 1114111, convMode> utf8utf16;
|
|
|
+
|
|
|
+ // Bug?: Regardless me of not providing the std::little_endian flag it seems that is how the data is read
|
|
|
+ // so I manually flip it
|
|
|
+ UINT32 numChars = (string.size() - 2) / 2;
|
|
|
+ for (UINT32 i = 0; i < numChars; i++)
|
|
|
+ std::swap(string[i * 2 + 0], string[i * 2 + 1]);
|
|
|
+
|
|
|
+ std::wstring_convert<utf8utf16, char16_t> conversion("?");
|
|
|
+ char16_t* start = (char16_t*)(string.data() + 2); // Bug?: std::consume_header seems to be ignored so I manually remove the header
|
|
|
+ char16_t* end = (start + (string.size() - 1) / 2);
|
|
|
+
|
|
|
+ return conversion.to_bytes(start, end).c_str();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return string.c_str();
|
|
|
}
|
|
|
|
|
|
WString DataStream::getAsWString()
|
|
|
@@ -38,11 +153,12 @@ namespace BansheeEngine
|
|
|
// Read the entire buffer - ideally in one read, but if the size of
|
|
|
// the buffer is unknown, do multiple fixed size reads.
|
|
|
size_t bufSize = (mSize > 0 ? mSize : 4096);
|
|
|
- WStringStream::char_type* tempBuffer = (WStringStream::char_type*)bs_alloc(bufSize);
|
|
|
+ std::stringstream::char_type* tempBuffer = (std::stringstream::char_type*)bs_alloc(bufSize);
|
|
|
|
|
|
// Ensure read from begin of stream
|
|
|
seek(0);
|
|
|
- WStringStream result;
|
|
|
+
|
|
|
+ std::stringstream result;
|
|
|
while (!eof())
|
|
|
{
|
|
|
size_t numReadBytes = read(tempBuffer, bufSize);
|
|
|
@@ -50,7 +166,60 @@ namespace BansheeEngine
|
|
|
}
|
|
|
|
|
|
free(tempBuffer);
|
|
|
- return result.str();
|
|
|
+ std::string string = result.str();
|
|
|
+
|
|
|
+ UINT32 readBytes = (UINT32)string.size();
|
|
|
+ if (readBytes >= 4)
|
|
|
+ {
|
|
|
+ if (isUTF32LE((UINT8*)string.data()))
|
|
|
+ {
|
|
|
+ // Not supported
|
|
|
+ }
|
|
|
+ else if (isUTF32BE((UINT8*)string.data()))
|
|
|
+ {
|
|
|
+ // Not supported
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (readBytes >= 3)
|
|
|
+ {
|
|
|
+ if (isUTF8((UINT8*)string.data()))
|
|
|
+ {
|
|
|
+ const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
|
|
|
+ typedef std::codecvt_utf8<wchar_t, 1114111, convMode> wcharutf8;
|
|
|
+
|
|
|
+ std::wstring_convert<wcharutf8> conversion("?");
|
|
|
+ return conversion.from_bytes(string).c_str();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (readBytes >= 2)
|
|
|
+ {
|
|
|
+ if (isUTF16LE((UINT8*)string.data()))
|
|
|
+ {
|
|
|
+ const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header | std::little_endian);
|
|
|
+ typedef std::codecvt_utf16 <wchar_t, 1114111, convMode> wcharutf16;
|
|
|
+
|
|
|
+ std::wstring_convert<wcharutf16> conversion("?");
|
|
|
+ return conversion.from_bytes(string).c_str();
|
|
|
+ }
|
|
|
+ else if (isUTF16BE((UINT8*)string.data()))
|
|
|
+ {
|
|
|
+ const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
|
|
|
+ typedef std::codecvt_utf16<wchar_t, 1114111, convMode> wcharutf16;
|
|
|
+
|
|
|
+ std::wstring_convert<wcharutf16> conversion("?");
|
|
|
+ return conversion.from_bytes(string).c_str();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
|
|
|
+ typedef std::codecvt_utf8<wchar_t, 1114111, convMode> wcharutf8;
|
|
|
+
|
|
|
+ std::wstring_convert<wcharutf8> conversion("?");
|
|
|
+ return conversion.from_bytes(string).c_str();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
MemoryDataStream::MemoryDataStream(void* memory, size_t inSize)
|