BsDataStream.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "FileSystem/BsDataStream.h"
  4. #include "Debug/BsDebug.h"
  5. #include "String/BsUnicode.h"
  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. // Write BOM
  44. UINT8 bom[2] = { 0xFF, 0xFE };
  45. write(bom, sizeof(bom));
  46. U16String u16string = UTF8::toUTF16(string);
  47. write(u16string.data(), u16string.length() * sizeof(char16_t));
  48. }
  49. else
  50. {
  51. // Write BOM
  52. UINT8 bom[3] = { 0xEF, 0xBB, 0xBF };
  53. write(bom, sizeof(bom));
  54. write(string.data(), string.length());
  55. }
  56. }
  57. void DataStream::writeString(const WString& string, StringEncoding encoding)
  58. {
  59. if (encoding == StringEncoding::UTF16)
  60. {
  61. // Write BOM
  62. UINT8 bom[2] = { 0xFF, 0xFE };
  63. write(bom, sizeof(bom));
  64. String u8string = UTF8::fromWide(string);
  65. U16String u16string = UTF8::toUTF16(u8string);
  66. write(u16string.data(), u16string.length() * sizeof(char16_t));
  67. }
  68. else
  69. {
  70. // Write BOM
  71. UINT8 bom[3] = { 0xEF, 0xBB, 0xBF };
  72. write(bom, sizeof(bom));
  73. String u8string = UTF8::fromWide(string);
  74. write(u8string.data(), u8string.length());
  75. }
  76. }
  77. String DataStream::getAsString()
  78. {
  79. // Read the entire buffer - ideally in one read, but if the size of
  80. // the buffer is unknown, do multiple fixed size reads.
  81. size_t bufSize = (mSize > 0 ? mSize : 4096);
  82. std::stringstream::char_type* tempBuffer = (std::stringstream::char_type*)bs_alloc((UINT32)bufSize);
  83. // Ensure read from begin of stream
  84. seek(0);
  85. // Try reading header
  86. UINT8 headerBytes[4];
  87. size_t numHeaderBytes = read(headerBytes, 4);
  88. size_t dataOffset = 0;
  89. if(numHeaderBytes >= 4)
  90. {
  91. if (isUTF32LE(headerBytes))
  92. dataOffset = 4;
  93. else if (isUTF32BE(headerBytes))
  94. {
  95. LOGWRN("UTF-32 big endian decoding not supported");
  96. return u8"";
  97. }
  98. }
  99. if(dataOffset == 0 && numHeaderBytes >= 3)
  100. {
  101. if (isUTF8(headerBytes))
  102. dataOffset = 3;
  103. }
  104. if(dataOffset == 0 && numHeaderBytes >= 2)
  105. {
  106. if (isUTF16LE(headerBytes))
  107. dataOffset = 2;
  108. else if (isUTF16BE(headerBytes))
  109. {
  110. LOGWRN("UTF-16 big endian decoding not supported");
  111. return u8"";
  112. }
  113. }
  114. seek(dataOffset);
  115. std::stringstream result;
  116. while (!eof())
  117. {
  118. size_t numReadBytes = read(tempBuffer, bufSize);
  119. result.write(tempBuffer, numReadBytes);
  120. }
  121. free(tempBuffer);
  122. std::string string = result.str();
  123. switch(dataOffset)
  124. {
  125. default:
  126. case 0: // No BOM = assumed UTF-8
  127. case 3: // UTF-8
  128. return String(string.data(), string.length());
  129. case 2: // UTF-16
  130. {
  131. UINT32 numElems = (UINT32)string.length() / 2;
  132. return UTF8::fromUTF16(U16String((char16_t*)string.data(), numElems));
  133. }
  134. case 4: // UTF-32
  135. {
  136. UINT32 numElems = (UINT32)string.length() / 4;
  137. return UTF8::fromUTF32(U32String((char32_t*)string.data(), numElems));
  138. }
  139. }
  140. // Note: Never assuming ANSI as there is no ideal way to check for it. If required I need to
  141. // try reading the data and if all UTF encodings fail, assume it's ANSI. For now it should be
  142. // fine as most files are UTF-8 encoded.
  143. }
  144. WString DataStream::getAsWString()
  145. {
  146. String u8string = getAsString();
  147. return UTF8::toWide(u8string);
  148. }
  149. MemoryDataStream::MemoryDataStream(size_t size)
  150. : DataStream(READ | WRITE), mData(nullptr), mFreeOnClose(true)
  151. {
  152. mData = mPos = (UINT8*)bs_alloc((UINT32)size);
  153. mSize = size;
  154. mEnd = mData + mSize;
  155. assert(mEnd >= mPos);
  156. }
  157. MemoryDataStream::MemoryDataStream(void* memory, size_t inSize, bool freeOnClose)
  158. : DataStream(READ | WRITE), mData(nullptr), mFreeOnClose(freeOnClose)
  159. {
  160. mData = mPos = static_cast<UINT8*>(memory);
  161. mSize = inSize;
  162. mEnd = mData + mSize;
  163. assert(mEnd >= mPos);
  164. }
  165. MemoryDataStream::MemoryDataStream(DataStream& sourceStream)
  166. : DataStream(READ | WRITE), mData(nullptr)
  167. {
  168. // Copy data from incoming stream
  169. mSize = sourceStream.size();
  170. mData = (UINT8*)bs_alloc((UINT32)mSize);
  171. mPos = mData;
  172. mEnd = mData + sourceStream.read(mData, mSize);
  173. mFreeOnClose = true;
  174. assert(mEnd >= mPos);
  175. }
  176. MemoryDataStream::MemoryDataStream(const SPtr<DataStream>& sourceStream)
  177. :DataStream(READ | WRITE), mData(nullptr)
  178. {
  179. // Copy data from incoming stream
  180. mSize = sourceStream->size();
  181. mData = (UINT8*)bs_alloc((UINT32)mSize);
  182. mPos = mData;
  183. mEnd = mData + sourceStream->read(mData, mSize);
  184. mFreeOnClose = true;
  185. assert(mEnd >= mPos);
  186. }
  187. MemoryDataStream::~MemoryDataStream()
  188. {
  189. close();
  190. }
  191. size_t MemoryDataStream::read(void* buf, size_t count)
  192. {
  193. size_t cnt = count;
  194. if (mPos + cnt > mEnd)
  195. cnt = mEnd - mPos;
  196. if (cnt == 0)
  197. return 0;
  198. assert (cnt <= count);
  199. memcpy(buf, mPos, cnt);
  200. mPos += cnt;
  201. return cnt;
  202. }
  203. size_t MemoryDataStream::write(const void* buf, size_t count)
  204. {
  205. size_t written = 0;
  206. if (isWriteable())
  207. {
  208. written = count;
  209. if (mPos + written > mEnd)
  210. written = mEnd - mPos;
  211. if (written == 0)
  212. return 0;
  213. memcpy(mPos, buf, written);
  214. mPos += written;
  215. }
  216. return written;
  217. }
  218. void MemoryDataStream::skip(size_t count)
  219. {
  220. size_t newpos = (size_t)( (mPos - mData) + count );
  221. assert(mData + newpos <= mEnd);
  222. mPos = mData + newpos;
  223. }
  224. void MemoryDataStream::seek(size_t pos)
  225. {
  226. assert(mData + pos <= mEnd);
  227. mPos = mData + pos;
  228. }
  229. size_t MemoryDataStream::tell() const
  230. {
  231. return mPos - mData;
  232. }
  233. bool MemoryDataStream::eof() const
  234. {
  235. return mPos >= mEnd;
  236. }
  237. SPtr<DataStream> MemoryDataStream::clone(bool copyData) const
  238. {
  239. if (!copyData)
  240. return bs_shared_ptr_new<MemoryDataStream>(mData, mSize, false);
  241. return bs_shared_ptr_new<MemoryDataStream>(*this);
  242. }
  243. void MemoryDataStream::close()
  244. {
  245. if (mData != nullptr)
  246. {
  247. if(mFreeOnClose)
  248. bs_free(mData);
  249. mData = nullptr;
  250. }
  251. }
  252. FileDataStream::FileDataStream(const Path& path, AccessMode accessMode, bool freeOnClose)
  253. : DataStream(accessMode), mPath(path), mFreeOnClose(freeOnClose)
  254. {
  255. // Always open in binary mode
  256. // Also, always include reading
  257. std::ios::openmode mode = std::ios::binary;
  258. if ((accessMode & READ) != 0)
  259. mode |= std::ios::in;
  260. if (((accessMode & WRITE) != 0))
  261. {
  262. mode |= std::ios::out;
  263. mFStream = bs_shared_ptr_new<std::fstream>();
  264. mFStream->open(path.toPlatformString().c_str(), mode);
  265. mInStream = mFStream;
  266. }
  267. else
  268. {
  269. mFStreamRO = bs_shared_ptr_new<std::ifstream>();
  270. mFStreamRO->open(path.toPlatformString().c_str(), mode);
  271. mInStream = mFStreamRO;
  272. }
  273. // Should check ensure open succeeded, in case fail for some reason.
  274. if (mInStream->fail())
  275. {
  276. LOGWRN("Cannot open file: " + path.toString());
  277. return;
  278. }
  279. mInStream->seekg(0, std::ios_base::end);
  280. mSize = (size_t)mInStream->tellg();
  281. mInStream->seekg(0, std::ios_base::beg);
  282. }
  283. FileDataStream::~FileDataStream()
  284. {
  285. close();
  286. }
  287. size_t FileDataStream::read(void* buf, size_t count)
  288. {
  289. mInStream->read(static_cast<char*>(buf), static_cast<std::streamsize>(count));
  290. return (size_t)mInStream->gcount();
  291. }
  292. size_t FileDataStream::write(const void* buf, size_t count)
  293. {
  294. size_t written = 0;
  295. if (isWriteable() && mFStream)
  296. {
  297. mFStream->write(static_cast<const char*>(buf), static_cast<std::streamsize>(count));
  298. written = count;
  299. }
  300. return written;
  301. }
  302. void FileDataStream::skip(size_t count)
  303. {
  304. mInStream->clear(); // Clear fail status in case eof was set
  305. mInStream->seekg(static_cast<std::ifstream::pos_type>(count), std::ios::cur);
  306. }
  307. void FileDataStream::seek(size_t pos)
  308. {
  309. mInStream->clear(); // Clear fail status in case eof was set
  310. mInStream->seekg(static_cast<std::streamoff>(pos), std::ios::beg);
  311. }
  312. size_t FileDataStream::tell() const
  313. {
  314. mInStream->clear(); // Clear fail status in case eof was set
  315. return (size_t)mInStream->tellg();
  316. }
  317. bool FileDataStream::eof() const
  318. {
  319. return mInStream->eof();
  320. }
  321. SPtr<DataStream> FileDataStream::clone(bool copyData) const
  322. {
  323. return bs_shared_ptr_new<FileDataStream>(mPath, (AccessMode)getAccessMode(), true);
  324. }
  325. void FileDataStream::close()
  326. {
  327. if (mInStream)
  328. {
  329. if (mFStreamRO)
  330. mFStreamRO->close();
  331. if (mFStream)
  332. {
  333. mFStream->flush();
  334. mFStream->close();
  335. }
  336. if (mFreeOnClose)
  337. {
  338. mInStream = nullptr;
  339. mFStreamRO = nullptr;
  340. mFStream = nullptr;
  341. }
  342. }
  343. }
  344. }