CBinaryReader.cpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /*
  2. * CBinaryReader.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "CBinaryReader.h"
  12. #include "CInputStream.h"
  13. #include "../TextOperations.h"
  14. VCMI_LIB_NAMESPACE_BEGIN
  15. #ifdef VCMI_ENDIAN_BIG
  16. template <typename CData>
  17. CData readLE(CData data)
  18. {
  19. auto dataPtr = (char*)&data;
  20. std::reverse(dataPtr, dataPtr + sizeof(data));
  21. return data;
  22. }
  23. #else
  24. template <typename CData>
  25. CData readLE(CData data)
  26. {
  27. return data;
  28. }
  29. #endif
  30. CBinaryReader::CBinaryReader() : stream(nullptr)
  31. {
  32. }
  33. CBinaryReader::CBinaryReader(CInputStream * stream) : stream(stream)
  34. {
  35. }
  36. CInputStream * CBinaryReader::getStream()
  37. {
  38. return stream;
  39. }
  40. void CBinaryReader::setStream(CInputStream * stream)
  41. {
  42. this->stream = stream;
  43. }
  44. si64 CBinaryReader::read(ui8 * data, si64 size)
  45. {
  46. si64 bytesRead = stream->read(data, size);
  47. if(bytesRead != size)
  48. {
  49. throw std::runtime_error(getEndOfStreamExceptionMsg((long)size));
  50. }
  51. return bytesRead;
  52. }
  53. template <typename CData>
  54. CData CBinaryReader::readInteger()
  55. {
  56. CData val;
  57. stream->read(reinterpret_cast<unsigned char *>(&val), sizeof(val));
  58. return readLE(val);
  59. }
  60. //FIXME: any way to do this without macro?
  61. #define INSTANTIATE(datatype, methodname) \
  62. datatype CBinaryReader::methodname() \
  63. { return readInteger<datatype>(); }
  64. // While it is certanly possible to leave only template method
  65. // but typing template parameter every time can be annoying
  66. // and templates parameters can't be resolved by return type
  67. INSTANTIATE(ui8, readUInt8)
  68. INSTANTIATE(si8, readInt8)
  69. INSTANTIATE(ui16, readUInt16)
  70. INSTANTIATE(si16, readInt16)
  71. INSTANTIATE(ui32, readUInt32)
  72. INSTANTIATE(si32, readInt32)
  73. INSTANTIATE(ui64, readUInt64)
  74. INSTANTIATE(si64, readInt64)
  75. #undef INSTANTIATE
  76. std::string CBinaryReader::readBaseString()
  77. {
  78. unsigned int len = readUInt32();
  79. assert(len <= 500000); //not too long
  80. if (len > 0)
  81. {
  82. std::string ret;
  83. ret.resize(len);
  84. read(reinterpret_cast<ui8*>(&ret[0]), len);
  85. return ret;
  86. }
  87. return "";
  88. }
  89. void CBinaryReader::skip(int count)
  90. {
  91. stream->skip(count);
  92. }
  93. std::string CBinaryReader::getEndOfStreamExceptionMsg(long bytesToRead) const
  94. {
  95. std::stringstream ss;
  96. ss << "The end of the stream was reached unexpectedly. The stream has a length of " << stream->getSize() << " and the current reading position is "
  97. << stream->tell() << ". The client wanted to read " << bytesToRead << " bytes.";
  98. return ss.str();
  99. }
  100. VCMI_LIB_NAMESPACE_END