BinaryDeserializer.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /*
  2. * BinaryDeserializer.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 "BinaryDeserializer.h"
  12. #include "../registerTypes/RegisterTypes.h"
  13. VCMI_LIB_NAMESPACE_BEGIN
  14. extern template void registerTypes<BinaryDeserializer>(BinaryDeserializer & s);
  15. CLoadFile::CLoadFile(const boost::filesystem::path & fname, int minimalVersion)
  16. : serializer(this)
  17. {
  18. registerTypes(serializer);
  19. openNextFile(fname, minimalVersion);
  20. }
  21. //must be instantiated in .cpp file for access to complete types of all member fields
  22. CLoadFile::~CLoadFile() = default;
  23. int CLoadFile::read(void * data, unsigned size)
  24. {
  25. sfile->read(reinterpret_cast<char *>(data), size);
  26. return size;
  27. }
  28. void CLoadFile::openNextFile(const boost::filesystem::path & fname, int minimalVersion)
  29. {
  30. assert(!serializer.reverseEndianess);
  31. assert(minimalVersion <= SERIALIZATION_VERSION);
  32. try
  33. {
  34. fName = fname.string();
  35. sfile = std::make_unique<std::fstream>(fname.c_str(), std::ios::in | std::ios::binary);
  36. sfile->exceptions(std::ifstream::failbit | std::ifstream::badbit); //we throw a lot anyway
  37. if(!(*sfile))
  38. THROW_FORMAT("Error: cannot open to read %s!", fName);
  39. //we can read
  40. char buffer[4];
  41. sfile->read(buffer, 4);
  42. if(std::memcmp(buffer, "VCMI", 4) != 0)
  43. THROW_FORMAT("Error: not a VCMI file(%s)!", fName);
  44. serializer & serializer.fileVersion;
  45. if(serializer.fileVersion < minimalVersion)
  46. THROW_FORMAT("Error: too old file format (%s)!", fName);
  47. if(serializer.fileVersion > SERIALIZATION_VERSION)
  48. {
  49. logGlobal->warn("Warning format version mismatch: found %d when current is %d! (file %s)\n", serializer.fileVersion, SERIALIZATION_VERSION , fName);
  50. auto * versionptr = reinterpret_cast<char *>(&serializer.fileVersion);
  51. std::reverse(versionptr, versionptr + 4);
  52. logGlobal->warn("Version number reversed is %x, checking...", serializer.fileVersion);
  53. if(serializer.fileVersion == SERIALIZATION_VERSION)
  54. {
  55. logGlobal->warn("%s seems to have different endianness! Entering reversing mode.", fname.string());
  56. serializer.reverseEndianess = true;
  57. }
  58. else
  59. THROW_FORMAT("Error: too new file format (%s)!", fName);
  60. }
  61. }
  62. catch(...)
  63. {
  64. clear(); //if anything went wrong, we delete file and rethrow
  65. throw;
  66. }
  67. }
  68. void CLoadFile::reportState(vstd::CLoggerBase * out)
  69. {
  70. out->debug("CLoadFile");
  71. if(!!sfile && *sfile)
  72. out->debug("\tOpened %s Position: %d", fName, sfile->tellg());
  73. }
  74. void CLoadFile::clear()
  75. {
  76. sfile = nullptr;
  77. fName.clear();
  78. serializer.fileVersion = 0;
  79. }
  80. void CLoadFile::checkMagicBytes(const std::string &text)
  81. {
  82. std::string loaded = text;
  83. read((void *)loaded.data(), static_cast<unsigned int>(text.length()));
  84. if(loaded != text)
  85. throw std::runtime_error("Magic bytes doesn't match!");
  86. }
  87. VCMI_LIB_NAMESPACE_END