BinaryDeserializer.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. /*
  2. * BinaryDeserializer.h, 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. #pragma once
  11. #include "CSerializer.h"
  12. #include "CTypeList.h"
  13. #include "../mapObjects/CGHeroInstance.h"
  14. #include "../../Global.h"
  15. VCMI_LIB_NAMESPACE_BEGIN
  16. class CStackInstance;
  17. class DLL_LINKAGE CLoaderBase
  18. {
  19. protected:
  20. IBinaryReader * reader;
  21. public:
  22. CLoaderBase(IBinaryReader * r): reader(r){};
  23. inline int read(void * data, unsigned size)
  24. {
  25. return reader->read(data, size);
  26. };
  27. };
  28. /// Main class for deserialization of classes from binary form
  29. /// Effectively revesed version of BinarySerializer
  30. class DLL_LINKAGE BinaryDeserializer : public CLoaderBase
  31. {
  32. template<typename Ser,typename T>
  33. struct LoadIfStackInstance
  34. {
  35. static bool invoke(Ser &s, T &data)
  36. {
  37. return false;
  38. }
  39. };
  40. template<typename Ser>
  41. struct LoadIfStackInstance<Ser, CStackInstance *>
  42. {
  43. static bool invoke(Ser &s, CStackInstance* &data)
  44. {
  45. CArmedInstance *armedObj;
  46. SlotID slot;
  47. s.load(armedObj);
  48. s.load(slot);
  49. if(slot != SlotID::COMMANDER_SLOT_PLACEHOLDER)
  50. {
  51. assert(armedObj->hasStackAtSlot(slot));
  52. data = armedObj->stacks[slot];
  53. }
  54. else
  55. {
  56. auto * hero = dynamic_cast<CGHeroInstance *>(armedObj);
  57. assert(hero);
  58. assert(hero->commander);
  59. data = hero->commander;
  60. }
  61. return true;
  62. }
  63. };
  64. template <typename T, typename Enable = void>
  65. struct ClassObjectCreator
  66. {
  67. static T *invoke()
  68. {
  69. static_assert(!std::is_abstract<T>::value, "Cannot call new upon abstract classes!");
  70. return new T();
  71. }
  72. };
  73. template<typename T>
  74. struct ClassObjectCreator<T, typename std::enable_if<std::is_abstract<T>::value>::type>
  75. {
  76. static T *invoke()
  77. {
  78. throw std::runtime_error("Something went really wrong during deserialization. Attempted creating an object of an abstract class " + std::string(typeid(T).name()));
  79. }
  80. };
  81. STRONG_INLINE ui32 readAndCheckLength()
  82. {
  83. ui32 length;
  84. load(length);
  85. //NOTE: also used for h3m's embedded in campaigns, so it may be quite large in some cases (e.g. XXL maps with multiple objects)
  86. if(length > 1000000)
  87. {
  88. logGlobal->warn("Warning: very big length: %d", length);
  89. reader->reportState(logGlobal);
  90. };
  91. return length;
  92. }
  93. template <typename Type> class CPointerLoader;
  94. class IPointerLoader
  95. {
  96. public:
  97. virtual void * loadPtr(CLoaderBase &ar, ui32 pid) const =0; //data is pointer to the ACTUAL POINTER
  98. virtual ~IPointerLoader() = default;
  99. template<typename Type> static IPointerLoader *getApplier(const Type * t = nullptr)
  100. {
  101. return new CPointerLoader<Type>();
  102. }
  103. };
  104. template <typename Type> class CPointerLoader : public IPointerLoader
  105. {
  106. public:
  107. void * loadPtr(CLoaderBase &ar, ui32 pid) const override //data is pointer to the ACTUAL POINTER
  108. {
  109. auto & s = static_cast<BinaryDeserializer &>(ar);
  110. //create new object under pointer
  111. Type * ptr = ClassObjectCreator<Type>::invoke(); //does new npT or throws for abstract classes
  112. s.ptrAllocated(ptr, pid);
  113. assert(s.fileVersion != 0);
  114. ptr->serialize(s,s.fileVersion);
  115. return static_cast<void*>(ptr);
  116. }
  117. };
  118. CApplier<IPointerLoader> applier;
  119. int write(const void * data, unsigned size);
  120. public:
  121. bool reverseEndianess; //if source has different endianness than us, we reverse bytes
  122. si32 fileVersion;
  123. std::map<ui32, void*> loadedPointers;
  124. std::map<ui32, const std::type_info*> loadedPointersTypes;
  125. std::map<const void*, std::shared_ptr<void>> loadedSharedPointers;
  126. bool smartPointerSerialization;
  127. bool saving;
  128. BinaryDeserializer(IBinaryReader * r): CLoaderBase(r)
  129. {
  130. saving = false;
  131. fileVersion = 0;
  132. smartPointerSerialization = true;
  133. reverseEndianess = false;
  134. }
  135. template<class T>
  136. BinaryDeserializer & operator&(T & t)
  137. {
  138. this->load(t);
  139. return * this;
  140. }
  141. template < class T, typename std::enable_if < std::is_fundamental<T>::value && !std::is_same<T, bool>::value, int >::type = 0 >
  142. void load(T &data)
  143. {
  144. unsigned length = sizeof(data);
  145. char * dataPtr = reinterpret_cast<char *>(&data);
  146. this->read(dataPtr,length);
  147. if(reverseEndianess)
  148. std::reverse(dataPtr, dataPtr + length);
  149. }
  150. template < typename T, typename std::enable_if < is_serializeable<BinaryDeserializer, T>::value, int >::type = 0 >
  151. void load(T &data)
  152. {
  153. assert( fileVersion != 0 );
  154. ////that const cast is evil because it allows to implicitly overwrite const objects when deserializing
  155. typedef typename std::remove_const<T>::type nonConstT;
  156. auto & hlp = const_cast<nonConstT &>(data);
  157. hlp.serialize(*this,fileVersion);
  158. }
  159. template < typename T, typename std::enable_if < std::is_array<T>::value, int >::type = 0 >
  160. void load(T &data)
  161. {
  162. ui32 size = std::size(data);
  163. for(ui32 i = 0; i < size; i++)
  164. load(data[i]);
  165. }
  166. template < typename T, typename std::enable_if < std::is_enum<T>::value, int >::type = 0 >
  167. void load(T &data)
  168. {
  169. si32 read;
  170. load( read );
  171. data = static_cast<T>(read);
  172. }
  173. template < typename T, typename std::enable_if < std::is_same<T, bool>::value, int >::type = 0 >
  174. void load(T &data)
  175. {
  176. ui8 read;
  177. load( read );
  178. data = static_cast<bool>(read);
  179. }
  180. template < typename T, typename std::enable_if < std::is_same<T, std::vector<bool> >::value, int >::type = 0 >
  181. void load(T & data)
  182. {
  183. std::vector<ui8> convData;
  184. load(convData);
  185. convData.resize(data.size());
  186. range::copy(convData, data.begin());
  187. }
  188. template <typename T, typename std::enable_if < !std::is_same<T, bool >::value, int >::type = 0>
  189. void load(std::vector<T> &data)
  190. {
  191. ui32 length = readAndCheckLength();
  192. data.resize(length);
  193. for(ui32 i=0;i<length;i++)
  194. load( data[i]);
  195. }
  196. template < typename T, typename std::enable_if < std::is_pointer<T>::value, int >::type = 0 >
  197. void load(T &data)
  198. {
  199. bool isNull;
  200. load( isNull );
  201. if(isNull)
  202. {
  203. data = nullptr;
  204. return;
  205. }
  206. loadPointerImpl(data);
  207. }
  208. template < typename T, typename std::enable_if < std::is_base_of_v<Entity, std::remove_pointer_t<T>>, int >::type = 0 >
  209. void loadPointerImpl(T &data)
  210. {
  211. using DataType = std::remove_pointer_t<T>;
  212. typename DataType::IdentifierType index;
  213. load(index);
  214. auto * constEntity = index.toEntity(VLC);
  215. auto * constData = dynamic_cast<const DataType *>(constEntity);
  216. data = const_cast<DataType *>(constData);
  217. }
  218. template < typename T, typename std::enable_if < !std::is_base_of_v<Entity, std::remove_pointer_t<T>>, int >::type = 0 >
  219. void loadPointerImpl(T &data)
  220. {
  221. if(reader->smartVectorMembersSerialization)
  222. {
  223. typedef typename std::remove_const<typename std::remove_pointer<T>::type>::type TObjectType; //eg: const CGHeroInstance * => CGHeroInstance
  224. typedef typename VectorizedTypeFor<TObjectType>::type VType; //eg: CGHeroInstance -> CGobjectInstance
  225. typedef typename VectorizedIDType<TObjectType>::type IDType;
  226. if(const auto *info = reader->getVectorizedTypeInfo<VType, IDType>())
  227. {
  228. IDType id;
  229. load(id);
  230. if(id != IDType(-1))
  231. {
  232. data = static_cast<T>(reader->getVectorItemFromId<VType, IDType>(*info, id));
  233. return;
  234. }
  235. }
  236. }
  237. if(reader->sendStackInstanceByIds)
  238. {
  239. bool gotLoaded = LoadIfStackInstance<BinaryDeserializer,T>::invoke(* this, data);
  240. if(gotLoaded)
  241. return;
  242. }
  243. ui32 pid = 0xffffffff; //pointer id (or maybe rather pointee id)
  244. if(smartPointerSerialization)
  245. {
  246. load( pid ); //get the id
  247. auto i = loadedPointers.find(pid); //lookup
  248. if(i != loadedPointers.end())
  249. {
  250. // We already got this pointer
  251. // Cast it in case we are loading it to a non-first base pointer
  252. assert(loadedPointersTypes.count(pid));
  253. data = static_cast<T>(i->second);
  254. return;
  255. }
  256. }
  257. //get type id
  258. ui16 tid;
  259. load( tid );
  260. if(!tid)
  261. {
  262. typedef typename std::remove_pointer<T>::type npT;
  263. typedef typename std::remove_const<npT>::type ncpT;
  264. data = ClassObjectCreator<ncpT>::invoke();
  265. ptrAllocated(data, pid);
  266. load(*data);
  267. }
  268. else
  269. {
  270. auto * app = applier.getApplier(tid);
  271. if(app == nullptr)
  272. {
  273. logGlobal->error("load %d %d - no loader exists", tid, pid);
  274. data = nullptr;
  275. return;
  276. }
  277. data = static_cast<T>(app->loadPtr(*this, pid));
  278. }
  279. }
  280. template <typename T>
  281. void ptrAllocated(const T *ptr, ui32 pid)
  282. {
  283. if(smartPointerSerialization && pid != 0xffffffff)
  284. {
  285. loadedPointersTypes[pid] = &typeid(T);
  286. loadedPointers[pid] = (void*)ptr; //add loaded pointer to our lookup map; cast is to avoid errors with const T* pt
  287. }
  288. }
  289. template<typename Base, typename Derived> void registerType(const Base * b = nullptr, const Derived * d = nullptr)
  290. {
  291. applier.registerType(b, d);
  292. }
  293. template <typename T>
  294. void load(std::shared_ptr<T> &data)
  295. {
  296. typedef typename std::remove_const<T>::type NonConstT;
  297. NonConstT *internalPtr;
  298. load(internalPtr);
  299. void * internalPtrDerived = static_cast<void*>(internalPtr);
  300. if(internalPtr)
  301. {
  302. auto itr = loadedSharedPointers.find(internalPtrDerived);
  303. if(itr != loadedSharedPointers.end())
  304. {
  305. // This pointers is already loaded. The "data" needs to be pointed to it,
  306. // so their shared state is actually shared.
  307. data = std::static_pointer_cast<T>(itr->second);
  308. }
  309. else
  310. {
  311. auto hlp = std::shared_ptr<NonConstT>(internalPtr);
  312. data = hlp;
  313. loadedSharedPointers[internalPtrDerived] = std::static_pointer_cast<void>(hlp);
  314. }
  315. }
  316. else
  317. data.reset();
  318. }
  319. void load(std::monostate & data)
  320. {
  321. // no-op
  322. }
  323. template <typename T>
  324. void load(std::shared_ptr<const T> & data)
  325. {
  326. std::shared_ptr<T> nonConstData;
  327. load(nonConstData);
  328. data = nonConstData;
  329. }
  330. template <typename T>
  331. void load(std::unique_ptr<T> &data)
  332. {
  333. T *internalPtr;
  334. load( internalPtr );
  335. data.reset(internalPtr);
  336. }
  337. template <typename T, size_t N>
  338. void load(std::array<T, N> &data)
  339. {
  340. for(ui32 i = 0; i < N; i++)
  341. load( data[i] );
  342. }
  343. template <typename T>
  344. void load(std::set<T> &data)
  345. {
  346. ui32 length = readAndCheckLength();
  347. data.clear();
  348. T ins;
  349. for(ui32 i=0;i<length;i++)
  350. {
  351. load( ins );
  352. data.insert(ins);
  353. }
  354. }
  355. template <typename T, typename U>
  356. void load(std::unordered_set<T, U> &data)
  357. {
  358. ui32 length = readAndCheckLength();
  359. data.clear();
  360. T ins;
  361. for(ui32 i=0;i<length;i++)
  362. {
  363. load(ins);
  364. data.insert(ins);
  365. }
  366. }
  367. template <typename T>
  368. void load(std::list<T> &data)
  369. {
  370. ui32 length = readAndCheckLength();
  371. data.clear();
  372. T ins;
  373. for(ui32 i=0;i<length;i++)
  374. {
  375. load(ins);
  376. data.push_back(ins);
  377. }
  378. }
  379. template <typename T1, typename T2>
  380. void load(std::pair<T1,T2> &data)
  381. {
  382. load(data.first);
  383. load(data.second);
  384. }
  385. template <typename T1, typename T2>
  386. void load(std::map<T1,T2> &data)
  387. {
  388. ui32 length = readAndCheckLength();
  389. data.clear();
  390. T1 key;
  391. T2 value;
  392. for(ui32 i=0;i<length;i++)
  393. {
  394. load(key);
  395. load(value);
  396. data.insert(std::pair<T1, T2>(std::move(key), std::move(value)));
  397. }
  398. }
  399. template <typename T1, typename T2>
  400. void load(std::multimap<T1, T2> &data)
  401. {
  402. ui32 length = readAndCheckLength();
  403. data.clear();
  404. T1 key;
  405. T2 value;
  406. for(ui32 i = 0; i < length; i++)
  407. {
  408. load(key);
  409. load(value);
  410. data.insert(std::pair<T1, T2>(std::move(key), std::move(value)));
  411. }
  412. }
  413. void load(std::string &data)
  414. {
  415. ui32 length = readAndCheckLength();
  416. data.resize(length);
  417. this->read((void*)data.c_str(),length);
  418. }
  419. template<typename... TN>
  420. void load(std::variant<TN...> & data)
  421. {
  422. si32 which;
  423. load( which );
  424. assert(which < sizeof...(TN));
  425. // Create array of variants that contains all default-constructed alternatives
  426. const std::variant<TN...> table[] = { TN{ }... };
  427. // use appropriate alternative for result
  428. data = table[which];
  429. // perform actual load via std::visit dispatch
  430. std::visit([&](auto& o) { load(o); }, data);
  431. }
  432. template<typename T>
  433. void load(std::optional<T> & data)
  434. {
  435. ui8 present;
  436. load( present );
  437. if(present)
  438. {
  439. //TODO: replace with emplace once we start request Boost 1.56+, see PR360
  440. T t;
  441. load(t);
  442. data = std::make_optional(std::move(t));
  443. }
  444. else
  445. {
  446. data = std::optional<T>();
  447. }
  448. }
  449. template <typename T>
  450. void load(boost::multi_array<T, 3> & data)
  451. {
  452. ui32 length = readAndCheckLength();
  453. ui32 x, y, z;
  454. load(x);
  455. load(y);
  456. load(z);
  457. data.resize(boost::extents[x][y][z]);
  458. assert(length == data.num_elements()); //x*y*z should be equal to number of elements
  459. for(ui32 i = 0; i < length; i++)
  460. load(data.data()[i]);
  461. }
  462. template <std::size_t T>
  463. void load(std::bitset<T> &data)
  464. {
  465. static_assert(T <= 64);
  466. if constexpr (T <= 16)
  467. {
  468. uint16_t read;
  469. load(read);
  470. data = read;
  471. }
  472. else if constexpr (T <= 32)
  473. {
  474. uint32_t read;
  475. load(read);
  476. data = read;
  477. }
  478. else if constexpr (T <= 64)
  479. {
  480. uint64_t read;
  481. load(read);
  482. data = read;
  483. }
  484. }
  485. };
  486. class DLL_LINKAGE CLoadFile : public IBinaryReader
  487. {
  488. public:
  489. BinaryDeserializer serializer;
  490. std::string fName;
  491. std::unique_ptr<std::fstream> sfile;
  492. CLoadFile(const boost::filesystem::path & fname, int minimalVersion = SERIALIZATION_VERSION); //throws!
  493. virtual ~CLoadFile();
  494. int read(void * data, unsigned size) override; //throws!
  495. void openNextFile(const boost::filesystem::path & fname, int minimalVersion); //throws!
  496. void clear();
  497. void reportState(vstd::CLoggerBase * out) override;
  498. void checkMagicBytes(const std::string & text);
  499. template<class T>
  500. CLoadFile & operator>>(T &t)
  501. {
  502. serializer & t;
  503. return * this;
  504. }
  505. };
  506. VCMI_LIB_NAMESPACE_END