Spinning Topp Logo BlackTopp Studios
inc
serialization.h
Go to the documentation of this file.
1 // © Copyright 2010 - 2016 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _serialization_h
41 #define _serialization_h
42 
43 /// @file
44 /// @brief The interface for serialization
45 
46 #include "datatypes.h"
47 #include "countedptr.h"
48 #ifndef SWIG
49  #include "XML/xml.h"
50 #endif
51 
52 namespace Mezzanine
53 {
54  /// @page Serialization
55  /// @section SerializationMain
56  /// Serialization is the process of converting a class instance into a serial sequence of bits. DeSerialization is taking those
57  /// bits and reconstructing the original object without losing anything of value (in theory the only things not saved are cached
58  /// values or values calulated as they are needed). These bits could be just about anything, because of its ubiquity we chose
59  /// to serialize to xml (or something so similar as to be indistinguishable from standard xml). This allows a wide variety of tools
60  /// to be used when working with and verifying these serialized classes. Additionally, transmitting and storing xml is easy to do,
61  /// and can be done with a variety of other factors in mind. The xml text can be sent down any stream, put in any file, compressed,
62  /// queried. You should see @ref XMLManual for information about the xml system itself.
63  /// \n \n
64  /// Topics:
65  /// - @ref serializationxml
66  /// - @ref serializationintegration
67  /// - @ref serializationmaking
68  /// - @ref serializationserializers
69  /// - @ref serializationlegacy
70  /// - @ref serializationoperators
71  /// - @ref serializationmisc
72  /// @subsection serializationxml Serialization and XML
73  /// The process of serializing doesn't just convert from class instance to text. Since our end goal is to convert live objects to
74  /// XML it makes sense to closely integrate the Mezzanine::xml portion of the engine. If you plan on writing serialization
75  /// and deserialization code you should read the following parts of the @ref XMLManual at a minimum:
76  /// - @ref XMLDOM
77  /// - @ref XMLAccessingBasics
78  /// - @ref XMLModifyingNodeData
79  /// - @ref XMLModifyingAttributeData
80  ///
81  /// The central object that will carry information during this process is the Mezzanine::XML::Node. The Mezzanine::XML::Node is an excellent
82  /// tool for converting and storing data in a single unified heirarchy.
83  /// \n \n
84  /// C++ and most other object oriented languages heavily imply that class inheritance should be structured as hierarchies. Additionally
85  /// Hierarchies are implied when complex class has other complex classes or datatypes as members. Both of these structures map
86  /// cleanly onto the kind of hierarchies that a well formed xml documents provide.
87  /// \n \n
88  /// There are some relationships in video game objects that cross normal hierarchical boundaries. For example, A constraint
89  /// references two actors, and defines a relationship between them. When serialized the constraint simply stores the name of
90  /// the actor and looks it up in the actor manager during deserialization. This implies that the actors exist already, or that
91  /// there is some mechanism to create the constraint and fill in the actor later. Several mechanisms were discussed to
92  /// accomplish this, some include: two passes of processing where constraint would be done in the second pass, a work queue that
93  /// would store objects that couldn't be deserialized yet, a prefetcher that would dig through the xml to find the required
94  /// object.
95  /// \n \n
96  /// Those methods all likely could have been made to work. However, they are not optimal for a variety of reasons. All of them
97  /// have a set of preconditions and require more computing resources and could potentially delay loading or transmission times.
98  /// Some of them heavily imply that all of the items to deserialize must be stored in the same xml source. Some demand access to
99  /// xml that may not have been transmitted yet.
100  /// \n \n
101  /// The simplest, most performant way to work around the issues that cross-hierarchical relationships presented was to ignore
102  /// them. More specifically, throw an exception if an object reference during deserialization is not present. Then we ask that
103  /// programmers who write code that must store, transmit and reconstruct class instances be aware of the following preconditions
104  /// So can produce their own solutions:
105  /// - CollisionShapes must come before Actors and AreaEffects
106  /// - WorldNodes must come before Actors, Light and ParticleEffects. (this is still work in progress).
107  /// - Currently WorldNodes try to find the objects that are attached to them, and the attached tries to find the world node. (if one does not exist, this silently fails)
108  /// - Actors must come before constraints.
109  /// - Actors may have a WorldNode inside them, if this is the case, then the actor must come before Lights and ParticleEffects Attached to it.
110  /// - Actors must be done before SoundSets
111  /// - Sounds must be done before SoundSet (Still in progress)
112  ///
113  /// The easyiest way to meet these conditions and not consume an inordinate amount of computing resources, is to pay attention
114  /// to the order that items are serialized in. If a program serializes the worldnodes, then the actors, then everything else
115  /// it will have relatively little trouble making it work.
116  /// @subsection serializationintegration Integrate Serialization into Your Code
117  /// There several ways to interact with the current serialization system. One might have to create a class that can be
118  /// serialized or deserialized. There may be situations where another system is emitting xml and it must be intergrated into
119  /// an existing game. It may be desired to create a 'factory' that produces objects from and xml source or create a sink to put
120  /// objects into so they can be serialized. Here we will discuss some of the ways that the serialization system can be extended
121  /// and what kind of assumptions it makes, so that anyone can write software that interacts with it cleanly.
122  /// @subsubsection serializationmaking Make a Serializable or a DeSerializable
123  /// Creating a class that be serialized is easy. There is just one function that it must implement. If a class implements this,
124  /// it is said to be Serializable:
125  /// @code
126  /// void SerializableClass::ProtoSerialize(XML::Node&) const;
127  /// @endcode
128  /// The member ProtoSerialize(XML::Node&) is expected to accept a Mezzanine::XML::Node and attach exactly one Node to it. This new Serialized
129  /// node should contain all the data stored in the current state of the object being serialized. Storing data outside of this
130  /// one node could cause undefined behavior.
131  /// \n \n
132  /// The exact layout of the data in the Serialized Node is not pre-determined. The creator of that function need only
133  /// take into account any difficulties DeSerializing when creating this. Because of this concern it is advisable name the Serialized
134  /// node something unique and appropriate and to include a 'Version' attribute on it. If the class
135  /// changes, the DeSerialization function will only need to check the 'Version' attribute to know if and how it can handle it.
136  /// \n \n
137  /// Integrating with the DeSerialization code is pretty easy too. There are two functions you are expected to implement to
138  /// create a DeSerializable:
139  /// @code
140  /// void DeSerializableClass::ProtoDeSerialize(const XML::Node&);
141  /// static String DeSerializableClass::GetSerializableName();
142  /// @endcode
143  /// The GetSerializableName() is expected to simply return the name of the xml elements this class will DeSerialize. For example
144  /// A Mezzanine::Vector3 returns "Vector3", and a Mezzanine::ActorRigid return "ActorRigid". If a class is both DeSerializable and
145  /// serializable it makes sense to call this function when assigning the name to the Serialized Node it creates.
146  /// \n \n
147  /// ProtoDeSerialize(const XML::Node&), accepts a Mezzanine::XML::Node. The Node passed to it would correspond to the Serialized
148  /// Node created by the ProtoSerialize(XML::Node&) function listed above. If xml is created by something then this is calling
149  /// code is expecting this function to be the correct deserialization function. It is advisable but not required to verify the
150  /// name of the xml node matches what is expected and that
151  /// the 'Version' is something this code can handle. It is also advisable that every piece of data pulled out is verified the
152  /// best it can be. If exceptions are thrown for every discrepency, then programmers using this will create xml and code that
153  /// produce no discrepencies.
154  /// \n \n
155  /// The following template make use of only the 3 functions described above to Serialize or DeSerialize class instances:
156  /// @code
157  /// template <class T> std::ostream& Serialize(std::ostream& Stream, const T& Converted, const String& Indent = String("") );
158  /// template <class T> std::istream& DeSerialize(std::istream& Stream, T& Converted);
159  /// @endcode
160  /// The functions make calls on the Mezzanine::xml system and expect a fairly basic set of conditions to be met before they are used.
161  /// Serialize accepts an output stream and the class instance to be Serialized. It will create an XML::Document and populate it
162  /// data from the class provided and then emit that into the stream. DeSerialize accepts an inputstream and the object to be
163  /// populated. It expects the next xml element in the stream to be a serialized version of the passed object and will then
164  /// overwrite as many of the values of the passed object as possible with the serialized values. For small items DeSerialize
165  /// is fine, where possible it is better to have the XML::Document open the file or stream itself as to prevent the second
166  /// pass through to find exactly one xml element.
167  /// \n \n
168  /// @subsubsection serializationserializers Working with Serializers and Deserializers
169  /// In some cases, there are some pieces of information that cannot be supplied or
170  /// entered by the class itself. This data must be provided by another class or upon creation of the class. This other class
171  /// can implement the Serializer, DeSerializer, or both interfaces to make working with large amounts of serialization easier.
172  /// \n \n
173  /// For example EntityProxy can only accept a mesh upon construction. So overwriting an existing EntityProxy is impossible to do completely.
174  /// It expected to be partially implemented, to the extent possible, in the class members. But if you have the need to create
175  /// EntityProxys on the fly from data stored in files it makes sense to have a dedicated class or interface than can create these.
176  /// Here is what goes into a Serializer:
177  /// @code
178  /// template <class Serializable> class Serializer
179  /// {
180  /// virtual void Serializer::ProtoSerializeAll(XML::Node& CurrentRoot) const = 0;
181  /// virtual std::ostream& Serializer::SerializeAll(std::ostream& Stream) const;
182  /// virtual void Serializer::ProtoSerialize(const Serializable& Target, XML::Node& CurrentRoot) = 0;
183  /// virtual std::ostream& Serializer::Serialize(std::ostream& Stream, const Serializable& Target)
184  /// };
185  /// @endcode
186  /// Serializer::ProtoSerialize() when implement should take the required steps to attach a Serialized Node to the
187  /// Passed XML::Node that represent the Serialization target. It is expected to get the extra information that the target
188  /// cannot provide from somewhere else. Ideally the the Serializer can be, or be associated with, a manager or container
189  /// of some kind. There is not default implementation of this.
190  /// \n \n
191  /// Serializer::Serialize() Goes one step further than Serializer::ProtoSerialize() and also sends it down a stream. The
192  /// default implements use Serializer::ProtoSerialize().
193  /// \n \n
194  /// Serializer::ProtoSerializeAll() performs a similar role to Serializer::ProtoSerialize(), but again, it goes one step
195  /// further. Rather than accept a single Target to serialize it is expected that the Serializer go to the source of the
196  /// Targets and serialize all of them that are available. All of the target should be contained in one Node attached to
197  /// the Node the function accepts. This is not implemented by default, the logic is too specific to the items to be
198  /// serialized.
199  /// \n \n
200  /// Serializer::SerializeAll() uses Serializer::ProtoSerializeAll() to send all of the available Targets in Serialized
201  /// down a stream.
202  /// \n \n
203  /// The logic behind a DeSerializer is similar to a Serializer. The same types of methods, even similar implementations
204  /// if the function is implemented. Like the ProtoDeSerialize() individual DeSerializables implement, the functions on
205  /// a DeSerializer will be passed the nodes that would correspond to the those created by their counterparts on the
206  /// Serializer. Here is the contents of a Deserializer:
207  /// @code
208  /// template <class DeSerializable> class DeSerializer
209  /// {
210  /// virtual void DeSerializer::ProtoDeSerializeAll(const XML::Node& OneNode) = 0;
211  /// virtual std::istream& DeSerializer::DeSerializeAll(std::istream& Stream)
212  /// virtual DeSerializable* DeSerializer::ProtoDeSerialize(const XML::Node& OneNode) = 0;
213  /// virtual std::istream& DeSerializer::DeSerialize(std::istream& Stream)
214  /// virtual String ContainerName() const = 0;
215  /// };
216  /// @endcode
217  /// The function ContainerName() should be used when creating and verifying the xml element that is parent to the items
218  /// DeSerialized by ProtoDeSerializeAll(). The Default implmentation of DeSerializeAll() will use ContainerName to
219  /// verify it has extracted the correct Node.
220  /// \n \n
221  /// There is no technical reason why a class cannot be both a serializer and a deserializer, or even multiple kinds of
222  /// Serializers or DeSerializers. To keep things simple the Managers provided by the Mezzanine engine will store a pointer
223  /// to the appropriate Serializer when one is required.
224  /// @subsubsection serializationlegacy Integrating with External XML Providers
225  /// Sometimes yu will be forced to work with a system that produces xml that is not structured in a similar way to this
226  /// system. Sometimes it may be too costly or not possible to modify the code to integrate it. For these the following
227  /// function exists:
228  /// @code
229  /// template <class T> void SloppyProtoSerialize(const T& Converted, XML::Node& CurrentRoot)
230  /// @endcode
231  /// This function will make a call on the the stream insertion operator of the class passed in. If one doesn't exist
232  /// it is easy to add one in your code without chaning the original source. If one does exist than you should probably
233  /// copy/paste the whole function and re-implement it calling the functions that emit the XML string or stream. If you
234  /// want to implement a stream insertion operator, the function prototype should be similar to the stream insertion
235  /// operator in the @ref serializationoperators section.
236  /// @subsection serializationoperators Serialization Operators
237  /// The stream insertion (<<) and stream extraction (>>) operators can be used for serializing and deserializing most items
238  /// in the Mezzanine engine.
239  ///
240  /// Unfortunately due to conflict with the stream insertion operators provided with the iostreams library these couldn't be
241  /// made into a template. That doesn't mean that they are difficult to implement. Here is a typical implemenation of stream
242  /// insertion operators for XML serialization:
243  /// @code
244  /// std::ostream& operator << (std::ostream& stream, const Mezzanine::RigidDebris& DebrisToSerialize)
245  /// {
246  /// Serialize(stream, DebrisToSerialize);
247  /// return stream;
248  /// }
249  ///
250  /// std::istream& operator >> (std::istream& stream, Mezzanine::RigidDebris& x)
251  /// { return DeSerialize(stream, x); }
252  ///
253  /// void operator >> (const Mezzanine::XML::Node& OneNode, Mezzanine::RigidDebris& x)
254  /// { x.ProtoDeSerialize(OneNode); }
255  ///
256  /// @endcode
257  /// You will want to implement these functions with the appropriate type. The type Mezzanine::RigidDebris is used purely as example
258  /// Though this is actual working code and was in the engine at one point, the current code is more sophiscticated
259  /// \n \n
260  /// The function operator<< simply calls Serialize and returns the stream, so it has all the pre and cost conditions of the Serialize
261  /// function listed in the @ref serializationmaking section.
262  /// \n \n
263  /// The stream extraction operators are a little bit more interesting. The operator>>(istream,YourType), by virtue of calling Deserialize
264  /// will wind up taking two passes over the XML. One looking for the ending tag that matches the first (it gets all the children of that tag too)
265  /// and one performing the actual parsing. The operator>>(istream,YourType) will work only with completely parsed objects in memory. With the
266  /// combination of these two all the heavy lifting of parsing is done up front, and the rest of the deserialization is just a bunch of pointer
267  /// and string manipulation. Another possibility with your stream extraction operator, if you new that it had exactly one parent xml node ,you
268  /// create without that first pass for improved performance.
269  /// @subsection serializationmisc Other little Things
270  /// To simplify and standardize errors thrown, the following functions exist:
271  /// @code
272  /// void SerializeError(const String& FailedTo, const String& ClassName, Boole SOrD = true);
273  /// void DeSerializeError(const String& FailedTo, const String& ClassName, Boole SOrD = false);
274  /// @endcode
275  /// Both of these functions throw a Mezzanine::Exception with the descriptive text of "Could not {FailedTo} during {ClassName} [De]Serialization."
276  /// If SOrD (Serialize Or Deserialize) is true the "De" is not printed.
277 
278 
279 
280 
281  ///////////////////////////////////////////////////////////////////////////////
282  /// @brief A tool for serializing classes with specific issues serializing.
283  /// @details Some classes have private members and it is impractical to change the class to expose this data. In this case a
284  /// serializer could be made that to work around this limitation.
285  /// \n \n
286  /// This was designed with the idea that a manager could inherit from this or have a separate class that implements this as a member. There should also be
287  /// no reason why something could not inherit from this and Mezzanine::DeSerializer. The type of this template is expected to match what this is serializing.
288  ///////////////////////////////////////
289  template <class Serializable>
291  {
292  public:
293  /// @brief Get all of the data from the serializable class instance
294  /// @details This is to be implemented in individual serializer with logic
295  /// specific to the required tasks. It is expected to produce an XML::Node
296  /// containing the entirety of the data required to reconstitute the serialized
297  /// class. \n \n
298  /// This is expected to gets it's knowledge about what to serialize some other than
299  /// being passed as an argument. It could query a manager or be passed a series pointers
300  /// that is needs to work with.
301  /// \n \n
302  /// This is not implemented by default.
303  /// @param CurrentRoot The point in the XML hierarchy that all the items deserialized should be appended to.
304  virtual void ProtoSerializeAll(XML::Node& CurrentRoot) const = 0;
305  /// @brief Output the complete serialized data to a stream.
306  /// @param Stream The std::ostream to send the data into.
307  /// @details By default this is implemented in using ProtoSerializeAll().
308  /// @return The populated ostream.
309  virtual std::ostream& SerializeAll(std::ostream& Stream) const
310  {
312  Doc.Load("");
313  ProtoSerializeAll(Doc);
314  Doc.Print(Stream);
315  return Stream;
316  }
317 
318  /// @brief Get all the serialized data about one class instance in an XML::Node
319  /// @param Target A reference to class instance to be deserialized.
320  /// @details This is not implemented by default.
321  /// @param CurrentRoot The point in the XML hierarchy that all this vector3 should be appended to.
322  virtual void ProtoSerialize(const Serializable& Target, XML::Node& CurrentRoot) = 0;
323  /// @brief Output the specified member to a stream
324  /// @param Target A reference to class instance to be deserialized.
325  /// @param Stream The std::ostream to send the data into.
326  /// @details The default implementation of this uses ProtoSerialize(const String&)
327  /// @return The std::ostream that was passed in.
328  virtual std::ostream& Serialize(std::ostream& Stream, const Serializable& Target)
329  {
331  Doc.Load("");
332  ProtoSerialize(Target,Doc);
333  Doc.Print(Stream);
334  return Stream;
335  }
336 
337  };
338 
339  ///////////////////////////////////////////////////////////////////////////////
340  /// @brief A tool for deserializing classes with specific issues deserializing them
341  /// @details Some classes Must have certain values available at the time of construction. This make deserializing them by overwriting an existing
342  /// class instance impractical. \n \n
343  /// This is expected to work with classes that have implemented the required DeSerializable functions. Specifically This makes use of
344  /// "static String GetSerializableName()", and it is expected that functions that must be implemented would call on "void ProtoDeSerialize(const XML::Node&)".
345  /// The type of this template is expected to match what this is deserializing.
346  /// \n \n
347  /// This was designed with the idea that a manager could inherit from this or have a separate class that implements this as a member. There should also be
348  /// no reason why something could not inherit from this and Mezzanine::Serializer.
349  ///////////////////////////////////////
350  template <class DeSerializable>
352  {
353  public:
354  /// @brief Convert An XML Node into a complete series of live class instances
355  /// @param OneNode A reference to the XML node to reconstitute into multiple Live classes.
356  /// @details This is expected to put the deserialized items somewhere they can be accessed by the calling,
357  /// but provides no facility for working them itself. \n \n
358  /// Not implemented in default DeSerializer.
359  virtual void ProtoDeSerializeAll(const XML::Node& OneNode)
360  {
361  // no checking occurs here, because this should be DeSerializeAll(istream&)
362  XML::Node SingleItemNode = OneNode.GetFirstChild();
363  while(SingleItemNode)
364  {
365  ProtoDeSerialize(SingleItemNode);
366  SingleItemNode = SingleItemNode.GetNextSibling();
367  }
368  }
369  /// @brief Get One node that has several of the appropriate kinds of nodes as children and deserialize all of them
370  /// @param Stream The std::istream to get the data from.
371  /// @details The default implementation of this uses ProtoDeSerializeAll(XML::Node&) to accept11
372  /// The complete XML to serialise and assemble it in memory.
373  /// @return This returns the input stream after the xml document has been extracted from it.
374  virtual std::istream& DeSerializeAll(std::istream& Stream)
375  {
378  ProtoDeSerializeAll(Doc->GetFirstChild());
379  return Stream;
380  }
381 
382  /// @brief Convert An XML Node into a complete live data structure
383  /// @param OneNode A reference to the XML node to reconstitute into a live class instance.
384  /// @details Not implemented in default serializer.
385  /// @return A pointer to the freshly deserialized class instance.
386  virtual DeSerializable* ProtoDeSerialize(const XML::Node& OneNode) = 0;
387  /// @brief Get the serialized version of all the live data from the stream.
388  /// @param Stream The std::istream to get the data from.
389  /// @details The default implementation of this uses ProtoDeSerializeAll(XML::Node*) to accept
390  /// The complete XML to serialise and assemble it in memory.
391  /// @return This returns the input stream after the xml document has been extracted from it.
392  virtual std::istream& DeSerialize(std::istream& Stream)
393  {
395  Mezzanine::CountedPtr<Mezzanine::XML::Document> Doc(Mezzanine::XML::PreParseClassFromSingleTag(DeSerializable::GetSerializableName(), OneTag) );
396  ProtoDeSerialize(Doc->GetFirstChild());
397  return Stream;
398  }
399 
400  /// @brief This will return the Name of the element that Contains multiple of the items to be DeSerialized
401  /// @return A String that correctly indicates the name of an xml tag.
402  virtual String ContainerName() const = 0;
403  };
404 
405  /// @brief Convert any class that supports serialization or has a serializer to a string of chars in a stream
406  /// @details Any Class will work with this template as long as it implements the method "XML::Node ProtoSerialize(XML::Document&) const"
407  /// @param Stream The ostream to put the serializable into.
408  /// @param Converted The item to be serialized, which must have a "XML::Node ProtoSerialize(XML::Node& CurrentRoot) const" method.
409  /// @param Indent Defaults to nothing but can be set to "\t" to get normal
410  /// @return A the stream that was passed and now contains the serialized object.
411  template <class T>
412  std::ostream& Serialize(std::ostream& Stream, const T& Converted, const String& Indent = String("") )
413  {
415  Doc.Load(""); // This sets the encoding to UTF8 ?!
416  Converted.ProtoSerialize(Doc);
417  Doc.Print(Stream, Indent.c_str());
418  return Stream;
419  }
420 
421  /// @brief Deserialize the next xml tag in the stream into a specific in memory class instance.
422  /// @details "void ProtoDeSerialize(const XML::Node&)" and "static String GetSerializableName() const" must be implemented on
423  /// the class instance that is passed in for this to work
424  /// @param Stream The istream to extract the required data from
425  /// @param Converted The Class member that is deserialized.
426  /// @return This returns the istream that provided the serialized data.
427  template <class T>
428  std::istream& DeSerialize(std::istream& Stream, T& Converted)
429  {
431  Mezzanine::CountedPtr<Mezzanine::XML::Document> Doc( Mezzanine::XML::PreParseClassFromSingleTag("Mezzanine::", Converted.GetSerializableName(), OneTag) );
432 
433  Converted.ProtoDeSerialize(Doc->GetFirstChild());
434 
435  return Stream;
436  }
437 
438  /// @internal
439  /// @brief Used to interface with a previous version of the serialization code.
440  /// @details The older serialization was implemented entirely in streaming operators. This uses those, however inneficient to get the XML::Node that
441  /// the current serialization solution is centered around.
442  /// @param Converted The class implementing older serialization code.
443  /// @param CurrentRoot The place in the xml hiearchy to append the items to be sloppily ProtoSerialized.
444  template <class T>
445  void SloppyProtoSerialize(const T& Converted, XML::Node& CurrentRoot)
446  {
447  std::stringstream Depot; //Make a place to store serialized XML
448  XML::Document Staging; //Make a place to convert from XML to an xml node
449  Depot << Converted; //Use old conversion tools to convert to serialized XML as if writing to a file
450  Staging.Load(Depot); //Load To the staging area as if loading XML form a file or whatever.
451 
452  CurrentRoot.AppendCopy(Staging.DocumentElement()); //Append our work as an XML::node to the desired place in the xml Hierarchy.
453  }
454 
455  /// @brief Simply does some string concatenation, then throws an Exception
456  /// @param FailedTo What failed to happed for example "create testnode" or "acquire a mutex"
457  /// @param ClassName The name of the class throw the exception
458  /// @param SOrD Defaults to true, and if true uses the word "Serialization", otherwise uses the word "DeSerialization"
459  /// @throw A Mezzanine::Exception with the message "Could not {FailedTo} during {ClassName} [De]Serialization.""Could not {FailedTo} during {ClassName} [De]Serialization."
460  void MEZZ_LIB SerializeError(const String& FailedTo, const String& ClassName, Boole SOrD = true);
461 
462  /// @brief Simply does some string concatenation, then throws an Exception
463  /// @param FailedTo What failed to happed for example "create testnode" or "acquire a mutex"
464  /// @param ClassName The name of the class throw the exception
465  /// @param SOrD Defaults to false, and if true uses the word "Serialization", otherwise uses the word "DeSerialization"
466  /// @throw A Mezzanine::Exception with the message "Could not {FailedTo} during {ClassName} [De]Serialization."
467  /// @details This just calls SerializeError() with the third parameter false. This exists solely to make code
468  /// A little more readable.
469  void MEZZ_LIB DeSerializeError(const String& FailedTo, const String& ClassName, Boole SOrD = false);
470 }//Mezzanine
471 
472 /*
473 /// @brief This will call convert an XML::Node into Text in a stream
474 /// @param Stream The std::ostream that the serializable will be stuffed into.
475 /// @param OneNode The xml to be converted
476 /// @return This returns Stream that is passed in, with the additional data of the serialized object.
477 //template <>
478 std::ostream& MEZZ_LIB operator<< <Mezzanine::XML::Node> (std::ostream& Stream, const Mezzanine::XML::Node& OneNode)
479 {
480  OneNode.Print(Stream);
481  return Stream;
482 }
483 */
484 
485 #endif
String GetOneTag(std::istream &stream)
Gets the first tag out of the Stream and returns it as a String.
Definition: xmlstring.cpp:72
virtual std::ostream & Serialize(std::ostream &Stream, const Serializable &Target)
Output the specified member to a stream.
virtual std::istream & DeSerializeAll(std::istream &Stream)
Get One node that has several of the appropriate kinds of nodes as children and deserialize all of th...
virtual void ProtoDeSerializeAll(const XML::Node &OneNode)
Convert An XML Node into a complete series of live class instances.
bool Boole
Generally acts a single bit, true or false.
Definition: datatypes.h:173
void Print(Writer &WriterInstance, const Char8 *indent="\t", unsigned int flags=FormatDefault, Encoding DocumentEncoding=EncodingAuto, unsigned int Depth=0) const
Output the XML document using a Writer.
A tool for serializing classes with specific issues serializing.
Document * PreParseClassFromSingleTag(const String &NameSpace, const String &ClassName, const String &OneTag)
Perform a basic series of checks for extracting meaning from a single xml tag.
Definition: xmlstring.cpp:116
Node GetFirstChild() const
Get the first child Node of this Node.
All the definitions for datatypes as well as some basic conversion functions are defined here...
std::ostream & Serialize(std::ostream &Stream, const T &Converted, const String &Indent=String(""))
Convert any class that supports serialization or has a serializer to a string of chars in a stream...
A simple reference counting pointer.
Definition: countedptr.h:70
virtual std::ostream & SerializeAll(std::ostream &Stream) const
Output the complete serialized data to a stream.
ParseResult Load(std::basic_istream< char, std::char_traits< char > > &stream, unsigned int options=ParseDefault, Encoding DocumentEncoding=EncodingAuto)
Load XML from a stream.
Node GetNextSibling() const
Attempt to retrieve the next sibling of this Node.
Node DocumentElement() const
Get document element.
virtual std::istream & DeSerialize(std::istream &Stream)
Get the serialized version of all the live data from the stream.
A light-weight handle for manipulating nodes in DOM tree.
Definition: node.h:89
This file describes and implements a reference counted pointer that is NOT threadsafe.
std::istream & DeSerialize(std::istream &Stream, T &Converted)
Deserialize the next xml tag in the stream into a specific in memory class instance.
void DeSerializeError(const String &FailedTo, const String &ClassName, Boole SOrD)
Simply does some string concatenation, then throws an Exception.
The root node of any xml hierarchy is a Document.
Definition: document.h:83
A tool for deserializing classes with specific issues deserializing them.
#define MEZZ_LIB
Some platforms require special decorations to denote what is exported/imported in a share library...
The bulk of the engine components go in this namspace.
Definition: actor.cpp:56
void SloppyProtoSerialize(const T &Converted, XML::Node &CurrentRoot)
Used to interface with a previous version of the serialization code.
void SerializeError(const String &FailedTo, const String &ClassName, Boole SOrD)
Simply does some string concatenation, then throws an Exception.
std::string String
A datatype used to a series of characters.
Definition: datatypes.h:159
Attribute AppendCopy(const Attribute &proto)
Copies an Attribute and puts the copy at the end of this Nodes attributes.