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/BsBinaryDiff.h"
4#include "Serialization/BsSerializedObject.h"
5#include "Serialization/BsBinarySerializer.h"
6#include "Serialization/BsBinaryCloner.h"
7#include "Reflection/BsRTTIType.h"
8#include "FileSystem/BsDataStream.h"
9
10namespace bs
11{
12 SPtr<SerializedObject> IDiff::generateDiff(const SPtr<SerializedObject>& orgObj,
13 const SPtr<SerializedObject>& newObj)
14 {
15 ObjectMap objectMap;
16 return generateDiff(orgObj, newObj, objectMap);
17 }
18
19 SPtr<SerializedInstance> IDiff::generateDiff(RTTITypeBase* rtti, UINT32 fieldType, const SPtr<SerializedInstance>& orgData,
20 const SPtr<SerializedInstance>& newData, ObjectMap& objectMap)
21 {
22 SPtr<SerializedInstance> modification;
23 switch (fieldType)
24 {
25 case SerializableFT_ReflectablePtr:
26 case SerializableFT_Reflectable:
27 {
28 SPtr<SerializedObject> orgObjData = std::static_pointer_cast<SerializedObject>(orgData);
29 SPtr<SerializedObject> newObjData = std::static_pointer_cast<SerializedObject>(newData);
30
31 auto iterFind = objectMap.find(newObjData);
32 if (iterFind != objectMap.end())
33 modification = iterFind->second;
34 else
35 {
36 RTTITypeBase* childRtti = nullptr;
37 if (orgObjData->getRootTypeId() == newObjData->getRootTypeId())
38 childRtti = IReflectable::_getRTTIfromTypeId(newObjData->getRootTypeId());
39
40 SPtr<SerializedObject> objectDiff;
41 if (childRtti != nullptr)
42 {
43 IDiff& handler = childRtti->getDiffHandler();
44 objectDiff = handler.generateDiff(orgObjData, newObjData, objectMap);
45 }
46
47 if (objectDiff != nullptr)
48 objectMap[newObjData] = objectDiff;
49
50 modification = objectDiff;
51 }
52 }
53 break;
54 case SerializableFT_Plain:
55 {
56 SPtr<SerializedField> orgFieldData = std::static_pointer_cast<SerializedField>(orgData);
57 SPtr<SerializedField> newFieldData = std::static_pointer_cast<SerializedField>(newData);
58
59 bool isModified = orgFieldData->size != newFieldData->size;
60 if (!isModified)
61 isModified = memcmp(orgFieldData->value, newFieldData->value, newFieldData->size) != 0;
62
63 if (isModified)
64 modification = newFieldData->clone();
65 }
66 break;
67 case SerializableFT_DataBlock:
68 {
69 SPtr<SerializedDataBlock> orgFieldData = std::static_pointer_cast<SerializedDataBlock>(orgData);
70 SPtr<SerializedDataBlock> newFieldData = std::static_pointer_cast<SerializedDataBlock>(newData);
71
72 bool isModified = orgFieldData->size != newFieldData->size;
73 if (!isModified)
74 {
75 UINT8* orgStreamData = nullptr;
76 if(orgFieldData->stream->isFile())
77 {
78 orgStreamData = (UINT8*)bs_stack_alloc(orgFieldData->size);
79 orgFieldData->stream->seek(orgFieldData->offset);
80 orgFieldData->stream->read(orgStreamData, orgFieldData->size);
81 }
82 else
83 {
84 SPtr<MemoryDataStream> orgMemStream = std::static_pointer_cast<MemoryDataStream>(orgFieldData->stream);
85 orgStreamData = orgMemStream->getCurrentPtr();
86 }
87
88 UINT8* newStreamData = nullptr;
89 if (newFieldData->stream->isFile())
90 {
91 newStreamData = (UINT8*)bs_stack_alloc(newFieldData->size);
92 newFieldData->stream->seek(newFieldData->offset);
93 newFieldData->stream->read(newStreamData, newFieldData->size);
94 }
95 else
96 {
97 SPtr<MemoryDataStream> newMemStream = std::static_pointer_cast<MemoryDataStream>(newFieldData->stream);
98 newStreamData = newMemStream->getCurrentPtr();
99 }
100
101 isModified = memcmp(orgStreamData, newStreamData, newFieldData->size) != 0;
102
103 if (newFieldData->stream->isFile())
104 bs_stack_free(newStreamData);
105
106 if (orgFieldData->stream->isFile())
107 bs_stack_free(orgStreamData);
108 }
109
110 if (isModified)
111 modification = newFieldData->clone();
112 }
113 break;
114 }
115
116 return modification;
117 }
118
119 void IDiff::applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff,
120 SerializationContext* context)
121 {
122 FrameAlloc& alloc = gFrameAlloc();
123 alloc.markFrame();
124
125 FrameVector<DiffCommand> commands;
126
127 DiffObjectMap objectMap;
128 applyDiff(object, diff, alloc, objectMap, commands, context);
129
130 IReflectable* destObject = nullptr;
131 RTTITypeBase* rttiInstance = nullptr;
132
133 Stack<IReflectable*> objectStack;
134 Vector<std::pair<RTTITypeBase*, IReflectable*>> rttiInstances;
135
136 for (auto& command : commands)
137 {
138 bool isArray = (command.type & Diff_ArrayFlag) != 0;
139 DiffCommandType type = (DiffCommandType)(command.type & 0xF);
140
141 switch (type)
142 {
143 case Diff_ArraySize:
144 command.field->setArraySize(rttiInstance, destObject, command.arraySize);
145 break;
146 case Diff_ObjectStart:
147 {
148 destObject = command.object.get();
149 objectStack.push(destObject);
150
151 FrameStack<RTTITypeBase*> rttiTypes;
152 RTTITypeBase* curRtti = destObject->getRTTI();
153 while (curRtti != nullptr)
154 {
155 rttiTypes.push(curRtti);
156 curRtti = curRtti->getBaseClass();
157 }
158
159 // Call base class first, followed by derived classes
160 while(!rttiTypes.empty())
161 {
162 RTTITypeBase* curRtti = rttiTypes.top();
163 RTTITypeBase* rttiInstance = curRtti->_clone(alloc);
164
165 rttiInstances.push_back(std::make_pair(rttiInstance, destObject));
166 rttiInstance->onDeserializationStarted(destObject, context);
167
168 rttiTypes.pop();
169 }
170 }
171 break;
172 case Diff_SubObjectStart:
173 {
174 // Find the instance
175 rttiInstance = nullptr;
176 for(auto iter = rttiInstances.rbegin(); iter != rttiInstances.rend(); ++iter)
177 {
178 if(iter->second != destObject)
179 break;
180
181 if(iter->first->getRTTIId() == command.rttiType->getRTTIId())
182 rttiInstance = iter->first;
183 }
184
185 assert(rttiInstance);
186 }
187 break;
188 case Diff_ObjectEnd:
189 {
190 while (!rttiInstances.empty())
191 {
192 if(rttiInstances.back().second != destObject)
193 break;
194
195 RTTITypeBase* rttiInstance = rttiInstances.back().first;
196
197 rttiInstance->onDeserializationEnded(destObject, context);
198 alloc.destruct(rttiInstance);
199
200 rttiInstances.erase(rttiInstances.end() - 1);
201 }
202
203 objectStack.pop();
204
205 if (!objectStack.empty())
206 destObject = objectStack.top();
207 else
208 destObject = nullptr;
209 }
210 break;
211 default:
212 break;
213 }
214
215 if (isArray)
216 {
217 switch (type)
218 {
219 case Diff_ReflectablePtr:
220 {
221 RTTIReflectablePtrFieldBase* field = static_cast<RTTIReflectablePtrFieldBase*>(command.field);
222 field->setArrayValue(rttiInstance, destObject, command.arrayIdx, command.object);
223 }
224 break;
225 case Diff_Reflectable:
226 {
227 RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(command.field);
228 field->setArrayValue(rttiInstance, destObject, command.arrayIdx, *command.object);
229 }
230 break;
231 case Diff_Plain:
232 {
233 RTTIPlainFieldBase* field = static_cast<RTTIPlainFieldBase*>(command.field);
234 field->arrayElemFromBuffer(rttiInstance, destObject, command.arrayIdx, command.value);
235 }
236 break;
237 default:
238 break;
239 }
240 }
241 else
242 {
243 switch (type)
244 {
245 case Diff_ReflectablePtr:
246 {
247 RTTIReflectablePtrFieldBase* field = static_cast<RTTIReflectablePtrFieldBase*>(command.field);
248 field->setValue(rttiInstance, destObject, command.object);
249 }
250 break;
251 case Diff_Reflectable:
252 {
253 RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(command.field);
254 field->setValue(rttiInstance, destObject, *command.object);
255 }
256 break;
257 case Diff_Plain:
258 {
259 RTTIPlainFieldBase* field = static_cast<RTTIPlainFieldBase*>(command.field);
260 field->fromBuffer(rttiInstance, destObject, command.value);
261 }
262 break;
263 case Diff_DataBlock:
264 {
265 RTTIManagedDataBlockFieldBase* field = static_cast<RTTIManagedDataBlockFieldBase*>(command.field);
266 field->setValue(rttiInstance, destObject, command.streamValue, command.size);
267 }
268 break;
269 default:
270 break;
271 }
272 }
273 }
274
275 alloc.clear();
276 }
277
278 void IDiff::applyDiff(RTTITypeBase* rtti, const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff,
279 FrameAlloc& alloc, DiffObjectMap& objectMap, FrameVector<DiffCommand>& diffCommands, SerializationContext* context)
280 {
281 IDiff& diffHandler = rtti->getDiffHandler();
282 diffHandler.applyDiff(object, diff, alloc, objectMap, diffCommands, context);
283 }
284
285 bool BinaryDiff::generateDiff(const RTTIField* field, RTTITypeBase* rtti, const SPtr<SerializedInstance>& oldData,
286 const SPtr<SerializedInstance>& newData, ObjectMap& objectMap,
287 SPtr<SerializedInstance>& modification)
288 {
289 if (newData != nullptr && oldData != nullptr)
290 {
291 modification = IDiff::generateDiff(rtti, field->mType, oldData, newData, objectMap);
292 return modification != nullptr;
293 }
294 else if (newData == nullptr)
295 {
296 switch (field->mType)
297 {
298 case SerializableFT_Plain:
299 modification = bs_shared_ptr_new<SerializedField>();
300 break;
301 case SerializableFT_DataBlock:
302 modification = bs_shared_ptr_new<SerializedDataBlock>();
303 break;
304 default:
305 break;
306 }
307
308 return true;
309 }
310 else if (oldData == nullptr)
311 {
312 modification = newData->clone();
313 return modification != nullptr;
314 }
315
316 return false;
317 }
318
319 SPtr<SerializedObject> BinaryDiff::generateDiff(const SPtr<SerializedObject>& orgObj,
320 const SPtr<SerializedObject>& newObj, ObjectMap& objectMap)
321 {
322 SPtr<SerializedObject> output;
323 for (auto& subObject : newObj->subObjects)
324 {
325 RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(subObject.typeId);
326 if (rtti == nullptr)
327 continue;
328
329 SerializedSubObject* orgSubObject = nullptr;
330 for (auto& curSubObject : orgObj->subObjects)
331 {
332 if (curSubObject.typeId == subObject.typeId)
333 {
334 orgSubObject = &curSubObject;
335 break;
336 }
337 }
338
339 SerializedSubObject* diffSubObject = nullptr;
340 for (auto& newEntry : subObject.entries)
341 {
342 RTTIField* genericField = rtti->findField(newEntry.first);
343 if (genericField == nullptr)
344 continue;
345
346 SPtr<SerializedInstance> newEntryData = newEntry.second.serialized;
347 SPtr<SerializedInstance> orgEntryData;
348
349 if (orgSubObject != nullptr)
350 {
351 auto orgEntryFind = orgSubObject->entries.find(newEntry.first);
352 if (orgEntryFind != orgSubObject->entries.end())
353 orgEntryData = orgEntryFind->second.serialized;
354 }
355
356 SPtr<SerializedInstance> modification;
357 bool hasModification = false;
358 if (genericField->isArray())
359 {
360 SPtr<SerializedArray> orgArrayData = std::static_pointer_cast<SerializedArray>(orgEntryData);
361 SPtr<SerializedArray> newArrayData = std::static_pointer_cast<SerializedArray>(newEntryData);
362
363 SPtr<SerializedArray> serializedArray;
364
365 if (newEntryData != nullptr && orgEntryData != nullptr)
366 {
367 // Check for new or different fields
368 for (auto& arrayEntryPair : newArrayData->entries)
369 {
370 SPtr<SerializedInstance> orgArrayEntryData;
371
372 auto iterFind = orgArrayData->entries.find(arrayEntryPair.first);
373 if (iterFind != orgArrayData->entries.end())
374 orgArrayEntryData = iterFind->second.serialized;
375
376 SPtr<SerializedInstance> arrayModification;
377 bool hasArrayModification = generateDiff(genericField, rtti, orgArrayEntryData,
378 arrayEntryPair.second.serialized, objectMap, arrayModification);
379
380 if (hasArrayModification)
381 {
382 if (serializedArray == nullptr)
383 {
384 serializedArray = bs_shared_ptr_new<SerializedArray>();
385 serializedArray->numElements = newArrayData->numElements;
386 }
387
388 SerializedArrayEntry arrayEntry;
389 arrayEntry.index = arrayEntryPair.first;
390 arrayEntry.serialized = arrayModification;
391 serializedArray->entries[arrayEntryPair.first] = arrayEntry;
392 }
393 }
394
395 if(newArrayData->numElements != orgArrayData->numElements)
396 {
397 if (serializedArray == nullptr)
398 {
399 serializedArray = bs_shared_ptr_new<SerializedArray>();
400 serializedArray->numElements = newArrayData->numElements;
401 }
402 }
403 }
404 else if (newEntryData == nullptr)
405 {
406 serializedArray = bs_shared_ptr_new<SerializedArray>();
407 }
408 else if (orgEntryData == nullptr)
409 {
410 serializedArray = std::static_pointer_cast<SerializedArray>(newArrayData->clone());
411 }
412
413 modification = serializedArray;
414 hasModification = modification != nullptr;
415 }
416 else
417 hasModification = generateDiff(genericField, rtti, orgEntryData, newEntryData, objectMap, modification);
418
419 if (hasModification)
420 {
421 if (output == nullptr)
422 output = bs_shared_ptr_new<SerializedObject>();
423
424 if (diffSubObject == nullptr)
425 {
426 output->subObjects.push_back(SerializedSubObject());
427 diffSubObject = &output->subObjects.back();
428 diffSubObject->typeId = rtti->getRTTIId();
429 }
430
431 SerializedEntry modificationEntry;
432 modificationEntry.fieldId = genericField->mUniqueId;
433 modificationEntry.serialized = modification;
434 diffSubObject->entries[genericField->mUniqueId] = modificationEntry;
435 }
436 }
437 }
438
439 return output;
440 }
441
442 void BinaryDiff::applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff,
443 FrameAlloc& alloc, DiffObjectMap& objectMap, FrameVector<DiffCommand>& diffCommands, SerializationContext* context)
444 {
445 if (object == nullptr || diff == nullptr || object->getTypeId() != diff->getRootTypeId())
446 return;
447
448 // Generate a list of commands per sub-object
449 FrameVector<FrameVector<DiffCommand>> commandsPerSubObj;
450
451 Stack<RTTITypeBase*> rttiInstances;
452 for (auto& subObject : diff->subObjects)
453 {
454 RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(subObject.typeId);
455 if (rtti == nullptr)
456 continue;
457
458 if (!object->isDerivedFrom(rtti))
459 continue;
460
461 RTTITypeBase* rttiInstance = rtti->_clone(alloc);
462 rttiInstance->onSerializationStarted(object.get(), nullptr);
463 rttiInstances.push(rttiInstance);
464
465 FrameVector<DiffCommand> commands;
466
467 DiffCommand subObjStartCommand;
468 subObjStartCommand.rttiType = rtti;
469 subObjStartCommand.field = nullptr;
470 subObjStartCommand.type = Diff_SubObjectStart;
471
472 commands.push_back(subObjStartCommand);
473
474 for (auto& diffEntry : subObject.entries)
475 {
476 RTTIField* genericField = rtti->findField(diffEntry.first);
477 if (genericField == nullptr)
478 continue;
479
480 SPtr<SerializedInstance> diffData = diffEntry.second.serialized;
481
482 if (genericField->isArray())
483 {
484 SPtr<SerializedArray> diffArray = std::static_pointer_cast<SerializedArray>(diffData);
485
486 UINT32 numArrayElements = (UINT32)diffArray->numElements;
487
488 DiffCommand arraySizeCommand;
489 arraySizeCommand.field = genericField;
490 arraySizeCommand.type = Diff_ArraySize | Diff_ArrayFlag;
491 arraySizeCommand.arraySize = numArrayElements;
492
493 commands.push_back(arraySizeCommand);
494
495 switch (genericField->mType)
496 {
497 case SerializableFT_ReflectablePtr:
498 {
499 RTTIReflectablePtrFieldBase* field = static_cast<RTTIReflectablePtrFieldBase*>(genericField);
500
501 UINT32 orgArraySize = genericField->getArraySize(rttiInstance, object.get());
502 for (auto& arrayElem : diffArray->entries)
503 {
504 SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
505
506 DiffCommand command;
507 command.field = genericField;
508 command.type = Diff_ReflectablePtr | Diff_ArrayFlag;
509 command.arrayIdx = arrayElem.first;
510
511 if (arrayElemData == nullptr)
512 {
513 command.object = nullptr;
514 commands.push_back(command);
515 }
516 else
517 {
518 bool needsNewObject = arrayElem.first >= orgArraySize;
519
520 if (!needsNewObject)
521 {
522 SPtr<IReflectable> childObj = field->getArrayValue(rttiInstance, object.get(), arrayElem.first);
523 if (childObj != nullptr)
524 {
525 IDiff::applyDiff(childObj->getRTTI(), childObj, arrayElemData, alloc, objectMap,
526 commands, context);
527 command.object = childObj;
528 }
529 else
530 needsNewObject = true;
531 }
532
533 if (needsNewObject)
534 {
535 RTTITypeBase* childRtti = IReflectable::_getRTTIfromTypeId(arrayElemData->getRootTypeId());
536 if (childRtti != nullptr)
537 {
538 auto findObj = objectMap.find(arrayElemData);
539 if (findObj == objectMap.end())
540 {
541 SPtr<IReflectable> newObject = childRtti->newRTTIObject();
542 findObj = objectMap.insert(std::make_pair(arrayElemData, newObject)).first;
543 }
544
545 IDiff::applyDiff(childRtti, findObj->second, arrayElemData, alloc, objectMap,
546 commands, context);
547 command.object = findObj->second;
548 commands.push_back(command);
549 }
550 else
551 {
552 command.object = nullptr;
553 commands.push_back(command);
554 }
555 }
556 }
557 }
558 }
559 break;
560 case SerializableFT_Reflectable:
561 {
562 RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(genericField);
563
564 UINT32 orgArraySize = genericField->getArraySize(rttiInstance, object.get());
565
566 Vector<SPtr<IReflectable>> newArrayElements(numArrayElements);
567 UINT32 minArrayLength = std::min(orgArraySize, numArrayElements);
568 for (UINT32 i = 0; i < minArrayLength; i++)
569 {
570 IReflectable& childObj = field->getArrayValue(rttiInstance, object.get(), i);
571 newArrayElements[i] = BinaryCloner::clone(&childObj, true);
572 }
573
574 for (auto& arrayElem : diffArray->entries)
575 {
576 SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
577
578 if (arrayElem.first < orgArraySize)
579 {
580 SPtr<IReflectable> childObj = newArrayElements[arrayElem.first];
581 IDiff::applyDiff(childObj->getRTTI(), childObj, arrayElemData, alloc, objectMap,
582 commands, context);
583 }
584 else
585 {
586 RTTITypeBase* childRtti = IReflectable::_getRTTIfromTypeId(arrayElemData->getRootTypeId());
587 if (childRtti != nullptr)
588 {
589 SPtr<IReflectable> newObject = childRtti->newRTTIObject();
590 IDiff::applyDiff(childRtti, newObject, arrayElemData, alloc, objectMap, commands,
591 context);
592
593 newArrayElements[arrayElem.first] = newObject;
594 }
595 }
596 }
597
598 for (UINT32 i = 0; i < numArrayElements; i++)
599 {
600 DiffCommand command;
601 command.field = genericField;
602 command.type = Diff_Reflectable | Diff_ArrayFlag;
603 command.arrayIdx = i;
604 command.object = newArrayElements[i];
605
606 commands.push_back(command);
607 }
608 }
609 break;
610 case SerializableFT_Plain:
611 {
612 for (auto& arrayElem : diffArray->entries)
613 {
614 SPtr<SerializedField> fieldData = std::static_pointer_cast<SerializedField>(arrayElem.second.serialized);
615 if (fieldData != nullptr)
616 {
617 DiffCommand command;
618 command.field = genericField;
619 command.type = Diff_Plain | Diff_ArrayFlag;
620 command.value = fieldData->value;
621 command.size = fieldData->size;
622 command.arrayIdx = arrayElem.first;
623
624 commands.push_back(command);
625 }
626 }
627 }
628 break;
629 default:
630 break;
631 }
632 }
633 else
634 {
635 switch (genericField->mType)
636 {
637 case SerializableFT_ReflectablePtr:
638 {
639 RTTIReflectablePtrFieldBase* field = static_cast<RTTIReflectablePtrFieldBase*>(genericField);
640 SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(diffData);
641
642 DiffCommand command;
643 command.field = genericField;
644 command.type = Diff_ReflectablePtr;
645
646 if (fieldObjectData == nullptr)
647 command.object = nullptr;
648 else
649 {
650 SPtr<IReflectable> childObj = field->getValue(rttiInstance, object.get());
651 if (childObj == nullptr)
652 {
653 RTTITypeBase* childRtti = IReflectable::_getRTTIfromTypeId(fieldObjectData->getRootTypeId());
654 if (childRtti != nullptr)
655 {
656 auto findObj = objectMap.find(fieldObjectData);
657 if (findObj == objectMap.end())
658 {
659 SPtr<IReflectable> newObject = childRtti->newRTTIObject();
660 findObj = objectMap.insert(std::make_pair(fieldObjectData, newObject)).first;
661 }
662
663 IDiff::applyDiff(childRtti, findObj->second, fieldObjectData, alloc, objectMap,
664 commands, context);
665 command.object = findObj->second;
666 }
667 else
668 {
669 command.object = nullptr;
670 }
671 }
672 else
673 {
674 IDiff::applyDiff(childObj->getRTTI(), childObj, fieldObjectData, alloc, objectMap,
675 commands, context);
676 command.object = childObj;
677 }
678 }
679
680 commands.push_back(command);
681 }
682 break;
683 case SerializableFT_Reflectable:
684 {
685 RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(genericField);
686 SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(diffData);
687
688 IReflectable& childObj = field->getValue(rttiInstance, object.get());
689 SPtr<IReflectable> clonedObj = BinaryCloner::clone(&childObj, true);
690
691 IDiff::applyDiff(clonedObj->getRTTI(), clonedObj, fieldObjectData, alloc, objectMap, commands,
692 context);
693
694 DiffCommand command;
695 command.field = genericField;
696 command.type = Diff_Reflectable;
697 command.object = clonedObj;
698
699 commands.push_back(command);
700 }
701 break;
702 case SerializableFT_Plain:
703 {
704 SPtr<SerializedField> diffFieldData = std::static_pointer_cast<SerializedField>(diffData);
705
706 if (diffFieldData->size > 0)
707 {
708 DiffCommand command;
709 command.field = genericField;
710 command.type = Diff_Plain;
711 command.value = diffFieldData->value;
712 command.size = diffFieldData->size;
713
714 commands.push_back(command);
715 }
716 }
717 break;
718 case SerializableFT_DataBlock:
719 {
720 SPtr<SerializedDataBlock> diffFieldData = std::static_pointer_cast<SerializedDataBlock>(diffData);
721
722 DiffCommand command;
723 command.field = genericField;
724 command.type = Diff_DataBlock;
725 command.streamValue = diffFieldData->stream;
726 command.value = nullptr;
727 command.size = diffFieldData->size;
728
729 commands.push_back(command);
730 }
731 break;
732 }
733 }
734 }
735
736 commandsPerSubObj.emplace_back(std::move(commands));
737 }
738
739 DiffCommand objStartCommand;
740 objStartCommand.field = nullptr;
741 objStartCommand.type = Diff_ObjectStart;
742 objStartCommand.object = object;
743
744 diffCommands.push_back(objStartCommand);
745
746 // Go in reverse because when deserializing we want to deserialize base first, and then derived types
747 for(auto iter = commandsPerSubObj.rbegin(); iter != commandsPerSubObj.rend(); ++iter)
748 diffCommands.insert(diffCommands.end(), iter->begin(), iter->end());
749
750 DiffCommand objEndCommand;
751 objEndCommand.field = nullptr;
752 objEndCommand.type = Diff_ObjectEnd;
753 objEndCommand.object = object;
754
755 diffCommands.push_back(objEndCommand);
756
757 while (!rttiInstances.empty())
758 {
759 RTTITypeBase* rttiInstance = rttiInstances.top();
760 rttiInstance->onSerializationEnded(object.get(), nullptr);
761 alloc.destruct(rttiInstance);
762
763 rttiInstances.pop();
764 }
765 }
766}