ObjectStreamIn.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt/Jolt.h>
  4. #include <Jolt/Core/Factory.h>
  5. #include <Jolt/ObjectStream/SerializableAttribute.h>
  6. #include <Jolt/ObjectStream/ObjectStreamIn.h>
  7. #include <Jolt/ObjectStream/ObjectStreamTextIn.h>
  8. #include <Jolt/ObjectStream/ObjectStreamBinaryIn.h>
  9. #include <Jolt/ObjectStream/SerializableObject.h>
  10. JPH_SUPPRESS_WARNINGS_STD_BEGIN
  11. #include <unordered_set>
  12. JPH_SUPPRESS_WARNINGS_STD_END
  13. JPH_NAMESPACE_BEGIN
  14. ObjectStreamIn::ObjectStreamIn(istream &inStream) :
  15. mStream(inStream)
  16. {
  17. }
  18. bool ObjectStreamIn::GetInfo(istream &inStream, EStreamType &outType, int &outVersion, int &outRevision)
  19. {
  20. // Read header and check if it is the correct format, e.g. "TOS 1.00"
  21. char header[9];
  22. memset(header, 0, 9);
  23. inStream.read(header, 8);
  24. if ((header[0] == 'B' || header[0] == 'T') && header[1] == 'O' && header[2] == 'S'
  25. && (header[3] == ' ' || isdigit(header[3])) && isdigit(header[4])
  26. && header[5] == '.' && isdigit(header[6]) && isdigit(header[7]))
  27. {
  28. // Check if this is a binary or text objectfile
  29. switch (header[0])
  30. {
  31. case 'T': outType = ObjectStream::EStreamType::Text; break;
  32. case 'B': outType = ObjectStream::EStreamType::Binary; break;
  33. default: JPH_ASSERT(false); break;
  34. }
  35. // Extract version and revision
  36. header[5] = '\0';
  37. outVersion = atoi(&header[3]);
  38. outRevision = atoi(&header[6]);
  39. return true;
  40. }
  41. Trace("ObjectStreamIn: Not a valid object stream.");
  42. return false;
  43. }
  44. ObjectStreamIn *ObjectStreamIn::Open(istream &inStream)
  45. {
  46. // Check if file is an ObjectStream of the correct version and revision
  47. EStreamType type;
  48. int version;
  49. int revision;
  50. if (GetInfo(inStream, type, version, revision))
  51. {
  52. if (version == sVersion && revision == sRevision)
  53. {
  54. // Create an input stream of the correct type
  55. switch (type)
  56. {
  57. case EStreamType::Text: return new ObjectStreamTextIn(inStream);
  58. case EStreamType::Binary: return new ObjectStreamBinaryIn(inStream);
  59. default: JPH_ASSERT(false);
  60. }
  61. }
  62. else
  63. {
  64. Trace("ObjectStreamIn: Different version stream (%d.%02d, expected %d.%02d).", version, revision, sVersion, sRevision);
  65. }
  66. }
  67. return nullptr;
  68. }
  69. void *ObjectStreamIn::Read(const RTTI *inRTTI)
  70. {
  71. using ObjectSet = unordered_set<void *>;
  72. // Read all information on the stream
  73. void *main_object = nullptr;
  74. bool continue_reading = true;
  75. for (;;)
  76. {
  77. // Get type of next operation
  78. EDataType data_type;
  79. if (!ReadDataType(data_type))
  80. break;
  81. if (data_type == EDataType::Declare)
  82. {
  83. // Read type declaration
  84. if (!ReadRTTI())
  85. {
  86. Trace("ObjectStreamIn: Fatal error while reading class description for class %s.", inRTTI->GetName());
  87. continue_reading = false;
  88. break;
  89. }
  90. }
  91. else if (data_type == EDataType::Object)
  92. {
  93. const RTTI *rtti;
  94. void *object = ReadObject(rtti);
  95. if (!main_object && object)
  96. {
  97. // This is the first and thus main object of the file.
  98. if (rtti->IsKindOf(inRTTI))
  99. {
  100. // Object is of correct type
  101. main_object = object;
  102. }
  103. else
  104. {
  105. Trace("ObjectStreamIn: Main object of different type. Expected %s, but found %s.", inRTTI->GetName(), rtti->GetName());
  106. continue_reading = false;
  107. break;
  108. }
  109. }
  110. }
  111. else
  112. {
  113. // Invalid or out of place token found
  114. Trace("ObjectStreamIn: Invalid or out of place token found.");
  115. continue_reading = false;
  116. break;
  117. }
  118. }
  119. // Resolve links (pointer, references)
  120. if (continue_reading)
  121. {
  122. // Resolve links
  123. ObjectSet referenced_objects;
  124. for (Link &link : mUnresolvedLinks)
  125. {
  126. IdentifierMap::const_iterator j = mIdentifierMap.find(link.mIdentifier);
  127. if (j != mIdentifierMap.end() && j->second.mRTTI->IsKindOf(link.mRTTI))
  128. {
  129. const ObjectInfo &obj_info = j->second;
  130. // Set pointer
  131. *link.mPointer = obj_info.mInstance;
  132. // Increment refcount if it was a referencing pointer
  133. if (link.mRefCountOffset != -1)
  134. ++(*(uint32 *)(((uint8 *)obj_info.mInstance) + link.mRefCountOffset));
  135. // Add referenced object to the list
  136. if (referenced_objects.find(obj_info.mInstance) == referenced_objects.end())
  137. referenced_objects.insert(obj_info.mInstance);
  138. }
  139. else
  140. {
  141. // Referenced object not found, set pointer to nullptr
  142. Trace("ObjectStreamIn: Setting incorrect pointer to class of type %s to nullptr.", link.mRTTI->GetName());
  143. *link.mPointer = nullptr;
  144. }
  145. }
  146. // Release unreferenced objects except the main object
  147. for (IdentifierMap::const_iterator j = mIdentifierMap.begin(); j != mIdentifierMap.end(); ++j)
  148. {
  149. const ObjectInfo &obj_info = j->second;
  150. if (obj_info.mInstance != main_object)
  151. {
  152. ObjectSet::const_iterator k = referenced_objects.find(obj_info.mInstance);
  153. if (k == referenced_objects.end())
  154. {
  155. Trace("ObjectStreamIn: Releasing unreferenced object of type %s.", obj_info.mRTTI->GetName());
  156. obj_info.mRTTI->DestructObject(obj_info.mInstance);
  157. }
  158. }
  159. }
  160. // Call OnLoaded callback
  161. unordered_set<SerializableObject *> visited_set;
  162. OSVisitCompounds(main_object, inRTTI, [&visited_set](const void *inObject, const RTTI *inType)
  163. {
  164. SerializableObject *so = const_cast<SerializableObject *>(reinterpret_cast<const SerializableObject *>(inType->CastTo(inObject, JPH_RTTI(SerializableObject))));
  165. if (so != nullptr && visited_set.insert(so).second)
  166. so->OnLoaded();
  167. });
  168. return main_object;
  169. }
  170. else
  171. {
  172. // Release all objects if a fatal error occurred
  173. for (IdentifierMap::iterator i = mIdentifierMap.begin(); i != mIdentifierMap.end(); ++i)
  174. {
  175. const ObjectInfo &obj_info = i->second;
  176. obj_info.mRTTI->DestructObject(obj_info.mInstance);
  177. }
  178. return nullptr;
  179. }
  180. }
  181. void *ObjectStreamIn::ReadObject(const RTTI *& outRTTI)
  182. {
  183. // Read the object class
  184. void *object = nullptr;
  185. string class_name;
  186. if (ReadName(class_name))
  187. {
  188. // Get class description
  189. ClassDescriptionMap::iterator i = mClassDescriptionMap.find(class_name);
  190. if (i != mClassDescriptionMap.end())
  191. {
  192. const ClassDescription &class_desc = i->second;
  193. // Read object identifier
  194. Identifier identifier;
  195. if (ReadIdentifier(identifier))
  196. {
  197. // Check if this object can be read or must be skipped
  198. if (identifier != sNullIdentifier
  199. && class_desc.mRTTI
  200. && !class_desc.mRTTI->IsAbstract())
  201. {
  202. // Create object instance
  203. outRTTI = class_desc.mRTTI;
  204. object = outRTTI->CreateObject();
  205. // Read object attributes
  206. if (ReadClassData(class_desc, object))
  207. {
  208. // Add object to identifier map
  209. mIdentifierMap.insert(IdentifierMap::value_type(identifier, ObjectInfo(object, outRTTI)));
  210. }
  211. else
  212. {
  213. // Fatal error while reading attributes, release object
  214. outRTTI->DestructObject(object);
  215. object = nullptr;
  216. }
  217. }
  218. else
  219. {
  220. // Skip this object
  221. // TODO: This operation can fail, but there is no check yet
  222. Trace("ObjectStreamIn: Found uncreatable object %s.", class_name.c_str());
  223. ReadClassData(class_desc, nullptr);
  224. }
  225. }
  226. }
  227. else
  228. {
  229. // TODO: This is a fatal error, but this function has no way of indicating this
  230. Trace("ObjectStreamIn: Found object of unknown class %s.", class_name.c_str());
  231. }
  232. }
  233. return object;
  234. }
  235. bool ObjectStreamIn::ReadRTTI()
  236. {
  237. // Read class name and find it's attribute info
  238. string class_name;
  239. if (!ReadName(class_name))
  240. return false;
  241. // Find class
  242. const RTTI *rtti = Factory::sInstance.Find(class_name.c_str());
  243. if (rtti == nullptr)
  244. Trace("ObjectStreamIn: Unknown class: \"%s\".", class_name.c_str());
  245. // Insert class description
  246. mClassDescriptionMap.insert(ClassDescriptionMap::value_type(class_name, ClassDescription(rtti)));
  247. ClassDescription &class_desc = mClassDescriptionMap.find(class_name)->second;
  248. // Read the number of entries in the description
  249. uint32 count;
  250. if (!ReadCount(count))
  251. return false;
  252. // Read the entries
  253. for (uint32 i = 0; i < count; ++i)
  254. {
  255. AttributeDescription attribute;
  256. // Read name
  257. string attribute_name;
  258. if (!ReadName(attribute_name))
  259. return false;
  260. // Read type
  261. if (!ReadDataType(attribute.mDataType))
  262. return false;
  263. // Read array depth
  264. while (attribute.mDataType == EDataType::Array)
  265. {
  266. ++attribute.mArrayDepth;
  267. if (!ReadDataType(attribute.mDataType))
  268. return false;
  269. }
  270. // Read instance/pointer class name
  271. if (attribute.mDataType == EDataType::Instance || attribute.mDataType == EDataType::Pointer)
  272. if (!ReadName(attribute.mClassName))
  273. return false;
  274. // Find attribute in rtti
  275. if (rtti)
  276. {
  277. // Find attribute index
  278. for (int idx = 0; idx < rtti->GetAttributeCount(); ++idx)
  279. {
  280. const SerializableAttribute *attr = DynamicCast<SerializableAttribute, RTTIAttribute>(rtti->GetAttribute(idx));
  281. if (attr != nullptr && strcmp(attr->GetName(), attribute_name.c_str()) == 0)
  282. {
  283. attribute.mIndex = idx;
  284. break;
  285. }
  286. }
  287. // Check if attribute is of expected type
  288. if (attribute.mIndex >= 0)
  289. {
  290. const SerializableAttribute *attr = (const SerializableAttribute *)rtti->GetAttribute(attribute.mIndex);
  291. if (!attr->IsType(attribute.mArrayDepth, attribute.mDataType, attribute.mClassName.c_str()))
  292. attribute.mIndex = -1;
  293. }
  294. }
  295. // Add attribute to the class description
  296. class_desc.mAttributes.push_back(attribute);
  297. }
  298. return true;
  299. }
  300. bool ObjectStreamIn::ReadClassData(const char *inClassName, void *inInstance)
  301. {
  302. // Find the class description
  303. ClassDescriptionMap::iterator i = mClassDescriptionMap.find(inClassName);
  304. if (i != mClassDescriptionMap.end())
  305. return ReadClassData(i->second, inInstance);
  306. return false;
  307. }
  308. bool ObjectStreamIn::ReadClassData(const ClassDescription &inClassDesc, void *inInstance)
  309. {
  310. // Read data for this class
  311. bool continue_reading = true;
  312. for (const AttributeDescription &attr_desc : inClassDesc.mAttributes)
  313. {
  314. // Read or skip the attribute data
  315. if (attr_desc.mIndex >= 0 && inInstance)
  316. {
  317. const SerializableAttribute *attr = (const SerializableAttribute *)inClassDesc.mRTTI->GetAttribute(attr_desc.mIndex);
  318. continue_reading = attr->ReadData(*this, inInstance);
  319. }
  320. else
  321. continue_reading = SkipAttributeData(attr_desc.mArrayDepth, attr_desc.mDataType, attr_desc.mClassName.c_str());
  322. if (!continue_reading)
  323. break;
  324. }
  325. return continue_reading;
  326. }
  327. bool ObjectStreamIn::ReadPointerData(const RTTI *inRTTI, void **inPointer, int inRefCountOffset)
  328. {
  329. Identifier identifier;
  330. if (ReadIdentifier(identifier))
  331. {
  332. if (identifier == sNullIdentifier)
  333. {
  334. // Set nullptr pointer
  335. inPointer = nullptr;
  336. }
  337. else
  338. {
  339. // Put pointer on the list to be resolved later on
  340. mUnresolvedLinks.push_back(Link());
  341. mUnresolvedLinks.back().mPointer = inPointer;
  342. mUnresolvedLinks.back().mRefCountOffset = inRefCountOffset;
  343. mUnresolvedLinks.back().mIdentifier = identifier;
  344. mUnresolvedLinks.back().mRTTI = inRTTI;
  345. }
  346. return true;
  347. }
  348. return false;
  349. }
  350. bool ObjectStreamIn::SkipAttributeData(int inArrayDepth, EDataType inDataType, const char *inClassName)
  351. {
  352. bool continue_reading = true;
  353. // Get number of items to read
  354. uint32 count = 1;
  355. for (; inArrayDepth > 0; --inArrayDepth)
  356. {
  357. uint32 temporary;
  358. if (ReadCount(temporary))
  359. {
  360. // Multiply for multi dimensional arrays
  361. count *= temporary;
  362. }
  363. else
  364. {
  365. // Fatal error while reading array size
  366. continue_reading = false;
  367. break;
  368. }
  369. }
  370. // Read data for all items
  371. if (continue_reading)
  372. {
  373. if (inDataType == EDataType::Instance)
  374. {
  375. // Get the class description
  376. ClassDescriptionMap::iterator i = mClassDescriptionMap.find(inClassName);
  377. if (i != mClassDescriptionMap.end())
  378. {
  379. for (; count > 0 && continue_reading; --count)
  380. continue_reading = ReadClassData(i->second, nullptr);
  381. }
  382. else
  383. {
  384. continue_reading = false;
  385. Trace("ObjectStreamIn: Found instance of unknown class %s.", inClassName);
  386. }
  387. }
  388. else
  389. {
  390. for (; count > 0 && continue_reading; --count)
  391. {
  392. switch (inDataType)
  393. {
  394. case EDataType::Pointer:
  395. {
  396. Identifier temporary;
  397. continue_reading = ReadIdentifier(temporary);
  398. break;
  399. }
  400. case EDataType::T_uint8:
  401. {
  402. uint8 temporary;
  403. continue_reading = ReadPrimitiveData(temporary);
  404. break;
  405. }
  406. case EDataType::T_uint16:
  407. {
  408. uint16 temporary;
  409. continue_reading = ReadPrimitiveData(temporary);
  410. break;
  411. }
  412. case EDataType::T_int:
  413. {
  414. int temporary;
  415. continue_reading = ReadPrimitiveData(temporary);
  416. break;
  417. }
  418. case EDataType::T_uint32:
  419. {
  420. uint32 temporary;
  421. continue_reading = ReadPrimitiveData(temporary);
  422. break;
  423. }
  424. case EDataType::T_uint64:
  425. {
  426. uint64 temporary;
  427. continue_reading = ReadPrimitiveData(temporary);
  428. break;
  429. }
  430. case EDataType::T_float:
  431. {
  432. float temporary;
  433. continue_reading = ReadPrimitiveData(temporary);
  434. break;
  435. }
  436. case EDataType::T_bool:
  437. {
  438. bool temporary;
  439. continue_reading = ReadPrimitiveData(temporary);
  440. break;
  441. }
  442. case EDataType::T_string:
  443. {
  444. string temporary;
  445. continue_reading = ReadPrimitiveData(temporary);
  446. break;
  447. }
  448. case EDataType::T_Float3:
  449. {
  450. Float3 temporary;
  451. continue_reading = ReadPrimitiveData(temporary);
  452. break;
  453. }
  454. case EDataType::T_Vec3:
  455. {
  456. Vec3 temporary;
  457. continue_reading = ReadPrimitiveData(temporary);
  458. break;
  459. }
  460. case EDataType::T_Vec4:
  461. {
  462. Vec4 temporary;
  463. continue_reading = ReadPrimitiveData(temporary);
  464. break;
  465. }
  466. case EDataType::T_Quat:
  467. {
  468. Quat temporary;
  469. continue_reading = ReadPrimitiveData(temporary);
  470. break;
  471. }
  472. case EDataType::T_Mat44:
  473. {
  474. Mat44 temporary;
  475. continue_reading = ReadPrimitiveData(temporary);
  476. break;
  477. }
  478. case EDataType::Array:
  479. case EDataType::Object:
  480. case EDataType::Declare:
  481. case EDataType::Instance:
  482. case EDataType::Invalid:
  483. default:
  484. continue_reading = false;
  485. break;
  486. }
  487. }
  488. }
  489. }
  490. return continue_reading;
  491. }
  492. // Define macro to declare functions for a specific primitive type
  493. #define JPH_DECLARE_PRIMITIVE(name) \
  494. bool OSReadData(ObjectStreamIn &ioStream, name &outPrimitive) \
  495. { \
  496. return ioStream.ReadPrimitiveData(outPrimitive); \
  497. }
  498. // This file uses the JPH_DECLARE_PRIMITIVE macro to define all types
  499. #include <Jolt/ObjectStream/ObjectStreamTypes.h>
  500. JPH_NAMESPACE_END