CBinaryReader.cpp 2.4 KB

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