BsDataStream.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsDataStream.h"
  4. #include "BsDebug.h"
  5. #include <codecvt>
  6. namespace bs
  7. {
  8. const UINT32 DataStream::StreamTempSize = 128;
  9. /** Checks does the provided buffer has an UTF32 byte order mark in little endian order. */
  10. bool isUTF32LE(const UINT8* buffer)
  11. {
  12. return buffer[0] == 0xFF && buffer[1] == 0xFE && buffer[2] == 0x00 && buffer[3] == 0x00;
  13. }
  14. /** Checks does the provided buffer has an UTF32 byte order mark in big endian order. */
  15. bool isUTF32BE(const UINT8* buffer)
  16. {
  17. return buffer[0] == 0x00 && buffer[1] == 0x00 && buffer[2] == 0xFE && buffer[3] == 0xFF;
  18. }
  19. /** Checks does the provided buffer has an UTF16 byte order mark in little endian order. */
  20. bool isUTF16LE(const UINT8* buffer)
  21. {
  22. return buffer[0] == 0xFF && buffer[1] == 0xFE;
  23. }
  24. /** Checks does the provided buffer has an UTF16 byte order mark in big endian order. */
  25. bool isUTF16BE(const UINT8* buffer)
  26. {
  27. return buffer[0] == 0xFE && buffer[1] == 0xFF;
  28. }
  29. /** Checks does the provided buffer has an UTF8 byte order mark. */
  30. bool isUTF8(const UINT8* buffer)
  31. {
  32. return (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF);
  33. }
  34. template <typename T> DataStream& DataStream::operator>> (T& val)
  35. {
  36. read(static_cast<void*>(&val), sizeof(T));
  37. return *this;
  38. }
  39. void DataStream::writeString(const String& string, StringEncoding encoding)
  40. {
  41. if (encoding == StringEncoding::UTF16)
  42. {
  43. const std::codecvt_mode convMode = (std::codecvt_mode)(std::generate_header);
  44. typedef std::codecvt_utf8_utf16<char, 1114111, convMode> UTF8ToUTF16Conv;
  45. std::wstring_convert<UTF8ToUTF16Conv, char> conversion("?");
  46. std::string encodedString = conversion.from_bytes(string.c_str());
  47. write(encodedString.data(), encodedString.length());
  48. }
  49. else
  50. {
  51. write(string.data(), string.length());
  52. }
  53. }
  54. void DataStream::writeString(const WString& string, StringEncoding encoding)
  55. {
  56. if (encoding == StringEncoding::UTF16)
  57. {
  58. const std::codecvt_mode convMode = (std::codecvt_mode)(std::generate_header | std::little_endian);
  59. typedef std::codecvt_utf16<wchar_t, 1114111, convMode> WCharToUTF16Conv;
  60. std::wstring_convert<WCharToUTF16Conv, wchar_t> conversion("?");
  61. std::string encodedString = conversion.to_bytes(string.c_str());
  62. write(encodedString.data(), encodedString.length());
  63. }
  64. else
  65. {
  66. const std::codecvt_mode convMode = (std::codecvt_mode)(std::generate_header);
  67. typedef std::codecvt_utf8<wchar_t, 1114111, convMode> WCharToUTF8Conv;
  68. std::wstring_convert<WCharToUTF8Conv, wchar_t> conversion("?");
  69. std::string encodedString = conversion.to_bytes(string.c_str());
  70. write(encodedString.data(), encodedString.length());
  71. }
  72. }
  73. String DataStream::getAsString()
  74. {
  75. // Read the entire buffer - ideally in one read, but if the size of
  76. // the buffer is unknown, do multiple fixed size reads.
  77. size_t bufSize = (mSize > 0 ? mSize : 4096);
  78. std::stringstream::char_type* tempBuffer = (std::stringstream::char_type*)bs_alloc((UINT32)bufSize);
  79. // Ensure read from begin of stream
  80. seek(0);
  81. std::stringstream result;
  82. while (!eof())
  83. {
  84. size_t numReadBytes = read(tempBuffer, bufSize);
  85. result.write(tempBuffer, numReadBytes);
  86. }
  87. free(tempBuffer);
  88. std::string string = result.str();
  89. UINT32 readBytes = (UINT32)string.size();
  90. if (readBytes >= 4)
  91. {
  92. if (isUTF32LE((UINT8*)string.data()))
  93. {
  94. const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header | std::little_endian);
  95. typedef std::codecvt_utf8<UINT32, 1114111, convMode> utf8utf32;
  96. std::wstring_convert<utf8utf32, UINT32> conversion("?");
  97. UINT32* start = (UINT32*)string.data();
  98. UINT32* end = (start + (string.size() - 1) / 4);
  99. return conversion.to_bytes(start, end).c_str();
  100. }
  101. else if (isUTF32BE((UINT8*)string.data()))
  102. {
  103. const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
  104. typedef std::codecvt_utf8<UINT32, 1114111, convMode> utf8utf32;
  105. std::wstring_convert<utf8utf32, UINT32> conversion("?");
  106. UINT32* start = (UINT32*)string.data();
  107. UINT32* end = (start + (string.size() - 1) / 4);
  108. return conversion.to_bytes(start, end).c_str();
  109. }
  110. }
  111. if (readBytes >= 3)
  112. {
  113. if (isUTF8((UINT8*)string.data()))
  114. {
  115. return string.c_str() + 3;
  116. }
  117. }
  118. if (readBytes >= 2)
  119. {
  120. if (isUTF16LE((UINT8*)string.data()))
  121. {
  122. const std::codecvt_mode convMode = (std::codecvt_mode)(std::little_endian);
  123. typedef std::codecvt_utf8_utf16<UINT16, 1114111, convMode> utf8utf16;
  124. std::wstring_convert<utf8utf16, UINT16> conversion("?");
  125. UINT16* start = (UINT16*)(string.c_str() + 2); // Bug?: std::consume_header seems to be ignored so I manually remove the header
  126. return conversion.to_bytes(start).c_str();
  127. }
  128. else if (isUTF16BE((UINT8*)string.data()))
  129. {
  130. const std::codecvt_mode convMode = (std::codecvt_mode)(0);
  131. typedef std::codecvt_utf8_utf16<UINT16, 1114111, convMode> utf8utf16;
  132. // Bug?: Regardless of not providing the std::little_endian flag it seems that is how the data is read
  133. // so I manually flip it
  134. UINT32 numChars = (UINT32)(string.size() - 2) / 2;
  135. for (UINT32 i = 0; i < numChars; i++)
  136. std::swap(string[i * 2 + 0], string[i * 2 + 1]);
  137. std::wstring_convert<utf8utf16, UINT16> conversion("?");
  138. UINT16* start = (UINT16*)(string.c_str() + 2); // Bug?: std::consume_header seems to be ignored so I manually remove the header
  139. return conversion.to_bytes(start).c_str();
  140. }
  141. }
  142. return string.c_str();
  143. }
  144. WString DataStream::getAsWString()
  145. {
  146. // Read the entire buffer - ideally in one read, but if the size of
  147. // the buffer is unknown, do multiple fixed size reads.
  148. size_t bufSize = (mSize > 0 ? mSize : 4096);
  149. std::stringstream::char_type* tempBuffer = (std::stringstream::char_type*)bs_alloc((UINT32)bufSize);
  150. // Ensure read from begin of stream
  151. seek(0);
  152. std::stringstream result;
  153. while (!eof())
  154. {
  155. size_t numReadBytes = read(tempBuffer, bufSize);
  156. result.write(tempBuffer, numReadBytes);
  157. }
  158. free(tempBuffer);
  159. std::string string = result.str();
  160. UINT32 readBytes = (UINT32)string.size();
  161. if (readBytes >= 4)
  162. {
  163. if (isUTF32LE((UINT8*)string.data()))
  164. {
  165. // Not supported
  166. }
  167. else if (isUTF32BE((UINT8*)string.data()))
  168. {
  169. // Not supported
  170. }
  171. }
  172. if (readBytes >= 3)
  173. {
  174. if (isUTF8((UINT8*)string.data()))
  175. {
  176. const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
  177. typedef std::codecvt_utf8<wchar_t, 1114111, convMode> wcharutf8;
  178. std::wstring_convert<wcharutf8> conversion("?");
  179. return conversion.from_bytes(string).c_str();
  180. }
  181. }
  182. if (readBytes >= 2)
  183. {
  184. if (isUTF16LE((UINT8*)string.data()))
  185. {
  186. const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header | std::little_endian);
  187. typedef std::codecvt_utf16<wchar_t, 1114111, convMode> wcharutf16;
  188. std::wstring_convert<wcharutf16> conversion("?");
  189. return conversion.from_bytes(string).c_str();
  190. }
  191. else if (isUTF16BE((UINT8*)string.data()))
  192. {
  193. const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
  194. typedef std::codecvt_utf16<wchar_t, 1114111, convMode> wcharutf16;
  195. std::wstring_convert<wcharutf16> conversion("?");
  196. return conversion.from_bytes(string).c_str();
  197. }
  198. }
  199. {
  200. const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
  201. typedef std::codecvt_utf8<wchar_t, 1114111, convMode> wcharutf8;
  202. std::wstring_convert<wcharutf8> conversion("?");
  203. return conversion.from_bytes(string).c_str();
  204. }
  205. }
  206. MemoryDataStream::MemoryDataStream(size_t size)
  207. : DataStream(READ | WRITE), mData(nullptr), mFreeOnClose(true)
  208. {
  209. mData = mPos = (UINT8*)bs_alloc(size);
  210. mSize = size;
  211. mEnd = mData + mSize;
  212. assert(mEnd >= mPos);
  213. }
  214. MemoryDataStream::MemoryDataStream(void* memory, size_t inSize, bool freeOnClose)
  215. : DataStream(READ | WRITE), mData(nullptr), mFreeOnClose(freeOnClose)
  216. {
  217. mData = mPos = static_cast<UINT8*>(memory);
  218. mSize = inSize;
  219. mEnd = mData + mSize;
  220. assert(mEnd >= mPos);
  221. }
  222. MemoryDataStream::MemoryDataStream(DataStream& sourceStream)
  223. : DataStream(READ | WRITE), mData(nullptr)
  224. {
  225. // Copy data from incoming stream
  226. mSize = sourceStream.size();
  227. mData = (UINT8*)bs_alloc((UINT32)mSize);
  228. mPos = mData;
  229. mEnd = mData + sourceStream.read(mData, mSize);
  230. mFreeOnClose = true;
  231. assert(mEnd >= mPos);
  232. }
  233. MemoryDataStream::MemoryDataStream(const SPtr<DataStream>& sourceStream)
  234. :DataStream(READ | WRITE), mData(nullptr)
  235. {
  236. // Copy data from incoming stream
  237. mSize = sourceStream->size();
  238. mData = (UINT8*)bs_alloc((UINT32)mSize);
  239. mPos = mData;
  240. mEnd = mData + sourceStream->read(mData, mSize);
  241. mFreeOnClose = true;
  242. assert(mEnd >= mPos);
  243. }
  244. MemoryDataStream::~MemoryDataStream()
  245. {
  246. close();
  247. }
  248. size_t MemoryDataStream::read(void* buf, size_t count)
  249. {
  250. size_t cnt = count;
  251. if (mPos + cnt > mEnd)
  252. cnt = mEnd - mPos;
  253. if (cnt == 0)
  254. return 0;
  255. assert (cnt <= count);
  256. memcpy(buf, mPos, cnt);
  257. mPos += cnt;
  258. return cnt;
  259. }
  260. size_t MemoryDataStream::write(const void* buf, size_t count)
  261. {
  262. size_t written = 0;
  263. if (isWriteable())
  264. {
  265. written = count;
  266. if (mPos + written > mEnd)
  267. written = mEnd - mPos;
  268. if (written == 0)
  269. return 0;
  270. memcpy(mPos, buf, written);
  271. mPos += written;
  272. }
  273. return written;
  274. }
  275. void MemoryDataStream::skip(size_t count)
  276. {
  277. size_t newpos = (size_t)( (mPos - mData) + count );
  278. assert(mData + newpos <= mEnd);
  279. mPos = mData + newpos;
  280. }
  281. void MemoryDataStream::seek(size_t pos)
  282. {
  283. assert(mData + pos <= mEnd);
  284. mPos = mData + pos;
  285. }
  286. size_t MemoryDataStream::tell() const
  287. {
  288. return mPos - mData;
  289. }
  290. bool MemoryDataStream::eof() const
  291. {
  292. return mPos >= mEnd;
  293. }
  294. SPtr<DataStream> MemoryDataStream::clone(bool copyData) const
  295. {
  296. if (!copyData)
  297. return bs_shared_ptr_new<MemoryDataStream>(mData, mSize, false);
  298. return bs_shared_ptr_new<MemoryDataStream>(*this);
  299. }
  300. void MemoryDataStream::close()
  301. {
  302. if (mData != nullptr)
  303. {
  304. if(mFreeOnClose)
  305. bs_free(mData);
  306. mData = nullptr;
  307. }
  308. }
  309. FileDataStream::FileDataStream(const Path& path, AccessMode accessMode, bool freeOnClose)
  310. : DataStream(accessMode), mPath(path), mFreeOnClose(freeOnClose)
  311. {
  312. // Always open in binary mode
  313. // Also, always include reading
  314. std::ios::openmode mode = std::ios::binary;
  315. if ((accessMode & READ) != 0)
  316. mode |= std::ios::in;
  317. if (((accessMode & WRITE) != 0))
  318. {
  319. mode |= std::ios::out;
  320. mFStream = bs_shared_ptr_new<std::fstream>();
  321. mFStream->open(path.toPlatformString().c_str(), mode);
  322. mInStream = mFStream;
  323. }
  324. else
  325. {
  326. mFStreamRO = bs_shared_ptr_new<std::ifstream>();
  327. mFStreamRO->open(path.toPlatformString().c_str(), mode);
  328. mInStream = mFStreamRO;
  329. }
  330. // Should check ensure open succeeded, in case fail for some reason.
  331. if (mInStream->fail())
  332. {
  333. LOGWRN("Cannot open file: " + path.toString());
  334. return;
  335. }
  336. mInStream->seekg(0, std::ios_base::end);
  337. mSize = (size_t)mInStream->tellg();
  338. mInStream->seekg(0, std::ios_base::beg);
  339. }
  340. FileDataStream::~FileDataStream()
  341. {
  342. close();
  343. }
  344. size_t FileDataStream::read(void* buf, size_t count)
  345. {
  346. mInStream->read(static_cast<char*>(buf), static_cast<std::streamsize>(count));
  347. return (size_t)mInStream->gcount();
  348. }
  349. size_t FileDataStream::write(const void* buf, size_t count)
  350. {
  351. size_t written = 0;
  352. if (isWriteable() && mFStream)
  353. {
  354. mFStream->write(static_cast<const char*>(buf), static_cast<std::streamsize>(count));
  355. written = count;
  356. }
  357. return written;
  358. }
  359. void FileDataStream::skip(size_t count)
  360. {
  361. mInStream->clear(); // Clear fail status in case eof was set
  362. mInStream->seekg(static_cast<std::ifstream::pos_type>(count), std::ios::cur);
  363. }
  364. void FileDataStream::seek(size_t pos)
  365. {
  366. mInStream->clear(); // Clear fail status in case eof was set
  367. mInStream->seekg(static_cast<std::streamoff>(pos), std::ios::beg);
  368. }
  369. size_t FileDataStream::tell() const
  370. {
  371. mInStream->clear(); // Clear fail status in case eof was set
  372. return (size_t)mInStream->tellg();
  373. }
  374. bool FileDataStream::eof() const
  375. {
  376. return mInStream->eof();
  377. }
  378. SPtr<DataStream> FileDataStream::clone(bool copyData) const
  379. {
  380. return bs_shared_ptr_new<FileDataStream>(mPath, (AccessMode)getAccessMode(), true);
  381. }
  382. void FileDataStream::close()
  383. {
  384. if (mInStream)
  385. {
  386. if (mFStreamRO)
  387. mFStreamRO->close();
  388. if (mFStream)
  389. {
  390. mFStream->flush();
  391. mFStream->close();
  392. }
  393. if (mFreeOnClose)
  394. {
  395. mInStream = nullptr;
  396. mFStreamRO = nullptr;
  397. mFStream = nullptr;
  398. }
  399. }
  400. }
  401. }