CmDataStream.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. #include "CmDataStream.h"
  2. #include "CmDebug.h"
  3. #include "CmException.h"
  4. namespace CamelotFramework
  5. {
  6. template <typename T> DataStream& DataStream::operator >>(T& val)
  7. {
  8. read(static_cast<void*>(&val), sizeof(T));
  9. return *this;
  10. }
  11. String DataStream::getLine(bool trimAfter)
  12. {
  13. char tmpBuf[OGRE_STREAM_TEMP_SIZE];
  14. String retString;
  15. size_t readCount;
  16. // Keep looping while not hitting delimiter
  17. while ((readCount = read(tmpBuf, OGRE_STREAM_TEMP_SIZE-1)) != 0)
  18. {
  19. // Terminate string
  20. tmpBuf[readCount] = '\0';
  21. char* p = strchr(tmpBuf, '\n');
  22. if (p != 0)
  23. {
  24. // Reposition backwards
  25. skip((long)(p + 1 - tmpBuf - readCount));
  26. *p = '\0';
  27. }
  28. retString += tmpBuf;
  29. if (p != 0)
  30. {
  31. // Trim off trailing CR if this was a CR/LF entry
  32. if (retString.length() && retString[retString.length()-1] == '\r')
  33. {
  34. retString.erase(retString.length()-1, 1);
  35. }
  36. // Found terminator, break out
  37. break;
  38. }
  39. }
  40. if (trimAfter)
  41. {
  42. StringUtil::trim(retString);
  43. }
  44. return retString;
  45. }
  46. size_t DataStream::readLine(char* buf, size_t maxCount, const String& delim)
  47. {
  48. // Deal with both Unix & Windows LFs
  49. bool trimCR = false;
  50. if (delim.find_first_of('\n') != String::npos)
  51. {
  52. trimCR = true;
  53. }
  54. char tmpBuf[OGRE_STREAM_TEMP_SIZE];
  55. size_t chunkSize = std::min(maxCount, (size_t)OGRE_STREAM_TEMP_SIZE-1);
  56. size_t totalCount = 0;
  57. size_t readCount;
  58. while (chunkSize && (readCount = read(tmpBuf, chunkSize)) != 0)
  59. {
  60. // Terminate
  61. tmpBuf[readCount] = '\0';
  62. // Find first delimiter
  63. size_t pos = strcspn(tmpBuf, delim.c_str());
  64. if (pos < readCount)
  65. {
  66. // Found terminator, reposition backwards
  67. skip((long)(pos + 1 - readCount));
  68. }
  69. // Are we genuinely copying?
  70. if (buf)
  71. {
  72. memcpy(buf+totalCount, tmpBuf, pos);
  73. }
  74. totalCount += pos;
  75. if (pos < readCount)
  76. {
  77. // Trim off trailing CR if this was a CR/LF entry
  78. if (trimCR && totalCount && buf[totalCount-1] == '\r')
  79. {
  80. --totalCount;
  81. }
  82. // Found terminator, break out
  83. break;
  84. }
  85. // Adjust chunkSize for next time
  86. chunkSize = std::min(maxCount-totalCount, (size_t)OGRE_STREAM_TEMP_SIZE-1);
  87. }
  88. // Terminate
  89. buf[totalCount] = '\0';
  90. return totalCount;
  91. }
  92. size_t DataStream::skipLine(const String& delim)
  93. {
  94. char tmpBuf[OGRE_STREAM_TEMP_SIZE];
  95. size_t total = 0;
  96. size_t readCount;
  97. // Keep looping while not hitting delimiter
  98. while ((readCount = read(tmpBuf, OGRE_STREAM_TEMP_SIZE-1)) != 0)
  99. {
  100. // Terminate string
  101. tmpBuf[readCount] = '\0';
  102. // Find first delimiter
  103. size_t pos = strcspn(tmpBuf, delim.c_str());
  104. if (pos < readCount)
  105. {
  106. // Found terminator, reposition backwards
  107. skip((long)(pos + 1 - readCount));
  108. total += pos + 1;
  109. // break out
  110. break;
  111. }
  112. total += readCount;
  113. }
  114. return total;
  115. }
  116. String DataStream::getAsString(void)
  117. {
  118. // Read the entire buffer - ideally in one read, but if the size of
  119. // the buffer is unknown, do multiple fixed size reads.
  120. size_t bufSize = (mSize > 0 ? mSize : 4096);
  121. char* pBuf = (char*)malloc(sizeof(char) * bufSize);
  122. // Ensure read from begin of stream
  123. seek(0);
  124. String result;
  125. while (!eof())
  126. {
  127. size_t nr = read(pBuf, bufSize);
  128. result.append(pBuf, nr);
  129. }
  130. free(pBuf);
  131. return result;
  132. }
  133. MemoryDataStream::MemoryDataStream(void* pMem, size_t inSize, bool freeOnClose, bool readOnly)
  134. : DataStream(static_cast<UINT16>(readOnly ? READ : (READ | WRITE)))
  135. {
  136. mData = mPos = static_cast<UINT8*>(pMem);
  137. mSize = inSize;
  138. mEnd = mData + mSize;
  139. mFreeOnClose = freeOnClose;
  140. assert(mEnd >= mPos);
  141. }
  142. MemoryDataStream::MemoryDataStream(const String& name, void* pMem, size_t inSize,
  143. bool freeOnClose, bool readOnly)
  144. : DataStream(name, static_cast<UINT16>(readOnly ? READ : (READ | WRITE)))
  145. {
  146. mData = mPos = static_cast<UINT8*>(pMem);
  147. mSize = inSize;
  148. mEnd = mData + mSize;
  149. mFreeOnClose = freeOnClose;
  150. assert(mEnd >= mPos);
  151. }
  152. MemoryDataStream::MemoryDataStream(DataStream& sourceStream,
  153. bool freeOnClose, bool readOnly)
  154. : DataStream(static_cast<UINT16>(readOnly ? READ : (READ | WRITE)))
  155. {
  156. // Copy data from incoming stream
  157. mSize = sourceStream.size();
  158. if (mSize == 0 && !sourceStream.eof())
  159. {
  160. // size of source is unknown, read all of it into memory
  161. String contents = sourceStream.getAsString();
  162. mSize = contents.size();
  163. mData = (UINT8*)malloc(sizeof(UINT8) * mSize);
  164. mPos = mData;
  165. memcpy(mData, contents.data(), mSize);
  166. mEnd = mData + mSize;
  167. }
  168. else
  169. {
  170. mData = (UINT8*)malloc(sizeof(UINT8) * mSize);
  171. mPos = mData;
  172. mEnd = mData + sourceStream.read(mData, mSize);
  173. mFreeOnClose = freeOnClose;
  174. }
  175. assert(mEnd >= mPos);
  176. }
  177. MemoryDataStream::MemoryDataStream(DataStreamPtr& sourceStream,
  178. bool freeOnClose, bool readOnly)
  179. : DataStream(static_cast<UINT16>(readOnly ? READ : (READ | WRITE)))
  180. {
  181. // Copy data from incoming stream
  182. mSize = sourceStream->size();
  183. if (mSize == 0 && !sourceStream->eof())
  184. {
  185. // size of source is unknown, read all of it into memory
  186. String contents = sourceStream->getAsString();
  187. mSize = contents.size();
  188. mData = (UINT8*)malloc(sizeof(UINT8) * mSize);
  189. mPos = mData;
  190. memcpy(mData, contents.data(), mSize);
  191. mEnd = mData + mSize;
  192. }
  193. else
  194. {
  195. mData = (UINT8*)malloc(sizeof(UINT8) * mSize);
  196. mPos = mData;
  197. mEnd = mData + sourceStream->read(mData, mSize);
  198. mFreeOnClose = freeOnClose;
  199. }
  200. assert(mEnd >= mPos);
  201. }
  202. MemoryDataStream::MemoryDataStream(const String& name, DataStream& sourceStream,
  203. bool freeOnClose, bool readOnly)
  204. : DataStream(name, static_cast<UINT16>(readOnly ? READ : (READ | WRITE)))
  205. {
  206. // Copy data from incoming stream
  207. mSize = sourceStream.size();
  208. if (mSize == 0 && !sourceStream.eof())
  209. {
  210. // size of source is unknown, read all of it into memory
  211. String contents = sourceStream.getAsString();
  212. mSize = contents.size();
  213. mData = (UINT8*)malloc(sizeof(UINT8) * mSize);
  214. mPos = mData;
  215. memcpy(mData, contents.data(), mSize);
  216. mEnd = mData + mSize;
  217. }
  218. else
  219. {
  220. mData = (UINT8*)malloc(sizeof(UINT8) * mSize);
  221. mPos = mData;
  222. mEnd = mData + sourceStream.read(mData, mSize);
  223. mFreeOnClose = freeOnClose;
  224. }
  225. assert(mEnd >= mPos);
  226. }
  227. MemoryDataStream::MemoryDataStream(const String& name, const DataStreamPtr& sourceStream,
  228. bool freeOnClose, bool readOnly)
  229. : DataStream(name, static_cast<UINT16>(readOnly ? READ : (READ | WRITE)))
  230. {
  231. // Copy data from incoming stream
  232. mSize = sourceStream->size();
  233. if (mSize == 0 && !sourceStream->eof())
  234. {
  235. // size of source is unknown, read all of it into memory
  236. String contents = sourceStream->getAsString();
  237. mSize = contents.size();
  238. mData = (UINT8*)malloc(sizeof(UINT8) * mSize);
  239. mPos = mData;
  240. memcpy(mData, contents.data(), mSize);
  241. mEnd = mData + mSize;
  242. }
  243. else
  244. {
  245. mData = (UINT8*)malloc(sizeof(UINT8) * mSize);
  246. mPos = mData;
  247. mEnd = mData + sourceStream->read(mData, mSize);
  248. mFreeOnClose = freeOnClose;
  249. }
  250. assert(mEnd >= mPos);
  251. }
  252. MemoryDataStream::MemoryDataStream(size_t inSize, bool freeOnClose, bool readOnly)
  253. : DataStream(static_cast<UINT16>(readOnly ? READ : (READ | WRITE)))
  254. {
  255. mSize = inSize;
  256. mFreeOnClose = freeOnClose;
  257. mData = (UINT8*)malloc(sizeof(UINT8) * mSize);
  258. mPos = mData;
  259. mEnd = mData + mSize;
  260. assert(mEnd >= mPos);
  261. }
  262. MemoryDataStream::MemoryDataStream(const String& name, size_t inSize,
  263. bool freeOnClose, bool readOnly)
  264. : DataStream(name, static_cast<UINT16>(readOnly ? READ : (READ | WRITE)))
  265. {
  266. mSize = inSize;
  267. mFreeOnClose = freeOnClose;
  268. mData = (UINT8*)malloc(sizeof(UINT8) * mSize);
  269. mPos = mData;
  270. mEnd = mData + mSize;
  271. assert(mEnd >= mPos);
  272. }
  273. MemoryDataStream::~MemoryDataStream()
  274. {
  275. close();
  276. }
  277. size_t MemoryDataStream::read(void* buf, size_t count)
  278. {
  279. size_t cnt = count;
  280. // Read over end of memory?
  281. if (mPos + cnt > mEnd)
  282. cnt = mEnd - mPos;
  283. if (cnt == 0)
  284. return 0;
  285. assert (cnt<=count);
  286. memcpy(buf, mPos, cnt);
  287. mPos += cnt;
  288. return cnt;
  289. }
  290. size_t MemoryDataStream::write(const void* buf, size_t count)
  291. {
  292. size_t written = 0;
  293. if (isWriteable())
  294. {
  295. written = count;
  296. // we only allow writing within the extents of allocated memory
  297. // check for buffer overrun & disallow
  298. if (mPos + written > mEnd)
  299. written = mEnd - mPos;
  300. if (written == 0)
  301. return 0;
  302. memcpy(mPos, buf, written);
  303. mPos += written;
  304. }
  305. return written;
  306. }
  307. size_t MemoryDataStream::readLine(char* buf, size_t maxCount,
  308. const String& delim)
  309. {
  310. // Deal with both Unix & Windows LFs
  311. bool trimCR = false;
  312. if (delim.find_first_of('\n') != String::npos)
  313. {
  314. trimCR = true;
  315. }
  316. size_t pos = 0;
  317. // Make sure pos can never go past the end of the data
  318. while (pos < maxCount && mPos < mEnd)
  319. {
  320. if (delim.find(*mPos) != String::npos)
  321. {
  322. // Trim off trailing CR if this was a CR/LF entry
  323. if (trimCR && pos && buf[pos-1] == '\r')
  324. {
  325. // terminate 1 character early
  326. --pos;
  327. }
  328. // Found terminator, skip and break out
  329. ++mPos;
  330. break;
  331. }
  332. buf[pos++] = *mPos++;
  333. }
  334. // terminate
  335. buf[pos] = '\0';
  336. return pos;
  337. }
  338. size_t MemoryDataStream::skipLine(const String& delim)
  339. {
  340. size_t pos = 0;
  341. // Make sure pos can never go past the end of the data
  342. while (mPos < mEnd)
  343. {
  344. ++pos;
  345. if (delim.find(*mPos++) != String::npos)
  346. {
  347. // Found terminator, break out
  348. break;
  349. }
  350. }
  351. return pos;
  352. }
  353. void MemoryDataStream::skip(long count)
  354. {
  355. size_t newpos = (size_t)( ( mPos - mData ) + count );
  356. assert( mData + newpos <= mEnd );
  357. mPos = mData + newpos;
  358. }
  359. void MemoryDataStream::seek( size_t pos )
  360. {
  361. assert( mData + pos <= mEnd );
  362. mPos = mData + pos;
  363. }
  364. size_t MemoryDataStream::tell(void) const
  365. {
  366. //mData is start, mPos is current location
  367. return mPos - mData;
  368. }
  369. bool MemoryDataStream::eof(void) const
  370. {
  371. return mPos >= mEnd;
  372. }
  373. void MemoryDataStream::close(void)
  374. {
  375. if (mFreeOnClose && mData)
  376. {
  377. free(mData);
  378. mData = 0;
  379. }
  380. }
  381. FileDataStream::FileDataStream(std::shared_ptr<std::ifstream> s, bool freeOnClose)
  382. : DataStream(), mpInStream(s), mpFStreamRO(s), mpFStream(0), mFreeOnClose(freeOnClose)
  383. {
  384. // calculate the size
  385. mpInStream->seekg(0, std::ios_base::end);
  386. mSize = (size_t)mpInStream->tellg();
  387. mpInStream->seekg(0, std::ios_base::beg);
  388. determineAccess();
  389. }
  390. FileDataStream::FileDataStream(const String& name,
  391. std::shared_ptr<std::ifstream> s, bool freeOnClose)
  392. : DataStream(name), mpInStream(s), mpFStreamRO(s), mpFStream(0), mFreeOnClose(freeOnClose)
  393. {
  394. // calculate the size
  395. mpInStream->seekg(0, std::ios_base::end);
  396. mSize = (size_t)mpInStream->tellg();
  397. mpInStream->seekg(0, std::ios_base::beg);
  398. determineAccess();
  399. }
  400. FileDataStream::FileDataStream(const String& name,
  401. std::shared_ptr<std::ifstream> s, size_t inSize, bool freeOnClose)
  402. : DataStream(name), mpInStream(s), mpFStreamRO(s), mpFStream(0), mFreeOnClose(freeOnClose)
  403. {
  404. // Size is passed in
  405. mSize = inSize;
  406. determineAccess();
  407. }
  408. FileDataStream::FileDataStream(std::shared_ptr<std::fstream> s, bool freeOnClose)
  409. : DataStream(false), mpInStream(s), mpFStreamRO(0), mpFStream(s), mFreeOnClose(freeOnClose)
  410. {
  411. // writeable!
  412. // calculate the size
  413. mpInStream->seekg(0, std::ios_base::end);
  414. mSize = (size_t)mpInStream->tellg();
  415. mpInStream->seekg(0, std::ios_base::beg);
  416. determineAccess();
  417. }
  418. FileDataStream::FileDataStream(const String& name,
  419. std::shared_ptr<std::fstream> s, bool freeOnClose)
  420. : DataStream(name, false), mpInStream(s), mpFStreamRO(0), mpFStream(s), mFreeOnClose(freeOnClose)
  421. {
  422. // writeable!
  423. // calculate the size
  424. mpInStream->seekg(0, std::ios_base::end);
  425. mSize = (size_t)mpInStream->tellg();
  426. mpInStream->seekg(0, std::ios_base::beg);
  427. determineAccess();
  428. }
  429. FileDataStream::FileDataStream(const String& name,
  430. std::shared_ptr<std::fstream> s, size_t inSize, bool freeOnClose)
  431. : DataStream(name, false), mpInStream(s), mpFStreamRO(0), mpFStream(s), mFreeOnClose(freeOnClose)
  432. {
  433. // writeable!
  434. // Size is passed in
  435. mSize = inSize;
  436. determineAccess();
  437. }
  438. void FileDataStream::determineAccess()
  439. {
  440. mAccess = 0;
  441. if (mpInStream)
  442. mAccess |= READ;
  443. if (mpFStream)
  444. mAccess |= WRITE;
  445. }
  446. FileDataStream::~FileDataStream()
  447. {
  448. close();
  449. }
  450. size_t FileDataStream::read(void* buf, size_t count)
  451. {
  452. mpInStream->read(static_cast<char*>(buf), static_cast<std::streamsize>(count));
  453. return (size_t)mpInStream->gcount();
  454. }
  455. size_t FileDataStream::write(const void* buf, size_t count)
  456. {
  457. size_t written = 0;
  458. if (isWriteable() && mpFStream)
  459. {
  460. mpFStream->write(static_cast<const char*>(buf), static_cast<std::streamsize>(count));
  461. written = count;
  462. }
  463. return written;
  464. }
  465. size_t FileDataStream::readLine(char* buf, size_t maxCount,
  466. const String& delim)
  467. {
  468. if (delim.empty())
  469. {
  470. CM_EXCEPT(InvalidParametersException, "No delimiter provided");
  471. }
  472. if (delim.size() > 1)
  473. {
  474. gDebug().log("WARNING: FileStreamDataStream::readLine - using only first delimeter", "DataStream");
  475. }
  476. // Deal with both Unix & Windows LFs
  477. bool trimCR = false;
  478. if (delim.at(0) == '\n')
  479. {
  480. trimCR = true;
  481. }
  482. // maxCount + 1 since count excludes terminator in getline
  483. mpInStream->getline(buf, static_cast<std::streamsize>(maxCount+1), delim.at(0));
  484. size_t ret = (size_t)mpInStream->gcount();
  485. // three options
  486. // 1) we had an eof before we read a whole line
  487. // 2) we ran out of buffer space
  488. // 3) we read a whole line - in this case the delim character is taken from the stream but not written in the buffer so the read data is of length ret-1 and thus ends at index ret-2
  489. // in all cases the buffer will be null terminated for us
  490. if (mpInStream->eof())
  491. {
  492. // no problem
  493. }
  494. else if (mpInStream->fail())
  495. {
  496. // Did we fail because of maxCount hit? No - no terminating character
  497. // in included in the count in this case
  498. if (ret == maxCount)
  499. {
  500. // clear failbit for next time
  501. mpInStream->clear();
  502. }
  503. else
  504. {
  505. CM_EXCEPT(InternalErrorException, "Streaming error occurred");
  506. }
  507. }
  508. else
  509. {
  510. // we need to adjust ret because we want to use it as a
  511. // pointer to the terminating null character and it is
  512. // currently the length of the data read from the stream
  513. // i.e. 1 more than the length of the data in the buffer and
  514. // hence 1 more than the _index_ of the NULL character
  515. --ret;
  516. }
  517. // trim off CR if we found CR/LF
  518. if (trimCR && buf[ret-1] == '\r')
  519. {
  520. --ret;
  521. buf[ret] = '\0';
  522. }
  523. return ret;
  524. }
  525. void FileDataStream::skip(long count)
  526. {
  527. #if defined(STLPORT)
  528. // Workaround for STLport issues: After reached eof of file stream,
  529. // it's seems the stream was putted in intermediate state, and will be
  530. // fail if try to repositioning relative to current position.
  531. // Note: tellg() fail in this case too.
  532. if (mpInStream->eof())
  533. {
  534. mpInStream->clear();
  535. // Use seek relative to either begin or end to bring the stream
  536. // back to normal state.
  537. mpInStream->seekg(0, std::ios::end);
  538. }
  539. #endif
  540. mpInStream->clear(); //Clear fail status in case eof was set
  541. mpInStream->seekg(static_cast<std::ifstream::pos_type>(count), std::ios::cur);
  542. }
  543. void FileDataStream::seek( size_t pos )
  544. {
  545. mpInStream->clear(); //Clear fail status in case eof was set
  546. mpInStream->seekg(static_cast<std::streamoff>(pos), std::ios::beg);
  547. }
  548. size_t FileDataStream::tell(void) const
  549. {
  550. mpInStream->clear(); //Clear fail status in case eof was set
  551. return (size_t)mpInStream->tellg();
  552. }
  553. bool FileDataStream::eof(void) const
  554. {
  555. return mpInStream->eof();
  556. }
  557. void FileDataStream::close(void)
  558. {
  559. if (mpInStream)
  560. {
  561. // Unfortunately, there is no file-specific shared class hierarchy between fstream and ifstream (!!)
  562. if (mpFStreamRO)
  563. mpFStreamRO->close();
  564. if (mpFStream)
  565. {
  566. mpFStream->flush();
  567. mpFStream->close();
  568. }
  569. if (mFreeOnClose)
  570. {
  571. mpInStream = nullptr;
  572. mpFStreamRO = nullptr;
  573. mpFStream = nullptr;
  574. }
  575. }
  576. }
  577. }