1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #include "Serialization/BsSerializedObject.h" |
4 | #include "Private/RTTI/BsSerializedObjectRTTI.h" |
5 | |
6 | namespace bs |
7 | { |
8 | namespace detail |
9 | { |
10 | /** Helper class for performing SerializedObject <-> IReflectable encoding & decoding. */ |
11 | class BS_UTILITY_EXPORT IntermediateSerializer |
12 | { |
13 | public: |
14 | IntermediateSerializer(); |
15 | |
16 | /** Encodes an IReflectable object into an intermediate representation. */ |
17 | SPtr<SerializedObject> encode(IReflectable* object, bool shallow = false, |
18 | SerializationContext* context = nullptr); |
19 | |
20 | /** Decodes an intermediate representation of a serialized object into the actual object. */ |
21 | SPtr<IReflectable> decode(const SerializedObject* serializedObject, |
22 | SerializationContext* context = nullptr); |
23 | |
24 | private: |
25 | struct ObjectToDecode |
26 | { |
27 | ObjectToDecode(const SPtr<IReflectable>& _object, const SerializedObject* serializedObject) |
28 | :object(_object), serializedObject(serializedObject) |
29 | { } |
30 | |
31 | SPtr<IReflectable> object; |
32 | const SerializedObject* serializedObject; |
33 | bool isDecoded = false; |
34 | bool decodeInProgress = false; // Used for error reporting circular references |
35 | }; |
36 | |
37 | /** Decodes a single IReflectable object. */ |
38 | void decodeEntry(const SPtr<IReflectable>& object, const SerializedObject* serializableObject); |
39 | |
40 | /** Encodes a single IReflectable object. */ |
41 | SPtr<SerializedObject> encodeEntry(IReflectable* object, bool shallow); |
42 | |
43 | UnorderedMap<const SerializedObject*, ObjectToDecode> mObjectMap; |
44 | SerializationContext* mContext = nullptr; |
45 | FrameAlloc* mAlloc = nullptr; |
46 | }; |
47 | |
48 | IntermediateSerializer::IntermediateSerializer() |
49 | :mAlloc(&gFrameAlloc()) |
50 | { } |
51 | |
52 | SPtr<IReflectable> IntermediateSerializer::decode(const SerializedObject* serializedObject, |
53 | SerializationContext* context) |
54 | { |
55 | mContext = context; |
56 | |
57 | mAlloc->markFrame(); |
58 | mObjectMap.clear(); |
59 | |
60 | SPtr<IReflectable> output; |
61 | RTTITypeBase* type = IReflectable::_getRTTIfromTypeId(serializedObject->getRootTypeId()); |
62 | if (type != nullptr) |
63 | { |
64 | output = type->newRTTIObject(); |
65 | auto iterNewObj = mObjectMap.insert(std::make_pair(serializedObject, ObjectToDecode(output, serializedObject))); |
66 | |
67 | iterNewObj.first->second.decodeInProgress = true; |
68 | decodeEntry(output, serializedObject); |
69 | iterNewObj.first->second.decodeInProgress = false; |
70 | iterNewObj.first->second.isDecoded = true; |
71 | } |
72 | |
73 | // Go through the remaining objects (should be only ones with weak refs) |
74 | for (auto iter = mObjectMap.begin(); iter != mObjectMap.end(); ++iter) |
75 | { |
76 | ObjectToDecode& objToDecode = iter->second; |
77 | |
78 | if (objToDecode.isDecoded) |
79 | continue; |
80 | |
81 | objToDecode.decodeInProgress = true; |
82 | decodeEntry(objToDecode.object, objToDecode.serializedObject); |
83 | objToDecode.decodeInProgress = false; |
84 | objToDecode.isDecoded = true; |
85 | } |
86 | |
87 | mObjectMap.clear(); |
88 | mAlloc->clear(); |
89 | |
90 | return output; |
91 | } |
92 | |
93 | SPtr<SerializedObject> IntermediateSerializer::encode(IReflectable* object, bool shallow, |
94 | SerializationContext* context) |
95 | { |
96 | mContext = context; |
97 | |
98 | return encodeEntry(object, shallow); |
99 | } |
100 | |
101 | void IntermediateSerializer::decodeEntry(const SPtr<IReflectable>& object, const SerializedObject* serializableObject) |
102 | { |
103 | UINT32 numSubObjects = (UINT32)serializableObject->subObjects.size(); |
104 | if (numSubObjects == 0) |
105 | return; |
106 | |
107 | FrameStack<RTTITypeBase*> rttiInstances; |
108 | for (INT32 subObjectIdx = numSubObjects - 1; subObjectIdx >= 0; subObjectIdx--) |
109 | { |
110 | const SerializedSubObject& subObject = serializableObject->subObjects[subObjectIdx]; |
111 | |
112 | RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(subObject.typeId); |
113 | if (rtti == nullptr) |
114 | continue; |
115 | |
116 | RTTITypeBase* rttiInstance = rtti->_clone(*mAlloc); |
117 | rttiInstance->onDeserializationStarted(object.get(), mContext); |
118 | rttiInstances.push(rttiInstance); |
119 | |
120 | UINT32 numFields = rtti->getNumFields(); |
121 | for (UINT32 fieldIdx = 0; fieldIdx < numFields; fieldIdx++) |
122 | { |
123 | RTTIField* curGenericField = rtti->getField(fieldIdx); |
124 | |
125 | auto iterFindFieldData = subObject.entries.find(curGenericField->mUniqueId); |
126 | if (iterFindFieldData == subObject.entries.end()) |
127 | continue; |
128 | |
129 | SPtr<SerializedInstance> entryData = iterFindFieldData->second.serialized; |
130 | if (curGenericField->isArray()) |
131 | { |
132 | SPtr<SerializedArray> arrayData = std::static_pointer_cast<SerializedArray>(entryData); |
133 | |
134 | UINT32 arrayNumElems = (UINT32)arrayData->numElements; |
135 | curGenericField->setArraySize(rttiInstance, object.get(), arrayNumElems); |
136 | |
137 | switch (curGenericField->mType) |
138 | { |
139 | case SerializableFT_ReflectablePtr: |
140 | { |
141 | RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField); |
142 | |
143 | for (auto& arrayElem : arrayData->entries) |
144 | { |
145 | SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized); |
146 | RTTITypeBase* childRtti = nullptr; |
147 | |
148 | if (arrayElemData != nullptr) |
149 | childRtti = IReflectable::_getRTTIfromTypeId(arrayElemData->getRootTypeId()); |
150 | |
151 | if (childRtti != nullptr) |
152 | { |
153 | auto findObj = mObjectMap.find(arrayElemData.get()); |
154 | if (findObj == mObjectMap.end()) |
155 | { |
156 | SPtr<IReflectable> newObject = childRtti->newRTTIObject(); |
157 | findObj = mObjectMap.insert(std::make_pair(arrayElemData.get(), |
158 | ObjectToDecode(newObject, arrayElemData.get()))).first; |
159 | } |
160 | |
161 | ObjectToDecode& objToDecode = findObj->second; |
162 | |
163 | bool needsDecoding = !curField->getInfo().flags.isSet(RTTIFieldFlag::WeakRef) && !objToDecode.isDecoded; |
164 | if (needsDecoding) |
165 | { |
166 | if (objToDecode.decodeInProgress) |
167 | { |
168 | LOGWRN("Detected a circular reference when decoding. Referenced object fields " \ |
169 | "will be resolved in an undefined order (i.e. one of the objects will not " \ |
170 | "be fully deserialized when assigned to its field). Use RTTI_Flag_WeakRef to " \ |
171 | "get rid of this warning and tell the system which of the objects is allowed " \ |
172 | "to be deserialized after it is assigned to its field." ); |
173 | } |
174 | else |
175 | { |
176 | objToDecode.decodeInProgress = true; |
177 | decodeEntry(objToDecode.object, objToDecode.serializedObject); |
178 | objToDecode.decodeInProgress = false; |
179 | objToDecode.isDecoded = true; |
180 | } |
181 | } |
182 | |
183 | curField->setArrayValue(rttiInstance, object.get(), arrayElem.first, objToDecode.object); |
184 | } |
185 | else |
186 | { |
187 | curField->setArrayValue(rttiInstance, object.get(), arrayElem.first, nullptr); |
188 | } |
189 | } |
190 | } |
191 | break; |
192 | case SerializableFT_Reflectable: |
193 | { |
194 | RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField); |
195 | |
196 | for (auto& arrayElem : arrayData->entries) |
197 | { |
198 | SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized); |
199 | RTTITypeBase* childRtti = nullptr; |
200 | |
201 | if (arrayElemData != nullptr) |
202 | childRtti = IReflectable::_getRTTIfromTypeId(arrayElemData->getRootTypeId()); |
203 | |
204 | if (childRtti != nullptr) |
205 | { |
206 | SPtr<IReflectable> newObject = childRtti->newRTTIObject(); |
207 | decodeEntry(newObject, arrayElemData.get()); |
208 | curField->setArrayValue(rttiInstance, object.get(), arrayElem.first, *newObject); |
209 | } |
210 | } |
211 | break; |
212 | } |
213 | case SerializableFT_Plain: |
214 | { |
215 | RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField); |
216 | |
217 | for (auto& arrayElem : arrayData->entries) |
218 | { |
219 | SPtr<SerializedField> fieldData = std::static_pointer_cast<SerializedField>(arrayElem.second.serialized); |
220 | if (fieldData != nullptr) |
221 | { |
222 | curField->arrayElemFromBuffer(rttiInstance, object.get(), arrayElem.first, fieldData->value); |
223 | } |
224 | } |
225 | } |
226 | break; |
227 | default: |
228 | break; |
229 | } |
230 | } |
231 | else |
232 | { |
233 | switch (curGenericField->mType) |
234 | { |
235 | case SerializableFT_ReflectablePtr: |
236 | { |
237 | RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField); |
238 | |
239 | SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(entryData); |
240 | RTTITypeBase* childRtti = nullptr; |
241 | |
242 | if (fieldObjectData != nullptr) |
243 | childRtti = IReflectable::_getRTTIfromTypeId(fieldObjectData->getRootTypeId()); |
244 | |
245 | if (childRtti != nullptr) |
246 | { |
247 | auto findObj = mObjectMap.find(fieldObjectData.get()); |
248 | if (findObj == mObjectMap.end()) |
249 | { |
250 | SPtr<IReflectable> newObject = childRtti->newRTTIObject(); |
251 | findObj = mObjectMap.insert(std::make_pair(fieldObjectData.get(), |
252 | ObjectToDecode(newObject, fieldObjectData.get()))).first; |
253 | } |
254 | |
255 | ObjectToDecode& objToDecode = findObj->second; |
256 | |
257 | bool needsDecoding = !curField->getInfo().flags.isSet(RTTIFieldFlag::WeakRef) && !objToDecode.isDecoded; |
258 | if (needsDecoding) |
259 | { |
260 | if (objToDecode.decodeInProgress) |
261 | { |
262 | LOGWRN("Detected a circular reference when decoding. Referenced object's fields " \ |
263 | "will be resolved in an undefined order (i.e. one of the objects will not " \ |
264 | "be fully deserialized when assigned to its field). Use RTTI_Flag_WeakRef to " \ |
265 | "get rid of this warning and tell the system which of the objects is allowed " \ |
266 | "to be deserialized after it is assigned to its field." ); |
267 | } |
268 | else |
269 | { |
270 | objToDecode.decodeInProgress = true; |
271 | decodeEntry(objToDecode.object, objToDecode.serializedObject); |
272 | objToDecode.decodeInProgress = false; |
273 | objToDecode.isDecoded = true; |
274 | } |
275 | } |
276 | |
277 | curField->setValue(rttiInstance, object.get(), objToDecode.object); |
278 | } |
279 | else |
280 | { |
281 | curField->setValue(rttiInstance, object.get(), nullptr); |
282 | } |
283 | } |
284 | break; |
285 | case SerializableFT_Reflectable: |
286 | { |
287 | RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField); |
288 | |
289 | SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(entryData); |
290 | RTTITypeBase* childRtti = nullptr; |
291 | |
292 | if (fieldObjectData != nullptr) |
293 | childRtti = IReflectable::_getRTTIfromTypeId(fieldObjectData->getRootTypeId()); |
294 | |
295 | if (childRtti != nullptr) |
296 | { |
297 | SPtr<IReflectable> newObject = childRtti->newRTTIObject(); |
298 | decodeEntry(newObject, fieldObjectData.get()); |
299 | curField->setValue(rttiInstance, object.get(), *newObject); |
300 | } |
301 | break; |
302 | } |
303 | case SerializableFT_Plain: |
304 | { |
305 | RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField); |
306 | |
307 | SPtr<SerializedField> fieldData = std::static_pointer_cast<SerializedField>(entryData); |
308 | if (fieldData != nullptr) |
309 | { |
310 | curField->fromBuffer(rttiInstance, object.get(), fieldData->value); |
311 | } |
312 | } |
313 | break; |
314 | case SerializableFT_DataBlock: |
315 | { |
316 | RTTIManagedDataBlockFieldBase* curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField); |
317 | |
318 | SPtr<SerializedDataBlock> fieldData = std::static_pointer_cast<SerializedDataBlock>(entryData); |
319 | if (fieldData != nullptr) |
320 | { |
321 | fieldData->stream->seek(fieldData->offset); |
322 | curField->setValue(rttiInstance, object.get(), fieldData->stream, fieldData->size); |
323 | } |
324 | |
325 | break; |
326 | } |
327 | } |
328 | } |
329 | } |
330 | } |
331 | |
332 | while (!rttiInstances.empty()) |
333 | { |
334 | RTTITypeBase* rttiInstance = rttiInstances.top(); |
335 | rttiInstance->onDeserializationEnded(object.get(), mContext); |
336 | mAlloc->destruct(rttiInstance); |
337 | |
338 | rttiInstances.pop(); |
339 | } |
340 | } |
341 | |
342 | SPtr<SerializedObject> IntermediateSerializer::encodeEntry(IReflectable* object, bool shallow) |
343 | { |
344 | FrameStack<RTTITypeBase*> rttiInstances; |
345 | RTTITypeBase* rtti = object->getRTTI(); |
346 | |
347 | const auto cleanup = [&]() |
348 | { |
349 | while (!rttiInstances.empty()) |
350 | { |
351 | RTTITypeBase* rttiInstance = rttiInstances.top(); |
352 | rttiInstance->onSerializationEnded(object, mContext); |
353 | mAlloc->destruct(rttiInstance); |
354 | |
355 | rttiInstances.pop(); |
356 | } |
357 | }; |
358 | |
359 | SPtr<SerializedObject> output = bs_shared_ptr_new<SerializedObject>(); |
360 | |
361 | // If an object has base classes, we need to iterate through all of them |
362 | do |
363 | { |
364 | RTTITypeBase* rttiInstance = rtti->_clone(*mAlloc); |
365 | rttiInstances.push(rttiInstance); |
366 | |
367 | rttiInstance->onSerializationStarted(object, mContext); |
368 | |
369 | output->subObjects.push_back(SerializedSubObject()); |
370 | SerializedSubObject& subObject = output->subObjects.back(); |
371 | subObject.typeId = rtti->getRTTIId(); |
372 | |
373 | const UINT32 numFields = rtti->getNumFields(); |
374 | for (UINT32 i = 0; i < numFields; i++) |
375 | { |
376 | SPtr<SerializedInstance> serializedEntry; |
377 | |
378 | RTTIField* curGenericField = rtti->getField(i); |
379 | if (curGenericField->mIsVectorType) |
380 | { |
381 | const UINT32 arrayNumElems = curGenericField->getArraySize(rttiInstance, object); |
382 | |
383 | const SPtr<SerializedArray> serializedArray = bs_shared_ptr_new<SerializedArray>(); |
384 | serializedArray->numElements = arrayNumElems; |
385 | |
386 | serializedEntry = serializedArray; |
387 | |
388 | switch (curGenericField->mType) |
389 | { |
390 | case SerializableFT_ReflectablePtr: |
391 | { |
392 | auto curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField); |
393 | |
394 | for (UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++) |
395 | { |
396 | SPtr<SerializedObject> serializedChildObj = nullptr; |
397 | |
398 | if (!shallow) |
399 | { |
400 | SPtr<IReflectable> childObject = curField->getArrayValue(rttiInstance, object, arrIdx); |
401 | |
402 | if (childObject) |
403 | serializedChildObj = encodeEntry(childObject.get(), shallow); |
404 | } |
405 | |
406 | SerializedArrayEntry arrayEntry; |
407 | arrayEntry.serialized = serializedChildObj; |
408 | arrayEntry.index = arrIdx; |
409 | |
410 | serializedArray->entries[arrIdx] = arrayEntry; |
411 | } |
412 | |
413 | break; |
414 | } |
415 | case SerializableFT_Reflectable: |
416 | { |
417 | auto curField = static_cast<RTTIReflectableFieldBase*>(curGenericField); |
418 | |
419 | for (UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++) |
420 | { |
421 | IReflectable& childObject = curField->getArrayValue(rttiInstance, object, arrIdx); |
422 | |
423 | const SPtr<SerializedObject> serializedChildObj = encodeEntry(&childObject, shallow); |
424 | |
425 | SerializedArrayEntry arrayEntry; |
426 | arrayEntry.serialized = serializedChildObj; |
427 | arrayEntry.index = arrIdx; |
428 | |
429 | serializedArray->entries[arrIdx] = arrayEntry; |
430 | } |
431 | |
432 | break; |
433 | } |
434 | case SerializableFT_Plain: |
435 | { |
436 | auto curField = static_cast<RTTIPlainFieldBase*>(curGenericField); |
437 | |
438 | for (UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++) |
439 | { |
440 | UINT32 typeSize = 0; |
441 | if (curField->hasDynamicSize()) |
442 | typeSize = curField->getArrayElemDynamicSize(rttiInstance, object, arrIdx); |
443 | else |
444 | typeSize = curField->getTypeSize(); |
445 | |
446 | const auto serializedField = bs_shared_ptr_new<SerializedField>(); |
447 | serializedField->value = (UINT8*)bs_alloc(typeSize); |
448 | serializedField->ownsMemory = true; |
449 | serializedField->size = typeSize; |
450 | |
451 | curField->arrayElemToBuffer(rttiInstance, object, arrIdx, serializedField->value); |
452 | |
453 | SerializedArrayEntry arrayEntry; |
454 | arrayEntry.serialized = serializedField; |
455 | arrayEntry.index = arrIdx; |
456 | |
457 | serializedArray->entries[arrIdx] = arrayEntry; |
458 | } |
459 | |
460 | break; |
461 | } |
462 | default: |
463 | BS_EXCEPT(InternalErrorException, |
464 | "Error encoding data. Encountered a type I don't know how to encode. Type: " + toString(UINT32(curGenericField->mType)) + |
465 | ", Is array: " + toString(curGenericField->mIsVectorType)); |
466 | } |
467 | } |
468 | else |
469 | { |
470 | switch (curGenericField->mType) |
471 | { |
472 | case SerializableFT_ReflectablePtr: |
473 | { |
474 | auto curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField); |
475 | |
476 | if (!shallow) |
477 | { |
478 | SPtr<IReflectable> childObject = curField->getValue(rttiInstance, object); |
479 | |
480 | if (childObject) |
481 | serializedEntry = encodeEntry(childObject.get(), shallow); |
482 | } |
483 | |
484 | break; |
485 | } |
486 | case SerializableFT_Reflectable: |
487 | { |
488 | auto curField = static_cast<RTTIReflectableFieldBase*>(curGenericField); |
489 | IReflectable& childObject = curField->getValue(rttiInstance, object); |
490 | |
491 | serializedEntry = encodeEntry(&childObject, shallow); |
492 | |
493 | break; |
494 | } |
495 | case SerializableFT_Plain: |
496 | { |
497 | auto curField = static_cast<RTTIPlainFieldBase*>(curGenericField); |
498 | |
499 | UINT32 typeSize = 0; |
500 | if (curField->hasDynamicSize()) |
501 | typeSize = curField->getDynamicSize(rttiInstance, object); |
502 | else |
503 | typeSize = curField->getTypeSize(); |
504 | |
505 | const auto serializedField = bs_shared_ptr_new<SerializedField>(); |
506 | serializedField->value = (UINT8*)bs_alloc(typeSize); |
507 | serializedField->ownsMemory = true; |
508 | serializedField->size = typeSize; |
509 | |
510 | curField->toBuffer(rttiInstance, object, serializedField->value); |
511 | |
512 | serializedEntry = serializedField; |
513 | |
514 | break; |
515 | } |
516 | case SerializableFT_DataBlock: |
517 | { |
518 | auto curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField); |
519 | |
520 | UINT32 dataBlockSize = 0; |
521 | SPtr<DataStream> blockStream = curField->getValue(rttiInstance, object, dataBlockSize); |
522 | |
523 | auto dataBlockBuffer = (UINT8*)bs_alloc(dataBlockSize); |
524 | blockStream->read(dataBlockBuffer, dataBlockSize); |
525 | |
526 | SPtr<DataStream> stream = bs_shared_ptr_new<MemoryDataStream>(dataBlockBuffer, dataBlockSize); |
527 | |
528 | SPtr<SerializedDataBlock> serializedDataBlock = bs_shared_ptr_new<SerializedDataBlock>(); |
529 | serializedDataBlock->stream = stream; |
530 | serializedDataBlock->offset = 0; |
531 | |
532 | serializedDataBlock->size = dataBlockSize; |
533 | serializedEntry = serializedDataBlock; |
534 | |
535 | break; |
536 | } |
537 | default: |
538 | BS_EXCEPT(InternalErrorException, |
539 | "Error encoding data. Encountered a type I don't know how to encode. Type: " + toString(UINT32(curGenericField->mType)) + |
540 | ", Is array: " + toString(curGenericField->mIsVectorType)); |
541 | } |
542 | } |
543 | |
544 | SerializedEntry entry; |
545 | entry.fieldId = curGenericField->mUniqueId; |
546 | entry.serialized = serializedEntry; |
547 | |
548 | subObject.entries.insert(std::make_pair(curGenericField->mUniqueId, entry)); |
549 | } |
550 | |
551 | rtti = rtti->getBaseClass(); |
552 | |
553 | } while (rtti != nullptr); // Repeat until we reach the top of the inheritance hierarchy |
554 | |
555 | cleanup(); |
556 | |
557 | return output; |
558 | } |
559 | } |
560 | |
561 | SPtr<SerializedObject> SerializedObject::create(IReflectable& obj, bool shallow, SerializationContext* context) |
562 | { |
563 | detail::IntermediateSerializer is; |
564 | return is.encode(&obj, shallow, context); |
565 | |
566 | } |
567 | |
568 | SPtr<IReflectable> SerializedObject::decode(SerializationContext* context) const |
569 | { |
570 | detail::IntermediateSerializer is; |
571 | return is.decode(this, context); |
572 | } |
573 | |
574 | SPtr<SerializedInstance> SerializedObject::clone(bool cloneData) |
575 | { |
576 | SPtr<SerializedObject> copy = bs_shared_ptr_new<SerializedObject>(); |
577 | copy->subObjects = Vector<SerializedSubObject>(subObjects.size()); |
578 | |
579 | UINT32 i = 0; |
580 | for (auto& subObject : subObjects) |
581 | { |
582 | copy->subObjects[i].typeId = subObject.typeId; |
583 | |
584 | for (auto& entryPair : subObject.entries) |
585 | { |
586 | SerializedEntry entry = entryPair.second; |
587 | |
588 | if (entry.serialized != nullptr) |
589 | entry.serialized = entry.serialized->clone(cloneData); |
590 | |
591 | copy->subObjects[i].entries[entryPair.first] = entry; |
592 | } |
593 | |
594 | i++; |
595 | } |
596 | |
597 | return copy; |
598 | } |
599 | |
600 | SPtr<SerializedInstance> SerializedField::clone(bool cloneData) |
601 | { |
602 | SPtr<SerializedField> copy = bs_shared_ptr_new<SerializedField>(); |
603 | copy->size = size; |
604 | |
605 | if (cloneData) |
606 | { |
607 | copy->value = (UINT8*)bs_alloc(size); |
608 | memcpy(copy->value, value, size); |
609 | copy->ownsMemory = true; |
610 | } |
611 | else |
612 | { |
613 | copy->value = value; |
614 | copy->ownsMemory = false; |
615 | } |
616 | |
617 | return copy; |
618 | } |
619 | |
620 | SPtr<SerializedInstance> SerializedDataBlock::clone(bool cloneData) |
621 | { |
622 | SPtr<SerializedDataBlock> copy = bs_shared_ptr_new<SerializedDataBlock>(); |
623 | copy->size = size; |
624 | |
625 | if (cloneData) |
626 | { |
627 | if(stream->isFile()) |
628 | LOGWRN("Cloning a file stream. Streaming is disabled and stream data will be loaded into memory." ); |
629 | |
630 | UINT8* data = (UINT8*)bs_alloc(size); |
631 | stream->read(data, size); |
632 | |
633 | copy->stream = bs_shared_ptr_new<MemoryDataStream>(data, size); |
634 | copy->offset = 0; |
635 | } |
636 | else |
637 | { |
638 | copy->stream = stream; |
639 | copy->offset = offset; |
640 | } |
641 | |
642 | return copy; |
643 | } |
644 | |
645 | SPtr<SerializedInstance> SerializedArray::clone(bool cloneData) |
646 | { |
647 | SPtr<SerializedArray> copy = bs_shared_ptr_new<SerializedArray>(); |
648 | copy->numElements = numElements; |
649 | |
650 | for (auto& entryPair : entries) |
651 | { |
652 | SerializedArrayEntry entry = entryPair.second; |
653 | entry.serialized = entry.serialized->clone(cloneData); |
654 | |
655 | copy->entries[entryPair.first] = entry; |
656 | } |
657 | |
658 | return copy; |
659 | } |
660 | |
661 | RTTITypeBase* SerializedInstance::getRTTIStatic() |
662 | { |
663 | return SerializedInstanceRTTI::instance(); |
664 | } |
665 | |
666 | RTTITypeBase* SerializedInstance::getRTTI() const |
667 | { |
668 | return SerializedInstance::getRTTIStatic(); |
669 | } |
670 | |
671 | RTTITypeBase* SerializedDataBlock::getRTTIStatic() |
672 | { |
673 | return SerializedDataBlockRTTI::instance(); |
674 | } |
675 | |
676 | RTTITypeBase* SerializedDataBlock::getRTTI() const |
677 | { |
678 | return SerializedDataBlock::getRTTIStatic(); |
679 | } |
680 | |
681 | RTTITypeBase* SerializedField::getRTTIStatic() |
682 | { |
683 | return SerializedFieldRTTI::instance(); |
684 | } |
685 | |
686 | RTTITypeBase* SerializedField::getRTTI() const |
687 | { |
688 | return SerializedField::getRTTIStatic(); |
689 | } |
690 | |
691 | UINT32 SerializedObject::getRootTypeId() const |
692 | { |
693 | if(subObjects.size() > 0) |
694 | return subObjects[0].typeId; |
695 | |
696 | return 0; |
697 | } |
698 | |
699 | RTTITypeBase* SerializedObject::getRTTIStatic() |
700 | { |
701 | return SerializedObjectRTTI::instance(); |
702 | } |
703 | |
704 | RTTITypeBase* SerializedObject::getRTTI() const |
705 | { |
706 | return SerializedObject::getRTTIStatic(); |
707 | } |
708 | |
709 | RTTITypeBase* SerializedArray::getRTTIStatic() |
710 | { |
711 | return SerializedArrayRTTI::instance(); |
712 | } |
713 | |
714 | RTTITypeBase* SerializedArray::getRTTI() const |
715 | { |
716 | return SerializedArray::getRTTIStatic(); |
717 | } |
718 | |
719 | RTTITypeBase* SerializedSubObject::getRTTIStatic() |
720 | { |
721 | return SerializedSubObjectRTTI::instance(); |
722 | } |
723 | |
724 | RTTITypeBase* SerializedSubObject::getRTTI() const |
725 | { |
726 | return SerializedSubObject::getRTTIStatic(); |
727 | } |
728 | |
729 | RTTITypeBase* SerializedEntry::getRTTIStatic() |
730 | { |
731 | return SerializedEntryRTTI::instance(); |
732 | } |
733 | |
734 | RTTITypeBase* SerializedEntry::getRTTI() const |
735 | { |
736 | return SerializedEntry::getRTTIStatic(); |
737 | } |
738 | |
739 | RTTITypeBase* SerializedArrayEntry::getRTTIStatic() |
740 | { |
741 | return SerializedArrayEntryRTTI::instance(); |
742 | } |
743 | |
744 | RTTITypeBase* SerializedArrayEntry::getRTTI() const |
745 | { |
746 | return SerializedArrayEntry::getRTTIStatic(); |
747 | } |
748 | } |