2
0

ObjectStreamIn.cpp 15 KB

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