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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3183 - (show annotations) (download)
Mon May 15 18:44:32 2017 UTC (6 years, 10 months ago) by schoenebeck
File size: 90294 byte(s)
* Wrote API documentation for entire new Serialization
  framework.
* Hide some of the method implementation of the Serialization
  framework.

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 #include "Serialization.h"
25
26 #include <iostream>
27 #include <assert.h>
28 #include <string.h> // for memcpy()
29 #include <stdlib.h> // for atof()
30 #include <cxxabi.h>
31
32 #include "helper.h"
33
34 #define LIBGIG_EPOCH_TIME ((time_t)0)
35
36 namespace Serialization {
37
38 // *************** DataType ***************
39 // *
40
41 static UID _createNullUID() {
42 const UID uid = { NULL, 0 };
43 return uid;
44 }
45
46 const UID NO_UID = _createNullUID();
47
48 /** @brief Check whether this is a valid unique identifier.
49 *
50 * Returns @c false if this UID can be considered an invalid unique
51 * identifier. This is for example the case if this UID object was not
52 * explicitly set to some certain meaningful unique identifier value, or if
53 * this UID object was intentionally assigned the constant @c NO_UID value.
54 * Both represent essentially an UID object which is all zero.
55 *
56 * Note that this class also implements the @c bool operator, both return
57 * the same boolean result.
58 */
59 bool UID::isValid() const {
60 return id != NULL && id != (void*)-1 && size;
61 }
62
63 // *************** DataType ***************
64 // *
65
66 /** @brief Default constructor.
67 *
68 * Initializes a DataType object as being an "invalid" DataType object.
69 * Thus calling isValid(), after creating a DataType object with this
70 * constructor, would return @c false.
71 *
72 * To create a valid and meaningful DataType object instead, call the static
73 * function DataType::dataTypeOf() instead.
74 */
75 DataType::DataType() {
76 m_size = 0;
77 m_isPointer = false;
78 }
79
80 DataType::DataType(bool isPointer, int size, String baseType, String customType) {
81 m_size = size;
82 m_isPointer = isPointer;
83 m_baseTypeName = baseType;
84 m_customTypeName = customType;
85 }
86
87 /** @brief Check if this is a valid DataType object.
88 *
89 * Returns @c true if this DataType object is reflecting a valid data type.
90 * The default constructor creates DataType objects initialized to be
91 * "invalid" DataType objects by default. That way one can detect whether
92 * a DataType object was ever assigned to something meaningful.
93 *
94 * Note that this class also implements the @c bool operator, both return
95 * the same boolean result.
96 */
97 bool DataType::isValid() const {
98 return m_size;
99 }
100
101 /** @brief Whether this is reflecting a C/C++ pointer type.
102 *
103 * Returns @true if the respective native C/C++ object, member or variable
104 * (this DataType instance is reflecting) is a C/C++ pointer type.
105 */
106 bool DataType::isPointer() const {
107 return m_isPointer;
108 }
109
110 /** @brief Whether this is reflecting a C/C++ @c struct or @c class type.
111 *
112 * Returns @c true if the respective native C/C++ object, member or variable
113 * (this DataType instance is reflecting) is a C/C++ @c struct or @c class
114 * type.
115 *
116 * Note that in the following example:
117 * @code
118 * struct Foo {
119 * int a;
120 * bool b;
121 * };
122 * Foo foo;
123 * Foo* pFoo;
124 * @endcode
125 * the DataType objects of both @c foo, as well as of the C/C++ pointer
126 * @c pFoo would both return @c true for isClass() here!
127 *
128 * @see isPointer()
129 */
130 bool DataType::isClass() const {
131 return m_baseTypeName == "class";
132 }
133
134 /** @brief Whether this is reflecting a fundamental C/C++ data type.
135 *
136 * Returns @c true if the respective native C/C++ object, member or variable
137 * (this DataType instance is reflecting) is a primitive, fundamental C/C++
138 * data type. Those are fundamental data types which are already predefined
139 * by the C/C++ language, for example: @c char, @c int, @c float, @c double,
140 * @c bool, but also @b any pointer types like @c int*, @c double**, but
141 * including pointers to user defined types like:
142 * @code
143 * struct Foo {
144 * int a;
145 * bool b;
146 * };
147 * Foo* pFoo;
148 * @endcode
149 * So the DataType object of @c pFoo in the latter example would also return
150 * @c true for isPrimitive() here!
151 *
152 * @see isPointer()
153 */
154 bool DataType::isPrimitive() const {
155 return !isClass();
156 }
157
158 /** @brief Whether this is an integer C/C++ data type.
159 *
160 * Returns @c true if the respective native C/C++ object, member or variable
161 * (this DataType instance is reflecting) is a (fundamental, primitive)
162 * integer data type. So these are all @c int and @c unsigned @c int types
163 * of any size. It does not include floating point ("real") types though.
164 *
165 * You may use isSigned() to further check whether this data type allows
166 * negative numbers.
167 *
168 * Note that this method also returns @c true on integer pointer types!
169 *
170 * @see isPointer()
171 */
172 bool DataType::isInteger() const {
173 return m_baseTypeName.substr(0, 3) == "int" ||
174 m_baseTypeName.substr(0, 4) == "uint";
175 }
176
177 /** @brief Whether this is a floating point based C/C++ data type.
178 *
179 * Returns @c true if the respective native C/C++ object, member or variable
180 * (this DataType instance is reflecting) is a (fundamental, primitive)
181 * floating point based data type. So these are currently the C/C++ @c float
182 * and @c double types. It does not include integer types though.
183 *
184 * Note that this method also returns @c true on @c float pointer and
185 * @c double pointer types!
186 *
187 * @see isPointer()
188 */
189 bool DataType::isReal() const {
190 return m_baseTypeName.substr(0, 4) == "real";
191 }
192
193 /** @brief Whether this is a boolean C/C++ data type.
194 *
195 * Returns @c true if the respective native C/C++ object, member or variable
196 * (this DataType instance is reflecting) is a (fundamental, primitive)
197 * boolean data type. So this is the case for the C++ @c bool data type.
198 * It does not include integer or floating point types though.
199 *
200 * Note that this method also returns @c true on @c bool pointer types!
201 *
202 * @see isPointer()
203 */
204 bool DataType::isBool() const {
205 return m_baseTypeName == "bool";
206 }
207
208 /** @brief Whether this is a C/C++ @c enum data type.
209 *
210 * Returns @c true if the respective native C/C++ object, member or variable
211 * (this DataType instance is reflecting) is a user defined enumeration
212 * data type. So this is the case for all C/C++ @c enum data types.
213 * It does not include integer (or even floating point) types though.
214 *
215 * Note that this method also returns @c true on @c enum pointer types!
216 *
217 * @see isPointer()
218 */
219 bool DataType::isEnum() const {
220 return m_baseTypeName == "enum";
221 }
222
223 /** @brief Whether this is a signed integer C/C++ data type.
224 *
225 * Returns @c true if the respective native C/C++ object, member or variable
226 * (this DataType instance is reflecting) is a (fundamental, primitive)
227 * signed integer data type. This is the case for are all @c unsigned
228 * @c int C/C++ types of any size. For all floating point ("real") based
229 * types this method returns @c false though!
230 *
231 * Note that this method also returns @c true on signed integer pointer
232 * types!
233 *
234 * @see isInteger();
235 */
236 bool DataType::isSigned() const {
237 return m_baseTypeName.substr(0, 3) == "int" ||
238 isReal();
239 }
240
241 /** @brief Comparison for equalness.
242 *
243 * Returns @c true if the two DataType objects being compared can be
244 * considered to be "equal" C/C++ data types. They are considered to be
245 * equal if their underlying C/C++ data types are exactly identical. For
246 * example comparing @c int and @c unsigned int data types are considere to
247 * be @b not equal, since they are differently signed. Furthermore @c short
248 * @c int and @c long @c int would also not be considered to be equal, since
249 * they do have a different memory size. Additionally pointer type
250 * characteristic is compared as well. So a @c double type and @c double*
251 * type are also considered to be not equal data types and hence this method
252 * would return @c false.
253 */
254 bool DataType::operator==(const DataType& other) const {
255 return m_baseTypeName == other.m_baseTypeName &&
256 m_customTypeName == other.m_customTypeName &&
257 m_size == other.m_size &&
258 m_isPointer == other.m_isPointer;
259 }
260
261 /** @brief Comparison for inequalness.
262 *
263 * Returns the inverse result of what DataType::operator==() would return.
264 * So refer to the latter for more details.
265 */
266 bool DataType::operator!=(const DataType& other) const {
267 return !operator==(other);
268 }
269
270 /** @brief Smaller than comparison.
271 *
272 * Returns @c true if this DataType object can be consider to be "smaller"
273 * than the @a other DataType object being compared with. This operator
274 * is actually quite arbitrarily implemented and may change at any time,
275 * and thus result for the same data types may change in future at any time.
276 *
277 * This operator is basically implemented for allowing this DataType class
278 * to be used with various standard template library (STL) classes, which
279 * require sorting operators to be implemented.
280 */
281 bool DataType::operator<(const DataType& other) const {
282 return m_baseTypeName < other.m_baseTypeName ||
283 (m_baseTypeName == other.m_baseTypeName &&
284 m_customTypeName < other.m_customTypeName ||
285 (m_customTypeName == other.m_customTypeName &&
286 m_size < other.m_size ||
287 (m_size == other.m_size &&
288 m_isPointer < other.m_isPointer)));
289 }
290
291 /** @brief Greater than comparison.
292 *
293 * Returns @c true if this DataType object can be consider to be "greater"
294 * than the @a other DataType object being compared with. This operator
295 * is actually quite arbitrarily implemented and may change at any time,
296 * and thus result for the same data types may change in future at any time.
297 *
298 * This operator is basically implemented for allowing this DataType class
299 * to be used with various standard template library (STL) classes, which
300 * require sorting operators to be implemented.
301 */
302 bool DataType::operator>(const DataType& other) const {
303 return !(operator==(other) || operator<(other));
304 }
305
306 /** @brief Human readable long description for this data type.
307 *
308 * Returns a human readable long description for this data type, designed
309 * for the purpose for being displayed to the user. Note that the
310 * implementation for this method and thus the precise textual strings
311 * returned by this method, may change at any time. So you should not rely
312 * on precise strings for certain data types, and you should not use the
313 * return values of this method for comparing data types with each other.
314 *
315 * This class implements various comparison operators, so you should use
316 * them for comparing DataTypes objects instead.
317 *
318 * @see baseTypeName(), customTypeName()
319 */
320 String DataType::asLongDescr() const {
321 String s = m_baseTypeName;
322 if (!m_customTypeName.empty())
323 s += " " + customTypeName(true);
324 if (isPointer())
325 s += " pointer";
326 return s;
327 }
328
329 /** @brief The base type name of this data type.
330 *
331 * Returns a textual short string identifying the basic type of name of this
332 * data type. For example for a 32 bit signed integer data type this method
333 * would return @c "int32". For all user defined C/C++ @c enum types this
334 * method would return "enum". For all user defined C/C++ @c struct @b and
335 * @c class types this method would return "class" for both. Note that the
336 * precise user defined type name (of i.e. @c enum, @c struct and @c class
337 * types) is not included in the string returned by this method, use
338 * customTypeName() to retrieve that information instead.
339 *
340 * The precise textual strings returned by this method are guaranteed to
341 * retain equal with future versions of this framework. So you can rely on
342 * them for using the return values of this method for comparison tasks in
343 * your application. Note however that this class also implements various
344 * comparison operators.
345 *
346 * Further it is important to know that this method returns the same string
347 * for pointers and non-pointers of the same underlying data type. So in the
348 * following example:
349 * @code
350 * #include <stdint.h>
351 * uint64_t i;
352 * uint64_t* pi;
353 * @endcode
354 * this method would return for both @c i and @c pi the string @c "uint64" !
355 *
356 * @see isPointer(), customTypeName()
357 */
358 String DataType::baseTypeName() const {
359 return m_baseTypeName;
360 }
361
362 /** @brief The user defined C/C++ data type name of this data type.
363 *
364 * Call this method on user defined C/C++ data types like @c enum, @c struct
365 * and @c class types to retrieve the user defined type name portion of
366 * those data types. Note that this method is only intended for such user
367 * defined data types. For all fundamental, primitive data types (like i.e.
368 * @c int) this method returns an empty string instead.
369 *
370 * This method takes an optional boolean argument @b demangle, which allows
371 * you define whether you are interested in the raw C++ type name or rather
372 * the demangled custom type name. By default this method returns the raw
373 * C++ type name. The raw C++ type name is the one that is actually used
374 * in the compiled binaries and should be preferred for comparions tasks.
375 * The demangled C++ type name is a human readable representation of the
376 * type name instead, which you may use for displaying the user defined type
377 * name portion to the user, however you should not use the demangled
378 * representation for comparison tasks.
379 *
380 * Note that in the following example:
381 * @code
382 * struct Foo {
383 * int a;
384 * bool b;
385 * };
386 * Foo foo;
387 * Foo* pFoo;
388 * @endcode
389 * this method would return the same string for both @c foo and @c pFoo !
390 * In the latter example @c customTypeName(true) would return for both
391 * @c foo and @c pFoo the string @c "Foo" as return value of this method.
392 *
393 * @see isPointer(), baseTypeName()
394 */
395 String DataType::customTypeName(bool demangle) const {
396 if (!demangle) return m_customTypeName;
397 int status;
398 const char* result =
399 abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);
400 return (status == 0) ? result : m_customTypeName;
401 }
402
403 // *************** Member ***************
404 // *
405
406 /** @brief Default constructor.
407 *
408 * Initializes a Member object as being an "invalid" Member object.
409 * Thus calling isValid(), after creating a Member object with this
410 * constructor, would return @c false.
411 *
412 * You are currently not supposed to create (meaningful) Member objects on
413 * your own. This framework automatically create such Member objects for
414 * you instead.
415 *
416 * @see Object::members()
417 */
418 Member::Member() {
419 m_uid = NO_UID;
420 m_offset = 0;
421 }
422
423 Member::Member(String name, UID uid, size_t offset, DataType type) {
424 m_name = name;
425 m_uid = uid;
426 m_offset = offset;
427 m_type = type;
428 }
429
430 /** @brief Unique identifier of this member instance.
431 *
432 * Returns the unique identifier of the original C/C++ member instance of
433 * your C++ class. It is important to know that this unique identifier is
434 * not generated particularly for Member objects. That means no matter how
435 * many individual Member objects are created, as long as they are
436 * representing the same member variable of the same original native
437 * instance of your C++ class, then all those separately created Member
438 * objects return the same unique identifier here.
439 *
440 * @see UID for more details
441 */
442 UID Member::uid() const {
443 return m_uid;
444 }
445
446 /** @brief Name of the member.
447 *
448 * Returns the name of the native C/C++ member variable as originally typed
449 * in its C++ source code. So in the following example:
450 * @code
451 * struct Foo {
452 * int a;
453 * bool b;
454 * double someValue;
455 * };
456 * @endcode
457 * this method would usually return @c "a" for the first member of object
458 * instances of your native C/C++ @c struct @c Foo, and this method would
459 * usually return @c "someValue" for its third member.
460 *
461 * Note that when you implement the @c serialize() method of your own C/C++
462 * clases or strucs, you are able to override defining the precise name of
463 * your members. In that case this method would of course return the member
464 * names as explicitly forced by you instead.
465 */
466 String Member::name() const {
467 return m_name;
468 }
469
470 /** @brief Offset of member in its containing parent data structure.
471 *
472 * Returns the offset of this member (in bytes) within its containing parent
473 * user defined data structure or class. So in the following example:
474 * @code
475 * #include <stdint.h>
476 * struct Foo __attribute__ ((__packed__)) {
477 * int32_t a;
478 * bool b;
479 * double c;
480 * };
481 * @endcode
482 * this method would typically return @c 0 for member @c a, @c 4 for member
483 * @c b and @c 5 for member @c c. As you have noted in the latter example,
484 * the structure @c Foo was declared to have "packed" data members. That
485 * means the compiler is instructed to add no memory spaces between the
486 * individual members. Because by default the compiler might add memory
487 * spaces between individual members to align them on certain memory address
488 * boundaries for increasing runtime performance while accessing the
489 * members. So if you declared the previous example without the "packed"
490 * attribute like:
491 * @code
492 * #include <stdint.h>
493 * struct Foo {
494 * int32_t a;
495 * bool b;
496 * double c;
497 * };
498 * @endcode
499 * then this method would usually return a different offset for members
500 * @c b and @c c instead. For most 64 bit architectures this example would
501 * now still return @c 0 for member @c a, but @c 8 for member @c b and @c 16
502 * for member @c c.
503 */
504 size_t Member::offset() const {
505 return m_offset;
506 }
507
508 /** @brief C/C++ Data type of this member.
509 *
510 * Returns the precise data type of the original native C/C++ member.
511 */
512 const DataType& Member::type() const {
513 return m_type;
514 }
515
516 /** @brief Check if this is a valid Member object.
517 *
518 * Returns @c true if this Member object is reflecting a "valid" member
519 * object. The default constructor creates Member objects initialized to be
520 * "invalid" Member objects by default. That way one can detect whether
521 * a Member object was ever assigned to something meaningful.
522 *
523 * Note that this class also implements the @c bool operator, both return
524 * the same boolean result value.
525 */
526 bool Member::isValid() const {
527 return m_uid && !m_name.empty() && m_type;
528 }
529
530 /** @brief Comparison for equalness.
531 *
532 * Returns @c true if the two Member objects being compared can be
533 * considered to be "equal" C/C++ members. They are considered to be
534 * equal if their data type, member name, their offset within their parent
535 * containing C/C++ data structure, as well as their original native C/C++
536 * instance were exactly identical.
537 */
538 bool Member::operator==(const Member& other) const {
539 return m_uid == other.m_uid &&
540 m_offset == other.m_offset &&
541 m_name == other.m_name &&
542 m_type == other.m_type;
543 }
544
545 /** @brief Comparison for inequalness.
546 *
547 * Returns the inverse result of what Member::operator==() would return.
548 * So refer to the latter for more details.
549 */
550 bool Member::operator!=(const Member& other) const {
551 return !operator==(other);
552 }
553
554 /** @brief Smaller than comparison.
555 *
556 * Returns @c true if this Member object can be consider to be "smaller"
557 * than the @a other Member object being compared with. This operator
558 * is actually quite arbitrarily implemented and may change at any time,
559 * and thus result for the same member representations may change in
560 * future at any time.
561 *
562 * This operator is basically implemented for allowing this DataType class
563 * to be used with various standard template library (STL) classes, which
564 * require sorting operators to be implemented.
565 */
566 bool Member::operator<(const Member& other) const {
567 return m_uid < other.m_uid ||
568 (m_uid == other.m_uid &&
569 m_offset < other.m_offset ||
570 (m_offset == other.m_offset &&
571 m_name < other.m_name ||
572 (m_name == other.m_name &&
573 m_type < other.m_type)));
574 }
575
576 /** @brief Greater than comparison.
577 *
578 * Returns @c true if this Member object can be consider to be "greater"
579 * than the @a other Member object being compared with. This operator
580 * is actually quite arbitrarily implemented and may change at any time,
581 * and thus result for the same member representations may change in
582 * future at any time.
583 *
584 * This operator is basically implemented for allowing this DataType class
585 * to be used with various standard template library (STL) classes, which
586 * require sorting operators to be implemented.
587 */
588 bool Member::operator>(const Member& other) const {
589 return !(operator==(other) || operator<(other));
590 }
591
592 // *************** Object ***************
593 // *
594
595 /** @brief Default constructor (for an "invalid" Object).
596 *
597 * Initializes an Object instance as being an "invalid" Object.
598 * Thus calling isValid(), after creating an Object instance with this
599 * constructor, would return @c false.
600 *
601 * Usually you are not supposed to create (meaningful) Object instances on
602 * your own. They are typically constructed by the Archive class for you.
603 *
604 * @see Archive::rootObject(), Archive::objectByUID()
605 */
606 Object::Object() {
607 m_version = 0;
608 m_minVersion = 0;
609 }
610
611 /** @brief Constructor for a "meaningful" Object.
612 *
613 * Initializes a "meaningful" Object instance as being. Thus calling
614 * isValid(), after creating an Object instance with this constructor,
615 * should return @c true, provided that the arguments passed to this
616 * constructor construe a valid object representation.
617 *
618 * Usually you are not supposed to create (meaningful) Object instances on
619 * your own. They are typically constructed by the Archive class for you.
620 *
621 * @see Archive::rootObject(), Archive::objectByUID()
622 *
623 * @param uidChain - unique identifier chain of the object to be constructed
624 * @param type - C/C++ data type of the actual native object this abstract
625 * Object instance should reflect after calling this
626 * constructor
627 */
628 Object::Object(UIDChain uidChain, DataType type) {
629 m_type = type;
630 m_uid = uidChain;
631 m_version = 0;
632 m_minVersion = 0;
633 //m_data.resize(type.size());
634 }
635
636 /** @brief Check if this is a valid Object instance.
637 *
638 * Returns @c true if this Object instance is reflecting a "valid" Object.
639 * The default constructor creates Object instances initialized to be
640 * "invalid" Objects by default. That way one can detect whether an Object
641 * instance was ever assigned to something meaningful.
642 *
643 * Note that this class also implements the @c bool operator, both return
644 * the same boolean result value.
645 */
646 bool Object::isValid() const {
647 return m_type && !m_uid.empty();
648 }
649
650 /** @brief Unique identifier of this Object.
651 *
652 * Returns the unique identifier for the original native C/C++ data this
653 * abstract Object instance is reflecting. If this Object is representing
654 * a C/C++ pointer (of first degree) then @c uid() (or @c uid(0) ) returns
655 * the unique identifier of the pointer itself, whereas @c uid(1) returns
656 * the unique identifier of the original C/C++ data that pointer was
657 * actually pointing to.
658 *
659 * @see UIDChain for more details about this overall topic.
660 */
661 UID Object::uid(int index) const {
662 return (index < m_uid.size()) ? m_uid[index] : NO_UID;
663 }
664
665 /** @brief Unique identifier chain of this Object.
666 *
667 * Returns the entire unique identifier chain of this Object.
668 *
669 * @see uid() and UIDChain for more details about this overall topic.
670 */
671 const UIDChain& Object::uidChain() const {
672 return m_uid;
673 }
674
675 /** @brief C/C++ data type this Object is reflecting.
676 *
677 * Returns the precise original C/C++ data type of the original native
678 * C/C++ object or data this Object instance is reflecting.
679 */
680 const DataType& Object::type() const {
681 return m_type;
682 }
683
684 /** @brief Raw data of the original native C/C++ data.
685 *
686 * Returns the raw data value of the original C/C++ data this Object is
687 * reflecting. So the precise raw data value, layout and size is dependent
688 * to the precise C/C++ data type of the original native C/C++ data. However
689 * potentially required endian correction is already automatically applied
690 * for you. That means you can safely, directly C-cast the raw data returned
691 * by this method to the respective native C/C++ data type in order to
692 * access and use the value for some purpose, at least if the respective
693 * data is of any fundamental, primitive C/C++ data type, or also to a
694 * certain extent if the type is user defined @c enum type.
695 *
696 * However directly C-casting this raw data for user defined @c struct or
697 * @c class types is not possible. For those user defined data structures
698 * this method always returns empty raw data instead.
699 *
700 * Note however that there are more convenient methods in the Archive class
701 * to get the right value for the individual data types instead.
702 *
703 * @see Archive::valueAsInt(), Archive::valueAsReal(), Archive::valueAsBool(),
704 * Archive::valueAsString()
705 */
706 const RawData& Object::rawData() const {
707 return m_data;
708 }
709
710 /** @brief Version of original user defined C/C++ @c struct or @c class.
711 *
712 * In case this Object is reflecting a native C/C++ @c struct or @c class
713 * type, then this method returns the version of that native C/C++ @c struct
714 * or @c class layout or implementation. For primitive, fundamental C/C++
715 * data types the return value of this method has no meaning.
716 *
717 * @see Archive::setVersion() for more details about this overall topic.
718 */
719 Version Object::version() const {
720 return m_version;
721 }
722
723 /** @brief Minimum version of original user defined C/C++ @c struct or @c class.
724 *
725 * In case this Object is reflecting a native C/C++ @c struct or @c class
726 * type, then this method returns the "minimum" version of that native C/C++
727 * @c struct or @c class layout or implementation which it may be compatible
728 * with. For primitive, fundamental C/C++ data types the return value of
729 * this method has no meaning.
730 *
731 * @see Archive::setVersion() and Archive::setMinVersion() for more details
732 * about this overall topic.
733 */
734 Version Object::minVersion() const {
735 return m_minVersion;
736 }
737
738 /** @brief All members of the original native C/C++ @c struct or @c class instance.
739 *
740 * In case this Object is reflecting a native C/C++ @c struct or @c class
741 * type, then this method returns all member variables of that original
742 * native C/C++ @c struct or @c class instance. For primitive, fundamental
743 * C/C++ data types this method returns an empty vector instead.
744 *
745 * Example:
746 * @code
747 * struct Foo {
748 * int a;
749 * bool b;
750 * double someValue;
751 * };
752 * @endcode
753 * Considering above's C++ code, a serialized Object representation of such
754 * a native @c Foo class would have 3 members @c a, @c b and @c someValue.
755 *
756 * Note that the respective serialize() method implementation of that
757 * fictional C++ @c struct @c Foo actually defines which members are going
758 * to be serialized and deserialized for instances of class @c Foo. So in
759 * practice the members returned by method members() here might return a
760 * different set of members as actually defined in the original C/C++ struct
761 * header declaration.
762 *
763 * The precise sequence of the members returned by this method here depends
764 * on the actual serialize() implementation of the user defined C/C++
765 * @c struct or @c class.
766 *
767 * @see Object::sequenceIndexOf() for more details about the precise order
768 * of members returned by this method in the same way.
769 */
770 std::vector<Member>& Object::members() {
771 return m_members;
772 }
773
774 /** @brief All members of the original native C/C++ @c struct or @c class instance (read only).
775 *
776 * Returns the same result as overridden members() method above, it just
777 * returns a read-only result instead. See above's method description for
778 * details for the return value of this method instead.
779 */
780 const std::vector<Member>& Object::members() const {
781 return m_members;
782 }
783
784 /** @brief Comparison for equalness.
785 *
786 * Returns @c true if the two Object instances being compared can be
787 * considered to be "equal" native C/C++ object instances. They are
788 * considered to be equal if they are representing the same original
789 * C/C++ data instance, which is essentially the case if the original
790 * reflecting native C/C++ data are sharing the same memory address and
791 * memory size (thus the exact same memory space) and originally had the
792 * exact same native C/C++ types.
793 */
794 bool Object::operator==(const Object& other) const {
795 // ignoring all other member variables here
796 // (since UID stands for "unique" ;-) )
797 return m_uid == other.m_uid &&
798 m_type == other.m_type;
799 }
800
801 /** @brief Comparison for inequalness.
802 *
803 * Returns the inverse result of what Object::operator==() would return.
804 * So refer to the latter for more details.
805 */
806 bool Object::operator!=(const Object& other) const {
807 return !operator==(other);
808 }
809
810 /** @brief Smaller than comparison.
811 *
812 * Returns @c true if this Object instance can be consider to be "smaller"
813 * than the @a other Object instance being compared with. This operator
814 * is actually quite arbitrarily implemented and may change at any time,
815 * and thus result for the same Object representations may change in future
816 * at any time.
817 *
818 * This operator is basically implemented for allowing this DataType class
819 * to be used with various standard template library (STL) classes, which
820 * require sorting operators to be implemented.
821 */
822 bool Object::operator<(const Object& other) const {
823 // ignoring all other member variables here
824 // (since UID stands for "unique" ;-) )
825 return m_uid < other.m_uid ||
826 (m_uid == other.m_uid &&
827 m_type < other.m_type);
828 }
829
830 /** @brief Greater than comparison.
831 *
832 * Returns @c true if this Object instance can be consider to be "greater"
833 * than the @a other Object instance being compared with. This operator
834 * is actually quite arbitrarily implemented and may change at any time,
835 * and thus result for the same Object representations may change in future
836 * at any time.
837 *
838 * This operator is basically implemented for allowing this DataType class
839 * to be used with various standard template library (STL) classes, which
840 * require sorting operators to be implemented.
841 */
842 bool Object::operator>(const Object& other) const {
843 return !(operator==(other) || operator<(other));
844 }
845
846 /** @brief Check version compatibility between Object instances.
847 *
848 * Use this method to check whether the two original C/C++ instances those
849 * two Objects are reflecting, were using a C/C++ data type which are version
850 * compatible with each other. By default all C/C++ Objects are considered
851 * to be version compatible. They might only be version incompatible if you
852 * enforced a certain backward compatibility constraint with your
853 * serialize() method implementation of your custom C/C++ @c struct or
854 * @c class types.
855 *
856 * You must only call this method on two Object instances which are
857 * representing the same data type, for example if both Objects reflect
858 * instances of the same user defined C++ class. Calling this method on
859 * completely different data types does not cause an error or exception, but
860 * its result would simply be useless for any purpose.
861 *
862 * @see Archive::setVersion() for more details about this overall topic.
863 */
864 bool Object::isVersionCompatibleTo(const Object& other) const {
865 if (this->version() == other.version())
866 return true;
867 if (this->version() > other.version())
868 return this->minVersion() <= other.version();
869 else
870 return other.minVersion() <= this->version();
871 }
872
873 void Object::setVersion(Version v) {
874 m_version = v;
875 }
876
877 void Object::setMinVersion(Version v) {
878 m_minVersion = v;
879 }
880
881 /** @brief Get the member of this Object with given name.
882 *
883 * In case this Object is reflecting a native C/C++ @c struct or @c class
884 * type, then this method returns the abstract reflection of the requested
885 * member variable of the original native C/C++ @c struct or @c class
886 * instance. For primitive, fundamental C/C++ data types this method always
887 * returns an "invalid" Member instance instead.
888 *
889 * Example:
890 * @code
891 * struct Foo {
892 * int a;
893 * bool b;
894 * double someValue;
895 * };
896 * @endcode
897 * Consider that you serialized the native C/C++ @c struct as shown in this
898 * example, and assuming that you implemented the respective serialize()
899 * method of this C++ @c struct to serialize all its members, then you might
900 * call memberNamed("someValue") to get the details of the third member in
901 * this example for instance. In case the passed @a name is an unknown
902 * member name, then this method will return an "invalid" Member object
903 * instead.
904 *
905 * @param name - original name of the sought serialized member variable of
906 * this Object reflection
907 * @returns abstract reflection of the sought member variable
908 * @see Member::isValid(), Object::members()
909 */
910 Member Object::memberNamed(String name) const {
911 for (int i = 0; i < m_members.size(); ++i)
912 if (m_members[i].name() == name)
913 return m_members[i];
914 return Member();
915 }
916
917 /** @brief Get the member of this Object with given unique identifier.
918 *
919 * This method behaves similar like method memberNamed() described above,
920 * but instead of searching for a member variable by name, it searches for
921 * a member with an abstract unique identifier instead. For primitive,
922 * fundamental C/C++ data types, for invalid or unknown unique identifiers,
923 * and for members which are actually not member instances of the original
924 * C/C++ @c struct or @c class instance this Object is reflecting, this
925 * method returns an "invalid" Member instance instead.
926 *
927 * @param uid - unique identifier of the member variable being sought
928 * @returns abstract reflection of the sought member variable
929 * @see Member::isValid(), Object::members(), Object::memberNamed()
930 */
931 Member Object::memberByUID(const UID& uid) const {
932 if (!uid) return Member();
933 for (int i = 0; i < m_members.size(); ++i)
934 if (m_members[i].uid() == uid)
935 return m_members[i];
936 return Member();
937 }
938
939 void Object::remove(const Member& member) {
940 for (int i = 0; i < m_members.size(); ++i) {
941 if (m_members[i] == member) {
942 m_members.erase(m_members.begin() + i);
943 return;
944 }
945 }
946 }
947
948 /** @brief Get all members of this Object with given data type.
949 *
950 * In case this Object is reflecting a native C/C++ @c struct or @c class
951 * type, then this method returns all member variables of that original
952 * native C/C++ @c struct or @c class instance which are matching the given
953 * requested data @a type. If this Object is reflecting a primitive,
954 * fundamental data type, or if there are no members of this Object with the
955 * requested precise C/C++ data type, then this method returns an empty
956 * vector instead.
957 *
958 * @param type - the precise C/C++ data type of the sought member variables
959 * of this Object
960 * @returns vector with abstract reflections of the sought member variables
961 * @see Object::members(), Object::memberNamed()
962 */
963 std::vector<Member> Object::membersOfType(const DataType& type) const {
964 std::vector<Member> v;
965 for (int i = 0; i < m_members.size(); ++i) {
966 const Member& member = m_members[i];
967 if (member.type() == type)
968 v.push_back(member);
969 }
970 return v;
971 }
972
973 /** @brief Serialization/deserialization sequence number of the requested member.
974 *
975 * Returns the precise serialization/deserialization sequence number of the
976 * requested @a member variable.
977 *
978 * Example:
979 * @code
980 * struct Foo {
981 * int a;
982 * bool b;
983 * double c;
984 *
985 * void serialize(Serialization::Archive* archive);
986 * };
987 * @endcode
988 * Assuming the declaration of the user defined native C/C++ @c struct
989 * @c Foo above, and assuming the following implementation of serialize():
990 * @code
991 * #define SRLZ(member) \
992 * archive->serializeMember(*this, member, #member);
993 *
994 * void Foo::serialize(Serialization::Archive* archive) {
995 * SRLZ(c);
996 * SRLZ(a);
997 * SRLZ(b);
998 * }
999 * @endcode
1000 * then @c sequenceIndexOf(obj.memberNamed("a")) returns 1,
1001 * @c sequenceIndexOf(obj.memberNamed("b")) returns 2, and
1002 * @c sequenceIndexOf(obj.memberNamed("c")) returns 0.
1003 */
1004 int Object::sequenceIndexOf(const Member& member) const {
1005 for (int i = 0; i < m_members.size(); ++i)
1006 if (m_members[i] == member)
1007 return i;
1008 return -1;
1009 }
1010
1011 // *************** Archive ***************
1012 // *
1013
1014 /** @brief Create an "empty" archive.
1015 *
1016 * This default constructor creates an "empty" archive which you then
1017 * subsequently for example might fill with serialized data like:
1018 * @code
1019 * Archive a;
1020 * a.serialize(&myRootObject);
1021 * @endcode
1022 * Or:
1023 * @code
1024 * Archive a;
1025 * a << myRootObject;
1026 * @endcode
1027 * Or you might also subsequently assign an already existing non-empty
1028 * to this empty archive, which effectively clones the other
1029 * archive (deep copy) or call decode() later on to assign a previously
1030 * serialized raw data stream.
1031 */
1032 Archive::Archive() {
1033 m_operation = OPERATION_NONE;
1034 m_root = NO_UID;
1035 m_isModified = false;
1036 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1037 }
1038
1039 /** @brief Create and fill the archive with the given serialized raw data.
1040 *
1041 * This constructor decodes the given raw @a data and constructs a
1042 * (non-empty) Archive object according to that given serialized data
1043 * stream.
1044 *
1045 * After this constructor returned, you may then traverse the individual
1046 * objects by starting with accessing the rootObject() for example. Finally
1047 * you might call deserialize() to restore your native C++ objects with the
1048 * content of this archive.
1049 *
1050 * @param data - the previously serialized raw data stream to be decoded
1051 * @throws Exception if the provided raw @a data uses an invalid, unknown,
1052 * incompatible or corrupt data stream or format.
1053 */
1054 Archive::Archive(const RawData& data) {
1055 m_operation = OPERATION_NONE;
1056 m_root = NO_UID;
1057 m_isModified = false;
1058 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1059 decode(m_rawData);
1060 }
1061
1062 /** @brief Create and fill the archive with the given serialized raw C-buffer data.
1063 *
1064 * This constructor essentially works like the constructor above, but just
1065 * uses another data type for the serialized raw data stream being passed to
1066 * this class.
1067 *
1068 * This constructor decodes the given raw @a data and constructs a
1069 * (non-empty) Archive object according to that given serialized data
1070 * stream.
1071 *
1072 * After this constructor returned, you may then traverse the individual
1073 * objects by starting with accessing the rootObject() for example. Finally
1074 * you might call deserialize() to restore your native C++ objects with the
1075 * content of this archive.
1076 *
1077 * @param data - the previously serialized raw data stream to be decoded
1078 * @param size - size of @a data in bytes
1079 * @throws Exception if the provided raw @a data uses an invalid, unknown,
1080 * incompatible or corrupt data stream or format.
1081 */
1082 Archive::Archive(const uint8_t* data, size_t size) {
1083 m_operation = OPERATION_NONE;
1084 m_root = NO_UID;
1085 m_isModified = false;
1086 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1087 decode(data, size);
1088 }
1089
1090 Archive::~Archive() {
1091 }
1092
1093 /** @brief Root C++ object of this archive.
1094 *
1095 * In case this is a non-empty Archive, then this method returns the so
1096 * called "root" C++ object. If this is an empty archive, then this method
1097 * returns an "invalid" Object instance instead.
1098 *
1099 * @see Archive::serialize() for more details about the "root" object concept.
1100 * @see Object for more details about the overall object reflection concept.
1101 * @returns reflection of the original native C++ root object
1102 */
1103 Object& Archive::rootObject() {
1104 return m_allObjects[m_root];
1105 }
1106
1107 static String _encodeBlob(String data) {
1108 return ToString(data.length()) + ":" + data;
1109 }
1110
1111 static String _encode(const UID& uid) {
1112 String s;
1113 s += _encodeBlob(ToString(size_t(uid.id)));
1114 s += _encodeBlob(ToString(size_t(uid.size)));
1115 return _encodeBlob(s);
1116 }
1117
1118 static String _encode(const time_t& time) {
1119 return _encodeBlob(ToString(time));
1120 }
1121
1122 static String _encode(const DataType& type) {
1123 String s;
1124 s += _encodeBlob(type.baseTypeName());
1125 s += _encodeBlob(type.customTypeName());
1126 s += _encodeBlob(ToString(type.size()));
1127 s += _encodeBlob(ToString(type.isPointer()));
1128 return _encodeBlob(s);
1129 }
1130
1131 static String _encode(const UIDChain& chain) {
1132 String s;
1133 for (int i = 0; i < chain.size(); ++i)
1134 s += _encode(chain[i]);
1135 return _encodeBlob(s);
1136 }
1137
1138 static String _encode(const Member& member) {
1139 String s;
1140 s += _encode(member.uid());
1141 s += _encodeBlob(ToString(member.offset()));
1142 s += _encodeBlob(member.name());
1143 s += _encode(member.type());
1144 return _encodeBlob(s);
1145 }
1146
1147 static String _encode(const std::vector<Member>& members) {
1148 String s;
1149 for (int i = 0; i < members.size(); ++i)
1150 s += _encode(members[i]);
1151 return _encodeBlob(s);
1152 }
1153
1154 static String _primitiveObjectValueToString(const Object& obj) {
1155 String s;
1156 const DataType& type = obj.type();
1157 const ID& id = obj.uid().id;
1158 void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1159 if (!obj.m_data.empty())
1160 assert(type.size() == obj.m_data.size());
1161 if (type.isPrimitive() && !type.isPointer()) {
1162 if (type.isInteger() || type.isEnum()) {
1163 if (type.isSigned()) {
1164 if (type.size() == 1)
1165 s = ToString((int16_t)*(int8_t*)ptr); // int16_t: prevent ToString() to render an ASCII character
1166 else if (type.size() == 2)
1167 s = ToString(*(int16_t*)ptr);
1168 else if (type.size() == 4)
1169 s = ToString(*(int32_t*)ptr);
1170 else if (type.size() == 8)
1171 s = ToString(*(int64_t*)ptr);
1172 else
1173 assert(false /* unknown signed int type size */);
1174 } else {
1175 if (type.size() == 1)
1176 s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
1177 else if (type.size() == 2)
1178 s = ToString(*(uint16_t*)ptr);
1179 else if (type.size() == 4)
1180 s = ToString(*(uint32_t*)ptr);
1181 else if (type.size() == 8)
1182 s = ToString(*(uint64_t*)ptr);
1183 else
1184 assert(false /* unknown unsigned int type size */);
1185 }
1186 } else if (type.isReal()) {
1187 if (type.size() == sizeof(float))
1188 s = ToString(*(float*)ptr);
1189 else if (type.size() == sizeof(double))
1190 s = ToString(*(double*)ptr);
1191 else
1192 assert(false /* unknown floating point type */);
1193 } else if (type.isBool()) {
1194 s = ToString(*(bool*)ptr);
1195 } else {
1196 assert(false /* unknown primitive type */);
1197 }
1198
1199 }
1200 return s;
1201 }
1202
1203 template<typename T>
1204 static T _primitiveObjectValueToNumber(const Object& obj) {
1205 T value = 0;
1206 const DataType& type = obj.type();
1207 const ID& id = obj.uid().id;
1208 void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1209 if (!obj.m_data.empty())
1210 assert(type.size() == obj.m_data.size());
1211 if (type.isPrimitive() && !type.isPointer()) {
1212 if (type.isInteger() || type.isEnum()) {
1213 if (type.isSigned()) {
1214 if (type.size() == 1)
1215 value = (T)*(int8_t*)ptr;
1216 else if (type.size() == 2)
1217 value = (T)*(int16_t*)ptr;
1218 else if (type.size() == 4)
1219 value = (T)*(int32_t*)ptr;
1220 else if (type.size() == 8)
1221 value = (T)*(int64_t*)ptr;
1222 else
1223 assert(false /* unknown signed int type size */);
1224 } else {
1225 if (type.size() == 1)
1226 value = (T)*(uint8_t*)ptr;
1227 else if (type.size() == 2)
1228 value = (T)*(uint16_t*)ptr;
1229 else if (type.size() == 4)
1230 value = (T)*(uint32_t*)ptr;
1231 else if (type.size() == 8)
1232 value = (T)*(uint64_t*)ptr;
1233 else
1234 assert(false /* unknown unsigned int type size */);
1235 }
1236 } else if (type.isReal()) {
1237 if (type.size() == sizeof(float))
1238 value = (T)*(float*)ptr;
1239 else if (type.size() == sizeof(double))
1240 value = (T)*(double*)ptr;
1241 else
1242 assert(false /* unknown floating point type */);
1243 } else if (type.isBool()) {
1244 value = (T)*(bool*)ptr;
1245 } else {
1246 assert(false /* unknown primitive type */);
1247 }
1248 }
1249 return value;
1250 }
1251
1252 static String _encodePrimitiveValue(const Object& obj) {
1253 return _encodeBlob( _primitiveObjectValueToString(obj) );
1254 }
1255
1256 static String _encode(const Object& obj) {
1257 String s;
1258 s += _encode(obj.type());
1259 s += _encodeBlob(ToString(obj.version()));
1260 s += _encodeBlob(ToString(obj.minVersion()));
1261 s += _encode(obj.uidChain());
1262 s += _encode(obj.members());
1263 s += _encodePrimitiveValue(obj);
1264 return _encodeBlob(s);
1265 }
1266
1267 String _encode(const Archive::ObjectPool& objects) {
1268 String s;
1269 for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1270 itObject != objects.end(); ++itObject)
1271 {
1272 const Object& obj = itObject->second;
1273 s += _encode(obj);
1274 }
1275 return _encodeBlob(s);
1276 }
1277
1278 #define MAGIC_START "Srx1v"
1279 #define ENCODING_FORMAT_MINOR_VERSION 0
1280
1281 String Archive::_encodeRootBlob() {
1282 String s;
1283 s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1284 s += _encode(m_root);
1285 s += _encode(m_allObjects);
1286 s += _encodeBlob(m_name);
1287 s += _encodeBlob(m_comment);
1288 s += _encode(m_timeCreated);
1289 s += _encode(m_timeModified);
1290 return _encodeBlob(s);
1291 }
1292
1293 void Archive::encode() {
1294 m_rawData.clear();
1295 String s = MAGIC_START;
1296 m_timeModified = time(NULL);
1297 if (m_timeCreated == LIBGIG_EPOCH_TIME)
1298 m_timeCreated = m_timeModified;
1299 s += _encodeRootBlob();
1300 m_rawData.resize(s.length() + 1);
1301 memcpy(&m_rawData[0], &s[0], s.length() + 1);
1302 m_isModified = false;
1303 }
1304
1305 struct _Blob {
1306 const char* p;
1307 const char* end;
1308 };
1309
1310 static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1311 if (!bThrow && p >= end) {
1312 const _Blob blob = { p, end };
1313 return blob;
1314 }
1315 size_t sz = 0;
1316 for (; true; ++p) {
1317 if (p >= end)
1318 throw Exception("Decode Error: Missing blob");
1319 const char& c = *p;
1320 if (c == ':') break;
1321 if (c < '0' || c > '9')
1322 throw Exception("Decode Error: Missing blob size");
1323 sz *= 10;
1324 sz += size_t(c - '0');
1325 }
1326 ++p;
1327 if (p + sz > end)
1328 throw Exception("Decode Error: Premature end of blob");
1329 const _Blob blob = { p, p + sz };
1330 return blob;
1331 }
1332
1333 template<typename T_int>
1334 static T_int _popIntBlob(const char*& p, const char* end) {
1335 _Blob blob = _decodeBlob(p, end);
1336 p = blob.p;
1337 end = blob.end;
1338
1339 T_int sign = 1;
1340 T_int i = 0;
1341 if (p >= end)
1342 throw Exception("Decode Error: premature end of int blob");
1343 if (*p == '-') {
1344 sign = -1;
1345 ++p;
1346 }
1347 for (; p < end; ++p) {
1348 const char& c = *p;
1349 if (c < '0' || c > '9')
1350 throw Exception("Decode Error: Invalid int blob format");
1351 i *= 10;
1352 i += size_t(c - '0');
1353 }
1354 return i * sign;
1355 }
1356
1357 template<typename T_int>
1358 static void _popIntBlob(const char*& p, const char* end, RawData& rawData) {
1359 const T_int i = _popIntBlob<T_int>(p, end);
1360 *(T_int*)&rawData[0] = i;
1361 }
1362
1363 template<typename T_real>
1364 static T_real _popRealBlob(const char*& p, const char* end) {
1365 _Blob blob = _decodeBlob(p, end);
1366 p = blob.p;
1367 end = blob.end;
1368
1369 if (p >= end || (end - p) < 1)
1370 throw Exception("Decode Error: premature end of real blob");
1371
1372 String s(p, size_t(end - p));
1373
1374 T_real r;
1375 if (sizeof(T_real) <= sizeof(double))
1376 r = atof(s.c_str());
1377 else
1378 assert(false /* unknown real type */);
1379
1380 p += s.length();
1381
1382 return r;
1383 }
1384
1385 template<typename T_real>
1386 static void _popRealBlob(const char*& p, const char* end, RawData& rawData) {
1387 const T_real r = _popRealBlob<T_real>(p, end);
1388 *(T_real*)&rawData[0] = r;
1389 }
1390
1391 static String _popStringBlob(const char*& p, const char* end) {
1392 _Blob blob = _decodeBlob(p, end);
1393 p = blob.p;
1394 end = blob.end;
1395 if (end - p < 0)
1396 throw Exception("Decode Error: missing String blob");
1397 String s;
1398 const size_t sz = end - p;
1399 s.resize(sz);
1400 memcpy(&s[0], p, sz);
1401 p += sz;
1402 return s;
1403 }
1404
1405 static time_t _popTimeBlob(const char*& p, const char* end) {
1406 const uint64_t i = _popIntBlob<uint64_t>(p, end);
1407 return (time_t) i;
1408 }
1409
1410 DataType _popDataTypeBlob(const char*& p, const char* end) {
1411 _Blob blob = _decodeBlob(p, end);
1412 p = blob.p;
1413 end = blob.end;
1414
1415 DataType type;
1416 type.m_baseTypeName = _popStringBlob(p, end);
1417 type.m_customTypeName = _popStringBlob(p, end);
1418 type.m_size = _popIntBlob<int>(p, end);
1419 type.m_isPointer = _popIntBlob<bool>(p, end);
1420 return type;
1421 }
1422
1423 static UID _popUIDBlob(const char*& p, const char* end) {
1424 _Blob blob = _decodeBlob(p, end);
1425 p = blob.p;
1426 end = blob.end;
1427
1428 if (p >= end)
1429 throw Exception("Decode Error: premature end of UID blob");
1430
1431 const ID id = (ID) _popIntBlob<size_t>(p, end);
1432 const size_t size = _popIntBlob<size_t>(p, end);
1433
1434 const UID uid = { id, size };
1435 return uid;
1436 }
1437
1438 static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
1439 _Blob blob = _decodeBlob(p, end);
1440 p = blob.p;
1441 end = blob.end;
1442
1443 UIDChain chain;
1444 while (p < end) {
1445 const UID uid = _popUIDBlob(p, end);
1446 chain.push_back(uid);
1447 }
1448 assert(!chain.empty());
1449 return chain;
1450 }
1451
1452 static Member _popMemberBlob(const char*& p, const char* end) {
1453 _Blob blob = _decodeBlob(p, end, false);
1454 p = blob.p;
1455 end = blob.end;
1456
1457 Member m;
1458 if (p >= end) return m;
1459
1460 m.m_uid = _popUIDBlob(p, end);
1461 m.m_offset = _popIntBlob<size_t>(p, end);
1462 m.m_name = _popStringBlob(p, end);
1463 m.m_type = _popDataTypeBlob(p, end);
1464 assert(m.type());
1465 assert(!m.name().empty());
1466 assert(m.uid().isValid());
1467 return m;
1468 }
1469
1470 static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
1471 _Blob blob = _decodeBlob(p, end, false);
1472 p = blob.p;
1473 end = blob.end;
1474
1475 std::vector<Member> members;
1476 while (p < end) {
1477 const Member member = _popMemberBlob(p, end);
1478 if (member)
1479 members.push_back(member);
1480 else
1481 break;
1482 }
1483 return members;
1484 }
1485
1486 static void _popPrimitiveValue(const char*& p, const char* end, Object& obj) {
1487 const DataType& type = obj.type();
1488 if (type.isPrimitive() && !type.isPointer()) {
1489 obj.m_data.resize(type.size());
1490 if (type.isInteger() || type.isEnum()) {
1491 if (type.isSigned()) {
1492 if (type.size() == 1)
1493 _popIntBlob<int8_t>(p, end, obj.m_data);
1494 else if (type.size() == 2)
1495 _popIntBlob<int16_t>(p, end, obj.m_data);
1496 else if (type.size() == 4)
1497 _popIntBlob<int32_t>(p, end, obj.m_data);
1498 else if (type.size() == 8)
1499 _popIntBlob<int64_t>(p, end, obj.m_data);
1500 else
1501 assert(false /* unknown signed int type size */);
1502 } else {
1503 if (type.size() == 1)
1504 _popIntBlob<uint8_t>(p, end, obj.m_data);
1505 else if (type.size() == 2)
1506 _popIntBlob<uint16_t>(p, end, obj.m_data);
1507 else if (type.size() == 4)
1508 _popIntBlob<uint32_t>(p, end, obj.m_data);
1509 else if (type.size() == 8)
1510 _popIntBlob<uint64_t>(p, end, obj.m_data);
1511 else
1512 assert(false /* unknown unsigned int type size */);
1513 }
1514 } else if (type.isReal()) {
1515 if (type.size() == sizeof(float))
1516 _popRealBlob<float>(p, end, obj.m_data);
1517 else if (type.size() == sizeof(double))
1518 _popRealBlob<double>(p, end, obj.m_data);
1519 else
1520 assert(false /* unknown floating point type */);
1521 } else if (type.isBool()) {
1522 _popIntBlob<uint8_t>(p, end, obj.m_data);
1523 } else {
1524 assert(false /* unknown primitive type */);
1525 }
1526
1527 } else {
1528 // don't whine if the empty blob was not added on encoder side
1529 _Blob blob = _decodeBlob(p, end, false);
1530 p = blob.p;
1531 end = blob.end;
1532 }
1533 }
1534
1535 static Object _popObjectBlob(const char*& p, const char* end) {
1536 _Blob blob = _decodeBlob(p, end, false);
1537 p = blob.p;
1538 end = blob.end;
1539
1540 Object obj;
1541 if (p >= end) return obj;
1542
1543 obj.m_type = _popDataTypeBlob(p, end);
1544 obj.m_version = _popIntBlob<Version>(p, end);
1545 obj.m_minVersion = _popIntBlob<Version>(p, end);
1546 obj.m_uid = _popUIDChainBlob(p, end);
1547 obj.m_members = _popMembersBlob(p, end);
1548 _popPrimitiveValue(p, end, obj);
1549 assert(obj.type());
1550 return obj;
1551 }
1552
1553 void Archive::_popObjectsBlob(const char*& p, const char* end) {
1554 _Blob blob = _decodeBlob(p, end, false);
1555 p = blob.p;
1556 end = blob.end;
1557
1558 if (p >= end)
1559 throw Exception("Decode Error: Premature end of objects blob");
1560
1561 while (true) {
1562 const Object obj = _popObjectBlob(p, end);
1563 if (!obj) break;
1564 m_allObjects[obj.uid()] = obj;
1565 }
1566 }
1567
1568 void Archive::_popRootBlob(const char*& p, const char* end) {
1569 _Blob blob = _decodeBlob(p, end, false);
1570 p = blob.p;
1571 end = blob.end;
1572
1573 if (p >= end)
1574 throw Exception("Decode Error: Premature end of root blob");
1575
1576 // just in case this encoding format will be extended in future
1577 // (currently not used)
1578 const int formatMinorVersion = _popIntBlob<int>(p, end);
1579
1580 m_root = _popUIDBlob(p, end);
1581 if (!m_root)
1582 throw Exception("Decode Error: No root object");
1583
1584 _popObjectsBlob(p, end);
1585 if (!m_allObjects[m_root])
1586 throw Exception("Decode Error: Missing declared root object");
1587
1588 m_name = _popStringBlob(p, end);
1589 m_comment = _popStringBlob(p, end);
1590 m_timeCreated = _popTimeBlob(p, end);
1591 m_timeModified = _popTimeBlob(p, end);
1592 }
1593
1594 /** @brief Fill this archive with the given serialized raw data.
1595 *
1596 * Calling this method will decode the given raw @a data and constructs a
1597 * (non-empty) Archive object according to that given serialized @a data
1598 * stream.
1599 *
1600 * After this method returned, you may then traverse the individual
1601 * objects by starting with accessing the rootObject() for example. Finally
1602 * you might call deserialize() to restore your native C++ objects with the
1603 * content of this archive.
1604 *
1605 * @param data - the previously serialized raw data stream to be decoded
1606 * @throws Exception if the provided raw @a data uses an invalid, unknown,
1607 * incompatible or corrupt data stream or format.
1608 */
1609 void Archive::decode(const RawData& data) {
1610 m_rawData = data;
1611 m_allObjects.clear();
1612 m_isModified = false;
1613 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1614 const char* p = (const char*) &data[0];
1615 const char* end = p + data.size();
1616 if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
1617 throw Exception("Decode Error: Magic start missing!");
1618 p += strlen(MAGIC_START);
1619 _popRootBlob(p, end);
1620 }
1621
1622 /** @brief Fill this archive with the given serialized raw C-buffer data.
1623 *
1624 * This method essentially works like the decode() method above, but just
1625 * uses another data type for the serialized raw data stream being passed to
1626 * this method.
1627 *
1628 * Calling this method will decode the given raw @a data and constructs a
1629 * (non-empty) Archive object according to that given serialized @a data
1630 * stream.
1631 *
1632 * After this method returned, you may then traverse the individual
1633 * objects by starting with accessing the rootObject() for example. Finally
1634 * you might call deserialize() to restore your native C++ objects with the
1635 * content of this archive.
1636 *
1637 * @param data - the previously serialized raw data stream to be decoded
1638 * @param size - size of @a data in bytes
1639 * @throws Exception if the provided raw @a data uses an invalid, unknown,
1640 * incompatible or corrupt data stream or format.
1641 */
1642 void Archive::decode(const uint8_t* data, size_t size) {
1643 RawData rawData;
1644 rawData.resize(size);
1645 memcpy(&rawData[0], data, size);
1646 decode(rawData);
1647 }
1648
1649 /** @brief Raw data stream of this archive content.
1650 *
1651 * Call this method to get a raw data stream for the current content of this
1652 * archive, which you may use to i.e. store on disk or send vie network to
1653 * another machine for deserializing there. This method only returns a
1654 * meaningful content if this is a non-empty archive, that is if you either
1655 * serialized with this Archive object or decoded a raw data stream to this
1656 * Archive object before. If this is an empty archive instead, then this
1657 * method simply returns an empty raw data stream (of size 0) instead.
1658 *
1659 * Note that whenever you call this method, the "modified" state of this
1660 * archive will be reset to @c false.
1661 *
1662 * @see isModified()
1663 */
1664 const RawData& Archive::rawData() {
1665 if (m_isModified) encode();
1666 return m_rawData;
1667 }
1668
1669 /** @brief Name of the encoding format used by this Archive class.
1670 *
1671 * This method returns the name of the encoding format used to encode
1672 * serialized raw data streams.
1673 */
1674 String Archive::rawDataFormat() const {
1675 return MAGIC_START;
1676 }
1677
1678 /** @brief Whether this archive was modified.
1679 *
1680 * This method returns the current "modified" state of this archive. When
1681 * either decoding a previously serialized raw data stream or after
1682 * serializing native C++ objects to this archive the modified state will
1683 * initially be set to @c false. However whenever you are modifying the
1684 * abstract data model of this archive afterwards, for example by removing
1685 * objects from this archive by calling remove() or removeMember(), or by
1686 * altering object values for example by calling setIntValue(), then the
1687 * "modified" state of this archive will automatically be set to @c true.
1688 *
1689 * You can reset the "modified" state explicitly at any time, by calling
1690 * rawData().
1691 */
1692 bool Archive::isModified() const {
1693 return m_isModified;
1694 }
1695
1696 /** @brief Clear content of this archive.
1697 *
1698 * Drops the entire content of this archive and thus resets this archive
1699 * back to become an empty archive.
1700 */
1701 void Archive::clear() {
1702 m_allObjects.clear();
1703 m_operation = OPERATION_NONE;
1704 m_root = NO_UID;
1705 m_rawData.clear();
1706 m_isModified = false;
1707 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1708 }
1709
1710 /** @brief Optional name of this archive.
1711 *
1712 * Returns the optional name of this archive that you might have assigned
1713 * to this archive before by calling setName(). If you haven't assigned any
1714 * name to this archive before, then this method simply returns an empty
1715 * string instead.
1716 */
1717 String Archive::name() const {
1718 return m_name;
1719 }
1720
1721 /** @brief Assign a name to this archive.
1722 *
1723 * You may optionally assign an arbitrary name to this archive. The name
1724 * will be stored along with the archive, that is it will encoded with the
1725 * resulting raw data stream, and accordingly it will be decoded from the
1726 * raw data stream later on.
1727 *
1728 * @param name - arbitrary new name for this archive
1729 */
1730 void Archive::setName(String name) {
1731 if (m_name == name) return;
1732 m_name = name;
1733 m_isModified = true;
1734 }
1735
1736 /** @brief Optional comments for this archive.
1737 *
1738 * Returns the optional comments for this archive that you might have
1739 * assigned to this archive before by calling setComment(). If you haven't
1740 * assigned any comment to this archive before, then this method simply
1741 * returns an empty string instead.
1742 */
1743 String Archive::comment() const {
1744 return m_comment;
1745 }
1746
1747 /** @brief Assign a comment to this archive.
1748 *
1749 * You may optionally assign arbitrary comments to this archive. The comment
1750 * will be stored along with the archive, that is it will encoded with the
1751 * resulting raw data stream, and accordingly it will be decoded from the
1752 * raw data stream later on.
1753 *
1754 * @param comment - arbitrary new comment for this archive
1755 */
1756 void Archive::setComment(String comment) {
1757 if (m_comment == comment) return;
1758 m_comment = comment;
1759 m_isModified = true;
1760 }
1761
1762 static tm _convertTimeStamp(const time_t& time, time_base_t base) {
1763 tm* pTm;
1764 switch (base) {
1765 case LOCAL_TIME:
1766 pTm = localtime(&time);
1767 break;
1768 case UTC_TIME:
1769 pTm = gmtime(&time);
1770 break;
1771 default:
1772 throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
1773 }
1774 if (!pTm)
1775 throw Exception("Failed assembling time stamp structure");
1776 return *pTm;
1777 }
1778
1779 /** @brief Date and time when this archive was initially created.
1780 *
1781 * Returns a UTC time stamp (date and time) when this archive was initially
1782 * created.
1783 */
1784 time_t Archive::timeStampCreated() const {
1785 return m_timeCreated;
1786 }
1787
1788 /** @brief Date and time when this archive was modified for the last time.
1789 *
1790 * Returns a UTC time stamp (date and time) when this archive was modified
1791 * for the last time.
1792 */
1793 time_t Archive::timeStampModified() const {
1794 return m_timeModified;
1795 }
1796
1797 /** @brief Date and time when this archive was initially created.
1798 *
1799 * Returns a calendar time information representing the date and time when
1800 * this archive was initially created. The optional @a base parameter may
1801 * be used to define to which time zone the returned data and time shall be
1802 * related to.
1803 *
1804 * @param base - (optional) time zone the result shall relate to, by default
1805 * UTC time (Greenwhich Mean Time) is assumed instead
1806 */
1807 tm Archive::dateTimeCreated(time_base_t base) const {
1808 return _convertTimeStamp(m_timeCreated, base);
1809 }
1810
1811 /** @brief Date and time when this archive was modified for the last time.
1812 *
1813 * Returns a calendar time information representing the date and time when
1814 * this archive has been modified for the last time. The optional @a base
1815 * parameter may be used to define to which time zone the returned date and
1816 * time shall be related to.
1817 *
1818 * @param base - (optional) time zone the result shall relate to, by default
1819 * UTC time (Greenwhich Mean Time) is assumed instead
1820 */
1821 tm Archive::dateTimeModified(time_base_t base) const {
1822 return _convertTimeStamp(m_timeModified, base);
1823 }
1824
1825 /** @brief Remove a member variable from the given object.
1826 *
1827 * Removes the member variable @a member from its containing object
1828 * @a parent and sets the modified state of this archive to @c true.
1829 * If the given @a parent object does not contain the given @a member then
1830 * this method does nothing.
1831 *
1832 * This method provides a means of "partial" deserialization. By removing
1833 * either objects or members from this archive before calling deserialize(),
1834 * only the remaining objects and remaining members will be restored by this
1835 * framework, all other data of your C++ classes remain untouched.
1836 *
1837 * @param parent - Object which contains @a member
1838 * @param member - member to be removed
1839 * @see isModified() for details about the modified state.
1840 * @see Object for more details about the overall object reflection concept.
1841 */
1842 void Archive::removeMember(Object& parent, const Member& member) {
1843 parent.remove(member);
1844 m_isModified = true;
1845 }
1846
1847 /** @brief Remove an object from this archive.
1848 *
1849 * Removes the object @obj from this archive and sets the modified state of
1850 * this archive to @c true. If the passed object is either invalid, or does
1851 * not exist in this archive, then this method does nothing.
1852 *
1853 * This method provides a means of "partial" deserialization. By removing
1854 * either objects or members from this archive before calling deserialize(),
1855 * only the remaining objects and remaining members will be restored by this
1856 * framework, all other data of your C++ classes remain untouched.
1857 *
1858 * @param obj - the object to be removed from this archive
1859 * @see isModified() for details about the modified state.
1860 * @see Object for more details about the overall object reflection concept.
1861 */
1862 void Archive::remove(const Object& obj) {
1863 //FIXME: Should traverse from root object and remove all members associated with this object
1864 if (!obj.uid()) return;
1865 m_allObjects.erase(obj.uid());
1866 m_isModified = true;
1867 }
1868
1869 /** @brief Access object by its unique identifier.
1870 *
1871 * Returns the object of this archive with the given unique identifier
1872 * @a uid. If the given @a uid is invalid, or if this archive does not
1873 * contain an object with the given unique identifier, then this method
1874 * returns an invalid object instead.
1875 *
1876 * @param uid - unique identifier of sought object
1877 * @see Object for more details about the overall object reflection concept.
1878 * @see Object::isValid() for valid/invalid objects
1879 */
1880 Object& Archive::objectByUID(const UID& uid) {
1881 return m_allObjects[uid];
1882 }
1883
1884 /** @brief Set the current version for the given object.
1885 *
1886 * Essentially behaves like above's setVersion() method, it just uses the
1887 * abstract reflection data type instead for the respective @a object being
1888 * passed to this method. Refer to above's setVersion() documentation about
1889 * the precise behavior details of setVersion().
1890 *
1891 * @param object - object to set the current version for
1892 * @param v - new current version to set for @a object
1893 */
1894 void Archive::setVersion(Object& object, Version v) {
1895 if (!object) return;
1896 object.setVersion(v);
1897 m_isModified = true;
1898 }
1899
1900 /** @brief Set the minimum version for the given object.
1901 *
1902 * Essentially behaves like above's setMinVersion() method, it just uses the
1903 * abstract reflection data type instead for the respective @a object being
1904 * passed to this method. Refer to above's setMinVersion() documentation
1905 * about the precise behavior details of setMinVersion().
1906 *
1907 * @param object - object to set the minimum version for
1908 * @param v - new minimum version to set for @a object
1909 */
1910 void Archive::setMinVersion(Object& object, Version v) {
1911 if (!object) return;
1912 object.setMinVersion(v);
1913 m_isModified = true;
1914 }
1915
1916 /** @brief Set new value for given @c enum object.
1917 *
1918 * Sets the new @a value to the given @c enum @a object.
1919 *
1920 * @param object - the @c enum object to be changed
1921 * @param value - the new value to be assigned to the @a object
1922 * @throws Exception if @a object is not an @c enum type.
1923 */
1924 void Archive::setEnumValue(Object& object, uint64_t value) {
1925 if (!object) return;
1926 if (!object.type().isEnum())
1927 throw Exception("Not an enum data type");
1928 Object* pObject = &object;
1929 if (object.type().isPointer()) {
1930 Object& obj = objectByUID(object.uid(1));
1931 if (!obj) return;
1932 pObject = &obj;
1933 }
1934 const int nativeEnumSize = sizeof(enum operation_t);
1935 DataType& type = const_cast<DataType&>( pObject->type() );
1936 // original serializer ("sender") might have had a different word size
1937 // than this machine, adjust type object in this case
1938 if (type.size() != nativeEnumSize) {
1939 type.m_size = nativeEnumSize;
1940 }
1941 pObject->m_data.resize(type.size());
1942 void* ptr = &pObject->m_data[0];
1943 if (type.size() == 1)
1944 *(uint8_t*)ptr = (uint8_t)value;
1945 else if (type.size() == 2)
1946 *(uint16_t*)ptr = (uint16_t)value;
1947 else if (type.size() == 4)
1948 *(uint32_t*)ptr = (uint32_t)value;
1949 else if (type.size() == 8)
1950 *(uint64_t*)ptr = (uint64_t)value;
1951 else
1952 assert(false /* unknown enum type size */);
1953 m_isModified = true;
1954 }
1955
1956 /** @brief Set new integer value for given integer object.
1957 *
1958 * Sets the new integer @a value to the given integer @a object. Currently
1959 * this framework handles any integer data type up to 64 bit. For larger
1960 * integer types an assertion failure will be raised.
1961 *
1962 * @param object - the integer object to be changed
1963 * @param value - the new value to be assigned to the @a object
1964 * @throws Exception if @a object is not an integer type.
1965 */
1966 void Archive::setIntValue(Object& object, int64_t value) {
1967 if (!object) return;
1968 if (!object.type().isInteger())
1969 throw Exception("Not an integer data type");
1970 Object* pObject = &object;
1971 if (object.type().isPointer()) {
1972 Object& obj = objectByUID(object.uid(1));
1973 if (!obj) return;
1974 pObject = &obj;
1975 }
1976 const DataType& type = pObject->type();
1977 pObject->m_data.resize(type.size());
1978 void* ptr = &pObject->m_data[0];
1979 if (type.isSigned()) {
1980 if (type.size() == 1)
1981 *(int8_t*)ptr = (int8_t)value;
1982 else if (type.size() == 2)
1983 *(int16_t*)ptr = (int16_t)value;
1984 else if (type.size() == 4)
1985 *(int32_t*)ptr = (int32_t)value;
1986 else if (type.size() == 8)
1987 *(int64_t*)ptr = (int64_t)value;
1988 else
1989 assert(false /* unknown signed int type size */);
1990 } else {
1991 if (type.size() == 1)
1992 *(uint8_t*)ptr = (uint8_t)value;
1993 else if (type.size() == 2)
1994 *(uint16_t*)ptr = (uint16_t)value;
1995 else if (type.size() == 4)
1996 *(uint32_t*)ptr = (uint32_t)value;
1997 else if (type.size() == 8)
1998 *(uint64_t*)ptr = (uint64_t)value;
1999 else
2000 assert(false /* unknown unsigned int type size */);
2001 }
2002 m_isModified = true;
2003 }
2004
2005 /** @brief Set new floating point value for given floating point object.
2006 *
2007 * Sets the new floating point @a value to the given floating point
2008 * @a object. Currently this framework supports single precision @c float
2009 * and double precision @c double floating point data types. For all other
2010 * floating point types this method will raise an assertion failure.
2011 *
2012 * @param object - the floating point object to be changed
2013 * @param value - the new value to be assigned to the @a object
2014 * @throws Exception if @a object is not a floating point based type.
2015 */
2016 void Archive::setRealValue(Object& object, double value) {
2017 if (!object) return;
2018 if (!object.type().isReal())
2019 throw Exception("Not a real data type");
2020 Object* pObject = &object;
2021 if (object.type().isPointer()) {
2022 Object& obj = objectByUID(object.uid(1));
2023 if (!obj) return;
2024 pObject = &obj;
2025 }
2026 const DataType& type = pObject->type();
2027 pObject->m_data.resize(type.size());
2028 void* ptr = &pObject->m_data[0];
2029 if (type.size() == sizeof(float))
2030 *(float*)ptr = (float)value;
2031 else if (type.size() == sizeof(double))
2032 *(double*)ptr = (double)value;
2033 else
2034 assert(false /* unknown real type size */);
2035 m_isModified = true;
2036 }
2037
2038 /** @brief Set new boolean value for given boolean object.
2039 *
2040 * Sets the new boolean @a value to the given boolean @a object.
2041 *
2042 * @param object - the boolean object to be changed
2043 * @param value - the new value to be assigned to the @a object
2044 * @throws Exception if @a object is not a boolean type.
2045 */
2046 void Archive::setBoolValue(Object& object, bool value) {
2047 if (!object) return;
2048 if (!object.type().isBool())
2049 throw Exception("Not a bool data type");
2050 Object* pObject = &object;
2051 if (object.type().isPointer()) {
2052 Object& obj = objectByUID(object.uid(1));
2053 if (!obj) return;
2054 pObject = &obj;
2055 }
2056 const DataType& type = pObject->type();
2057 pObject->m_data.resize(type.size());
2058 bool* ptr = (bool*)&pObject->m_data[0];
2059 *ptr = value;
2060 m_isModified = true;
2061 }
2062
2063 /** @brief Automatically cast and assign appropriate value to object.
2064 *
2065 * This method automatically converts the given @a value from textual string
2066 * representation into the appropriate data format of the requested
2067 * @a object. So this method is a convenient way to change values of objects
2068 * in this archive with your applications in automated way, i.e. for
2069 * implementing an editor where the user is able to edit values of objects
2070 * in this archive by entering the values as text with a keyboard.
2071 *
2072 * @throws Exception if the passed @a object is not a fundamental, primitive
2073 * data type or if the provided textual value cannot be converted
2074 * into an appropriate value for the requested object.
2075 */
2076 void Archive::setAutoValue(Object& object, String value) {
2077 if (!object) return;
2078 const DataType& type = object.type();
2079 if (type.isInteger())
2080 setIntValue(object, atoll(value.c_str()));
2081 else if (type.isReal())
2082 setRealValue(object, atof(value.c_str()));
2083 else if (type.isBool())
2084 setBoolValue(object, atof(value.c_str()));
2085 else if (type.isEnum())
2086 setEnumValue(object, atoll(value.c_str()));
2087 else
2088 throw Exception("Not a primitive data type");
2089 }
2090
2091 /** @brief Get value of object as string.
2092 *
2093 * Converts the current value of the given @a object into a textual string
2094 * and returns that string.
2095 *
2096 * @param object - object whose value shall be retrieved
2097 * @throws Exception if the given object is either invalid, or if the object
2098 * is not a fundamental, primitive data type.
2099 */
2100 String Archive::valueAsString(const Object& object) {
2101 if (!object)
2102 throw Exception("Invalid object");
2103 if (object.type().isClass())
2104 throw Exception("Object is class type");
2105 const Object* pObject = &object;
2106 if (object.type().isPointer()) {
2107 const Object& obj = objectByUID(object.uid(1));
2108 if (!obj) return "";
2109 pObject = &obj;
2110 }
2111 return _primitiveObjectValueToString(*pObject);
2112 }
2113
2114 /** @brief Get integer value of object.
2115 *
2116 * Returns the current integer value of the requested integer @a object or
2117 * @c enum object.
2118 *
2119 * @param object - object whose value shall be retrieved
2120 * @throws Exception if the given object is either invalid, or if the object
2121 * is neither an integer nor @c enum data type.
2122 */
2123 int64_t Archive::valueAsInt(const Object& object) {
2124 if (!object)
2125 throw Exception("Invalid object");
2126 if (!object.type().isInteger() && !object.type().isEnum())
2127 throw Exception("Object is neither an integer nor an enum");
2128 const Object* pObject = &object;
2129 if (object.type().isPointer()) {
2130 const Object& obj = objectByUID(object.uid(1));
2131 if (!obj) return 0;
2132 pObject = &obj;
2133 }
2134 return _primitiveObjectValueToNumber<int64_t>(*pObject);
2135 }
2136
2137 /** @brief Get floating point value of object.
2138 *
2139 * Returns the current floating point value of the requested floating point
2140 * @a object.
2141 *
2142 * @param object - object whose value shall be retrieved
2143 * @throws Exception if the given object is either invalid, or if the object
2144 * is not a floating point based type.
2145 */
2146 double Archive::valueAsReal(const Object& object) {
2147 if (!object)
2148 throw Exception("Invalid object");
2149 if (!object.type().isReal())
2150 throw Exception("Object is not an real type");
2151 const Object* pObject = &object;
2152 if (object.type().isPointer()) {
2153 const Object& obj = objectByUID(object.uid(1));
2154 if (!obj) return 0;
2155 pObject = &obj;
2156 }
2157 return _primitiveObjectValueToNumber<double>(*pObject);
2158 }
2159
2160 /** @brief Get boolean value of object.
2161 *
2162 * Returns the current boolean value of the requested boolean @a object.
2163 *
2164 * @param object - object whose value shall be retrieved
2165 * @throws Exception if the given object is either invalid, or if the object
2166 * is not a boolean data type.
2167 */
2168 bool Archive::valueAsBool(const Object& object) {
2169 if (!object)
2170 throw Exception("Invalid object");
2171 if (!object.type().isBool())
2172 throw Exception("Object is not a bool");
2173 const Object* pObject = &object;
2174 if (object.type().isPointer()) {
2175 const Object& obj = objectByUID(object.uid(1));
2176 if (!obj) return 0;
2177 pObject = &obj;
2178 }
2179 return _primitiveObjectValueToNumber<bool>(*pObject);
2180 }
2181
2182 // *************** Archive::Syncer ***************
2183 // *
2184
2185 Archive::Syncer::Syncer(Archive& dst, Archive& src)
2186 : m_dst(dst), m_src(src)
2187 {
2188 const Object srcRootObj = src.rootObject();
2189 const Object dstRootObj = dst.rootObject();
2190 if (!srcRootObj)
2191 throw Exception("No source root object!");
2192 if (!dstRootObj)
2193 throw Exception("Expected destination root object not found!");
2194 syncObject(dstRootObj, srcRootObj);
2195 }
2196
2197 void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
2198 assert(srcObj.rawData().size() == dstObj.type().size());
2199 void* pDst = (void*)dstObj.uid().id;
2200 memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2201 }
2202
2203 void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2204 assert(dstObj.type().isPointer());
2205 assert(dstObj.type() == srcObj.type());
2206 const Object& pointedDstObject = m_dst.m_allObjects[dstObj.uid(1)];
2207 const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2208 syncObject(pointedDstObject, pointedSrcObject);
2209 }
2210
2211 void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
2212 if (!dstObj || !srcObj) return; // end of recursion
2213 if (!dstObj.isVersionCompatibleTo(srcObj))
2214 throw Exception("Version incompatible (destination version " +
2215 ToString(dstObj.version()) + " [min. version " +
2216 ToString(dstObj.minVersion()) + "], source version " +
2217 ToString(srcObj.version()) + " [min. version " +
2218 ToString(srcObj.minVersion()) + "])");
2219 if (dstObj.type() != srcObj.type())
2220 throw Exception("Incompatible data structure type (destination type " +
2221 dstObj.type().asLongDescr() + " vs. source type " +
2222 srcObj.type().asLongDescr() + ")");
2223
2224 // prevent syncing this object again, and thus also prevent endless
2225 // loop on data structures with cyclic relations
2226 m_dst.m_allObjects.erase(dstObj.uid());
2227
2228 if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2229 syncPrimitive(dstObj, srcObj);
2230 return; // end of recursion
2231 }
2232
2233 if (dstObj.type().isPointer()) {
2234 syncPointer(dstObj, srcObj);
2235 return;
2236 }
2237
2238 assert(dstObj.type().isClass());
2239 for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2240 const Member& srcMember = srcObj.members()[iMember];
2241 Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2242 if (!dstMember)
2243 throw Exception("Expected member missing in destination object");
2244 syncMember(dstMember, srcMember);
2245 }
2246 }
2247
2248 Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
2249 Member dstMember = dstObj.memberNamed(srcMember.name());
2250 if (dstMember)
2251 return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2252 std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2253 if (members.size() <= 0)
2254 return Member();
2255 if (members.size() == 1)
2256 return members[0];
2257 for (int i = 0; i < members.size(); ++i)
2258 if (members[i].offset() == srcMember.offset())
2259 return members[i];
2260 const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2261 assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
2262 for (int i = 0; i < members.size(); ++i) {
2263 const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2264 if (dstSeqNr == srcSeqNr)
2265 return members[i];
2266 }
2267 return Member(); // give up!
2268 }
2269
2270 void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
2271 assert(dstMember && srcMember);
2272 assert(dstMember.type() == srcMember.type());
2273 const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2274 const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2275 syncObject(dstObj, srcObj);
2276 }
2277
2278 // *************** Exception ***************
2279 // *
2280
2281 /** @brief Print exception message to stdout.
2282 *
2283 * Prints the message of this Exception to the currently defined standard
2284 * output (that is to the terminal console for example).
2285 */
2286 void Exception::PrintMessage() {
2287 std::cout << "Serialization::Exception: " << Message << std::endl;
2288 }
2289
2290 } // namespace Serialization

  ViewVC Help
Powered by ViewVC