ObjectStreamIn.cpp 15 KB

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