/[svn]/libgig/trunk/src/Serialization.h
ViewVC logotype

Contents of /libgig/trunk/src/Serialization.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3156 - (show annotations) (download) (as text)
Mon May 8 17:18:07 2017 UTC (6 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 28470 byte(s)
* class Archive: Added methods name() and setName().
* class Archive: Added methods comment() and setComment().
* class Archive: Added methods timeStampCreated(),
  timeStampModified(), dateTimeCreated() and
  dateTimeModified().
* Bumped version (4.0.0.svn18).

1 /***************************************************************************
2 * *
3 * Copyright (C) 2017 Christian Schoenebeck *
4 * <cuse@users.sourceforge.net> *
5 * *
6 * This library is part of libgig. *
7 * *
8 * This library is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #ifndef LIBGIG_SERIALIZATION_H
25 #define LIBGIG_SERIALIZATION_H
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <typeinfo>
34 #include <string>
35 #include <vector>
36 #include <map>
37 #include <time.h>
38
39 /** @brief Serialization / deserialization framework.
40 *
41 * See class Archive as starting point for how to implement serialization and
42 * deserialization with your application.
43 *
44 * The classes in this namespace allow to serialize and deserialize native
45 * C++ objects in a portable, easy and flexible way. Serialization is a
46 * technique that allows to transform the current state and data of native
47 * (in this case C++) objects into a data stream (including all other objects
48 * the "serialized" objects relate to); the data stream may then be sent over
49 * "wire" (for example via network connection to another computer, which might
50 * also have a different OS, CPU architecture, native memory word size and
51 * endian type); and finally the data stream would be "deserialized" on that
52 * receiver side, that is transformed again to modify all objects and data
53 * structures on receiver side to resemble the objects' state and data as it
54 * was originally on sender side.
55 *
56 * In contrast to many other already existing serialization frameworks, this
57 * implementation has a strong focus on robustness regarding long-term changes
58 * to the serialized C++ classes of the serialized objects. So even if sender
59 * and receiver are using different versions of their serialized/deserialized
60 * C++ classes, structures and data types (thus having different data structure
61 * layout to a certain extent), this framework aims trying to automatically
62 * adapt its serialization and deserialization process in that case so that
63 * the deserialized objects on receiver side would still reflect the overall
64 * expected states and overall data as intended by the sender. For being able to
65 * do so, this framework stores all kind of additional information about each
66 * serialized object and each data structure member (for example name of each
67 * data structure member, but also the offset of each member within its
68 * containing data structure, precise data types, and more).
69 *
70 * Like most other serialization frameworks, this frameworks does not require a
71 * tree-structured layout of the serialized data structures. So it automatically
72 * handles also cyclic dependencies between serialized data structures
73 * correctly, without i.e. causing endless recursion or redundancy.
74 *
75 * Additionally this framework also allows partial deserialization. Which means
76 * the receiver side may for example decide that it wants to restrict
77 * deserialization so that it would only modify certain objects or certain
78 * members by the deserialization process, leaving all other ones untouched.
79 * So this partial deserialization technique for example allows to implement
80 * flexible preset features for applications in a powerful and easy way.
81 */
82 namespace Serialization {
83
84 // just symbol prototyping
85 class DataType;
86 class Object;
87 class Member;
88 class Archive;
89 class ObjectPool;
90 class Exception;
91
92 typedef std::string String;
93
94 typedef std::vector<uint8_t> RawData;
95
96 typedef void* ID;
97
98 typedef uint32_t Version;
99
100 enum operation_t {
101 OPERATION_NONE,
102 OPERATION_SERIALIZE,
103 OPERATION_DESERIALIZE
104 };
105
106 enum time_base_t {
107 LOCAL_TIME,
108 UTC_TIME
109 };
110
111 template<typename T>
112 bool IsEnum(const T& data) {
113 return __is_enum(T);
114 }
115
116 template<typename T>
117 bool IsUnion(const T& data) {
118 return __is_union(T);
119 }
120
121 template<typename T>
122 bool IsClass(const T& data) {
123 return __is_class(T);
124 }
125
126 /*template<typename T>
127 bool IsTrivial(T data) {
128 return __is_trivial(T);
129 }*/
130
131 /*template<typename T>
132 bool IsPOD(T data) {
133 return __is_pod(T);
134 }*/
135
136 /** @brief Unique identifier for one specific C++ object, member or fundamental variable.
137 *
138 * Reflects a unique identifier for one specific serialized C++ class
139 * instance, struct instance, member, primitive pointer, or fundamental
140 * variables.
141 */
142 class UID {
143 public:
144 ID id;
145 size_t size;
146
147 bool isValid() const;
148 operator bool() const { return isValid(); }
149 //bool operator()() const { return isValid(); }
150 bool operator==(const UID& other) const { return id == other.id && size == other.size; }
151 bool operator!=(const UID& other) const { return id != other.id || size != other.size; }
152 bool operator<(const UID& other) const { return id < other.id || (id == other.id && size < other.size); }
153 bool operator>(const UID& other) const { return id > other.id || (id == other.id && size > other.size); }
154
155 template<typename T>
156 static UID from(const T& obj) {
157 return Resolver<T>::resolve(obj);
158 }
159
160 protected:
161 // UID resolver for non-pointer types
162 template<typename T>
163 struct Resolver {
164 static UID resolve(const T& obj) {
165 return (UID) { (ID) &obj, sizeof(obj) };
166 }
167 };
168
169 // UID resolver for pointer types (of 1st degree)
170 template<typename T>
171 struct Resolver<T*> {
172 static UID resolve(const T* const & obj) {
173 return (UID) { (ID) obj, sizeof(*obj) };
174 }
175 };
176 };
177
178 /**
179 * Reflects an invalid UID and behaves similar to NULL as invalid value for
180 * pointer types.
181 */
182 extern const UID NO_UID;
183
184 typedef std::vector<UID> UIDChain;
185
186 // prototyping of private internal friend functions
187 static String _encodePrimitiveValue(const Object& obj);
188 static DataType _popDataTypeBlob(const char*& p, const char* end);
189 static Member _popMemberBlob(const char*& p, const char* end);
190 static Object _popObjectBlob(const char*& p, const char* end);
191 static void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
192 static String _primitiveObjectValueToString(const Object& obj);
193
194 /** @brief Abstract reflection of a native C++ data type.
195 *
196 * Provides detailed information about a C++ data type, whether it is a
197 * fundamental C/C++ data type (like int, float, char, etc.) or custom
198 * defined data type like a C++ class, struct, enum, as well as other
199 * features of the data type like its native memory size and more.
200 */
201 class DataType {
202 public:
203 DataType();
204 size_t size() const { return m_size; }
205 bool isValid() const;
206 bool isPointer() const;
207 bool isClass() const;
208 bool isPrimitive() const;
209 bool isInteger() const;
210 bool isReal() const;
211 bool isBool() const;
212 bool isEnum() const;
213 bool isSigned() const;
214 operator bool() const { return isValid(); }
215 //bool operator()() const { return isValid(); }
216 bool operator==(const DataType& other) const;
217 bool operator!=(const DataType& other) const;
218 bool operator<(const DataType& other) const;
219 bool operator>(const DataType& other) const;
220 String asLongDescr() const;
221 String baseTypeName() const { return m_baseTypeName; }
222 String customTypeName() const { return m_customTypeName; }
223
224 template<typename T>
225 static DataType dataTypeOf(const T& data) {
226 return Resolver<T>::resolve(data);
227 }
228
229 protected:
230 DataType(bool isPointer, int size, String baseType, String customType = "");
231
232 template<typename T, bool T_isPointer>
233 struct ResolverBase {
234 static DataType resolve(const T& data) {
235 const std::type_info& type = typeid(data);
236 const int sz = sizeof(data);
237
238 // for primitive types we are using our own type names instead of
239 // using std:::type_info::name(), because the precise output of the
240 // latter may vary between compilers
241 if (type == typeid(int8_t)) return DataType(T_isPointer, sz, "int8");
242 if (type == typeid(uint8_t)) return DataType(T_isPointer, sz, "uint8");
243 if (type == typeid(int16_t)) return DataType(T_isPointer, sz, "int16");
244 if (type == typeid(uint16_t)) return DataType(T_isPointer, sz, "uint16");
245 if (type == typeid(int32_t)) return DataType(T_isPointer, sz, "int32");
246 if (type == typeid(uint32_t)) return DataType(T_isPointer, sz, "uint32");
247 if (type == typeid(int64_t)) return DataType(T_isPointer, sz, "int64");
248 if (type == typeid(uint64_t)) return DataType(T_isPointer, sz, "uint64");
249 if (type == typeid(bool)) return DataType(T_isPointer, sz, "bool");
250 if (type == typeid(float)) return DataType(T_isPointer, sz, "real32");
251 if (type == typeid(double)) return DataType(T_isPointer, sz, "real64");
252
253 if (IsEnum(data)) return DataType(T_isPointer, sz, "enum", rawCppTypeNameOf(data));
254 if (IsUnion(data)) return DataType(T_isPointer, sz, "union", rawCppTypeNameOf(data));
255 if (IsClass(data)) return DataType(T_isPointer, sz, "class", rawCppTypeNameOf(data));
256
257 return DataType();
258 }
259 };
260
261 // DataType resolver for non-pointer types
262 template<typename T>
263 struct Resolver : ResolverBase<T,false> {
264 static DataType resolve(const T& data) {
265 return ResolverBase<T,false>::resolve(data);
266 }
267 };
268
269 // DataType resolver for pointer types (of 1st degree)
270 template<typename T>
271 struct Resolver<T*> : ResolverBase<T,true> {
272 static DataType resolve(const T*& data) {
273 return ResolverBase<T,true>::resolve(*data);
274 }
275 };
276
277 template<typename T>
278 static String rawCppTypeNameOf(const T& data) {
279 #if defined _MSC_VER // Microsoft compiler ...
280 # warning type_info::raw_name() demangling has not been tested yet with Microsoft compiler! Feedback appreciated!
281 String name = typeid(data).raw_name(); //NOTE: I haven't checked yet what MSC actually outputs here exactly
282 #else // i.e. especially GCC and clang ...
283 String name = typeid(data).name();
284 #endif
285 //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
286 // name = name.substr(1);
287 return name;
288 }
289
290 private:
291 String m_baseTypeName;
292 String m_customTypeName;
293 int m_size;
294 bool m_isPointer;
295
296 friend DataType _popDataTypeBlob(const char*& p, const char* end);
297 friend class Archive;
298 };
299
300 /** @brief Abstract reflection of a native C++ class/struct's member variable.
301 *
302 * Provides detailed information about a specific C++ member variable of
303 * serialized C++ object, like its C++ data type, offset of this member
304 * within its containing data structure/class, its C++ member variable name
305 * and more.
306 */
307 class Member {
308 public:
309 Member();
310 UID uid() const { return m_uid; }
311 String name() const { return m_name; }
312 size_t offset() const { return m_offset; }
313 const DataType& type() const { return m_type; }
314 bool isValid() const;
315 operator bool() const { return isValid(); }
316 //bool operator()() const { return isValid(); }
317 bool operator==(const Member& other) const;
318 bool operator!=(const Member& other) const;
319 bool operator<(const Member& other) const;
320 bool operator>(const Member& other) const;
321
322 protected:
323 Member(String name, UID uid, size_t offset, DataType type);
324 friend class Archive;
325
326 private:
327 UID m_uid;
328 size_t m_offset;
329 String m_name;
330 DataType m_type;
331
332 friend Member _popMemberBlob(const char*& p, const char* end);
333 };
334
335 /** @brief Abstract reflection of a native C++ class/struct instance.
336 *
337 * Provides detailed information about a specific serialized C++ object,
338 * like its C++ member variables, its C++ class/struct name, its native
339 * memory size and more.
340 */
341 class Object {
342 public:
343 Object();
344 Object(UIDChain uidChain, DataType type);
345
346 UID uid(int index = 0) const {
347 return (index < m_uid.size()) ? m_uid[index] : NO_UID;
348 }
349
350 const UIDChain& uidChain() const { return m_uid; }
351 const DataType& type() const { return m_type; }
352 const RawData& rawData() const { return m_data; }
353
354 Version version() const { return m_version; }
355
356 void setVersion(Version v) {
357 m_version = v;
358 }
359
360 Version minVersion() const { return m_minVersion; }
361
362 void setMinVersion(Version v) {
363 m_minVersion = v;
364 }
365
366 bool isVersionCompatibleTo(const Object& other) const;
367
368 std::vector<Member>& members() { return m_members; }
369 const std::vector<Member>& members() const { return m_members; }
370 Member memberNamed(String name) const;
371 Member memberByUID(const UID& uid) const;
372 std::vector<Member> membersOfType(const DataType& type) const;
373 int sequenceIndexOf(const Member& member) const;
374 bool isValid() const;
375 operator bool() const { return isValid(); }
376 //bool operator()() const { return isValid(); }
377 bool operator==(const Object& other) const;
378 bool operator!=(const Object& other) const;
379 bool operator<(const Object& other) const;
380 bool operator>(const Object& other) const;
381
382 protected:
383 void remove(const Member& member);
384
385 private:
386 DataType m_type;
387 UIDChain m_uid;
388 Version m_version;
389 Version m_minVersion;
390 RawData m_data;
391 std::vector<Member> m_members;
392
393 friend String _encodePrimitiveValue(const Object& obj);
394 friend Object _popObjectBlob(const char*& p, const char* end);
395 friend void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
396 friend String _primitiveObjectValueToString(const Object& obj);
397 friend class Archive;
398 };
399
400 /** @brief Destination container for serialization, and source container for deserialization.
401 *
402 * This is the main class for implementing serialization and deserialization
403 * with your C++ application. This framework does not require a a tree
404 * structured layout of your C++ objects being serialized/deserialized, it
405 * uses a concept of a "root" object though. So to start serialization
406 * construct an empty Archive object and then instruct it to serialize your
407 * C++ objects by pointing it to your "root" object:
408 * @code
409 * Archive a;
410 * a.serialize(&myRootObject);
411 * @endcode
412 * Or if you prefer the look of operator based code:
413 * @code
414 * Archive a;
415 * a << myRootObject;
416 * @endcode
417 * The Archive object will then serialize all members of the passed C++
418 * object, and will recursively serialize all other C++ objects which it
419 * contains or points to. So the root object is the starting point for the
420 * overall serialization. After the serialize() method returned, you can
421 * then access the serialized data stream by calling rawData() and send that
422 * data stream over "wire", or store it on disk or whatever you may intend
423 * to do with it.
424 *
425 * Then on receiver side likewise, you create a new Archive object, pass the
426 * received data stream i.e. via constructor to the Archive object and call
427 * deserialize() by pointing it to the root object on receiver side:
428 * @code
429 * Archive a(rawDataStream);
430 * a.deserialize(&myRootObject);
431 * @endcode
432 * Or with operator instead:
433 * @code
434 * Archive a(rawDataStream);
435 * a >> myRootObject;
436 * @endcode
437 * Now this framework automatically handles serialization and
438 * deserialization of fundamental data types automatically for you (like
439 * i.e. char, int, long int, float, double, etc.). However for your own
440 * custom C++ classes and structs you must implement one method which
441 * defines which members of your class should actually be serialized and
442 * deserialized. That method to be added must have the following signature:
443 * @code
444 * void serialize(Serialization::Archive* archive);
445 * @endcode
446 * So let's say you have the following simple data structures:
447 * @code
448 * struct Foo {
449 * int a;
450 * bool b;
451 * double c;
452 * };
453 *
454 * struct Bar {
455 * char one;
456 * float two;
457 * Foo foo1;
458 * Foo* pFoo2;
459 * Foo* pFoo3DontTouchMe; // shall not be serialized/deserialized
460 * };
461 * @endcode
462 * So in order to be able to serialize and deserialize objects of those two
463 * structures you would first add the mentioned method to each struct
464 * definition (i.e. in your header file):
465 * @code
466 * struct Foo {
467 * int a;
468 * bool b;
469 * double c;
470 *
471 * void serialize(Serialization::Archive* archive);
472 * };
473 *
474 * struct Bar {
475 * char one;
476 * float two;
477 * Foo foo1;
478 * Foo* pFoo2;
479 * Foo* pFoo3DontTouchMe; // shall not be serialized/deserialized
480 *
481 * void serialize(Serialization::Archive* archive);
482 * };
483 * @endcode
484 * And then you would implement those two new methods like this (i.e. in
485 * your .cpp file):
486 * @code
487 * #define SRLZ(member) \
488 * archive->serializeMember(*this, member, #member);
489 *
490 * void Foo::serialize(Serialization::Archive* archive) {
491 * SRLZ(a);
492 * SRLZ(b);
493 * SRLZ(c);
494 * }
495 *
496 * void Bar::serialize(Serialization::Archive* archive) {
497 * SRLZ(one);
498 * SRLZ(two);
499 * SRLZ(foo1);
500 * SRLZ(pFoo2);
501 * // leaving out pFoo3DontTouchMe here
502 * }
503 * @endcode
504 * Now when you serialize such a Bar object, this framework will also
505 * automatically serialize the respective Foo object(s) accordingly, also
506 * for the pFoo2 pointer for instance (as long as it is not a NULL pointer
507 * that is).
508 *
509 * Note that there is only one method that you need to implement. So the
510 * respective serialize() method implementation of your classes/structs are
511 * both called for serialization, as well as for deserialization!
512 */
513 class Archive {
514 public:
515 Archive();
516 Archive(const RawData& data);
517 Archive(const uint8_t* data, size_t size);
518 virtual ~Archive();
519
520 template<typename T>
521 void serialize(const T* obj) {
522 m_operation = OPERATION_SERIALIZE;
523 m_allObjects.clear();
524 m_rawData.clear();
525 m_root = UID::from(obj);
526 const_cast<T*>(obj)->serialize(this);
527 encode();
528 m_operation = OPERATION_NONE;
529 }
530
531 template<typename T>
532 void deserialize(T* obj) {
533 Archive a;
534 m_operation = OPERATION_DESERIALIZE;
535 obj->serialize(&a);
536 a.m_root = UID::from(obj);
537 Syncer s(a, *this);
538 m_operation = OPERATION_NONE;
539 }
540
541 template<typename T>
542 void operator<<(const T& obj) {
543 serialize(&obj);
544 }
545
546 template<typename T>
547 void operator>>(T& obj) {
548 deserialize(&obj);
549 }
550
551 const RawData& rawData();
552 virtual String rawDataFormat() const;
553
554 template<typename T_classType, typename T_memberType>
555 void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) {
556 const size_t offset =
557 ((const uint8_t*)(const void*)&nativeMember) -
558 ((const uint8_t*)(const void*)&nativeObject);
559 const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember);
560 const DataType type = DataType::dataTypeOf(nativeMember);
561 const Member member(memberName, uids[0], offset, type);
562 const UID parentUID = UID::from(nativeObject);
563 Object& parent = m_allObjects[parentUID];
564 if (!parent) {
565 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
566 const DataType type = DataType::dataTypeOf(nativeObject);
567 parent = Object(uids, type);
568 }
569 parent.members().push_back(member);
570 const Object obj(uids, type);
571 const bool bExistsAlready = m_allObjects.count(uids[0]);
572 const bool isValidObject = obj;
573 const bool bExistingObjectIsInvalid = !m_allObjects[uids[0]];
574 if (!bExistsAlready || (bExistingObjectIsInvalid && isValidObject)) {
575 m_allObjects[uids[0]] = obj;
576 // recurse serialization for all members of this member
577 // (only for struct/class types, noop for primitive types)
578 SerializationRecursion<T_memberType>::serializeObject(this, nativeMember);
579 }
580 }
581
582 virtual void decode(const RawData& data);
583 virtual void decode(const uint8_t* data, size_t size);
584 void clear();
585 bool isModified() const;
586 void removeMember(Object& parent, const Member& member);
587 void remove(const Object& obj);
588 Object& rootObject();
589 Object& objectByUID(const UID& uid);
590 void setAutoValue(Object& object, String value);
591 void setIntValue(Object& object, int64_t value);
592 void setRealValue(Object& object, double value);
593 void setBoolValue(Object& object, bool value);
594 void setEnumValue(Object& object, uint64_t value);
595 String valueAsString(const Object& object);
596 String name() const;
597 void setName(String name);
598 String comment() const;
599 void setComment(String comment);
600 time_t timeStampCreated() const;
601 time_t timeStampModified() const;
602 tm dateTimeCreated(time_base_t base = LOCAL_TIME) const;
603 tm dateTimeModified(time_base_t base = LOCAL_TIME) const;
604
605 protected:
606 // UID resolver for non-pointer types
607 template<typename T>
608 class UIDChainResolver {
609 public:
610 UIDChainResolver(const T& data) {
611 m_uid.push_back(UID::from(data));
612 }
613
614 operator UIDChain() const { return m_uid; }
615 UIDChain operator()() const { return m_uid; }
616 private:
617 UIDChain m_uid;
618 };
619
620 // UID resolver for pointer types (of 1st degree)
621 template<typename T>
622 class UIDChainResolver<T*> {
623 public:
624 UIDChainResolver(const T*& data) {
625 m_uid.push_back((UID) { &data, sizeof(data) });
626 m_uid.push_back((UID) { data, sizeof(*data) });
627 }
628
629 operator UIDChain() const { return m_uid; }
630 UIDChain operator()() const { return m_uid; }
631 private:
632 UIDChain m_uid;
633 };
634
635 // SerializationRecursion for non-pointer class/struct types.
636 template<typename T, bool T_isRecursive>
637 struct SerializationRecursionImpl {
638 static void serializeObject(Archive* archive, const T& obj) {
639 const_cast<T&>(obj).serialize(archive);
640 }
641 };
642
643 // SerializationRecursion for pointers (of 1st degree) to class/structs.
644 template<typename T, bool T_isRecursive>
645 struct SerializationRecursionImpl<T*,T_isRecursive> {
646 static void serializeObject(Archive* archive, const T*& obj) {
647 if (!obj) return;
648 const_cast<T*&>(obj)->serialize(archive);
649 }
650 };
651
652 // NOOP SerializationRecursion for primitive types.
653 template<typename T>
654 struct SerializationRecursionImpl<T,false> {
655 static void serializeObject(Archive* archive, const T& obj) {}
656 };
657
658 // NOOP SerializationRecursion for pointers (of 1st degree) to primitive types.
659 template<typename T>
660 struct SerializationRecursionImpl<T*,false> {
661 static void serializeObject(Archive* archive, const T*& obj) {}
662 };
663
664 // Automatically handles recursion for class/struct types, while ignoring all primitive types.
665 template<typename T>
666 struct SerializationRecursion : SerializationRecursionImpl<T, __is_class(T)> {
667 };
668
669 class ObjectPool : public std::map<UID,Object> {
670 public:
671 // prevent passing obvious invalid UID values from creating a new pair entry
672 Object& operator[](const UID& k) {
673 static Object invalid;
674 if (!k.isValid()) {
675 invalid = Object();
676 return invalid;
677 }
678 return std::map<UID,Object>::operator[](k);
679 }
680 };
681
682 friend String _encode(const ObjectPool& objects);
683
684 private:
685 String _encodeRootBlob();
686 void _popRootBlob(const char*& p, const char* end);
687 void _popObjectsBlob(const char*& p, const char* end);
688
689 protected:
690 class Syncer {
691 public:
692 Syncer(Archive& dst, Archive& src);
693 protected:
694 void syncObject(const Object& dst, const Object& src);
695 void syncPrimitive(const Object& dst, const Object& src);
696 void syncPointer(const Object& dst, const Object& src);
697 void syncMember(const Member& dstMember, const Member& srcMember);
698 static Member dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember);
699 private:
700 Archive& m_dst;
701 Archive& m_src;
702 };
703
704 virtual void encode();
705
706 ObjectPool m_allObjects;
707 operation_t m_operation;
708 UID m_root;
709 RawData m_rawData;
710 bool m_isModified;
711 String m_name;
712 String m_comment;
713 time_t m_timeCreated;
714 time_t m_timeModified;
715 };
716
717 /**
718 * Will be thrown whenever an error occurs during an serialization or
719 * deserialization process.
720 */
721 class Exception {
722 public:
723 String Message;
724
725 Exception(String Message) { Exception::Message = Message; }
726 void PrintMessage();
727 virtual ~Exception() {}
728 };
729
730 } // namespace Serialization
731
732 #endif // LIBGIG_SERIALIZATION_H

  ViewVC Help
Powered by ViewVC