CBinaryReader.cpp 2.5 KB

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