ObjectStreamIn.cpp 15 KB

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