root/src/Describer.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
////////////////////////////////////////////////////////////////////////
// Copyright (c) Nehmulos 2011-2014
// This file is part of N0 Strain Serialization Library.
//
// N0Strain-Serialization-Library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// N0Strain-Serialization-Library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with N0Strain-Serialization-Library.  If not, see https://gnu.org/licenses/lgpl-3.0
////////////////////////////////////////////////////////////////////////




#ifndef DESCRIBER_H_
#define DESCRIBER_H_

#include <sstream>
#include <iostream>
#include <fstream>
#include <istream>
#include <ostream>
#include <map>
#include <stack>
#include <stdio.h>

#include "N0SlibConstants.h"
#include "Tag.h"
#include "DescribedObject.h"

namespace nw {

typedef Describer Descriptor; ///< Alias to itself, to provide a more common term
 class PointerCollector;

///////////////////////////////////////////////////////////////////////////////////////////////////
/// This Class allows to write data into a file or to read it from there
/// It is build up, so that it can be implemented
/// to provide markup files and binary files
/// To allow this, a slow down by taking Markup-Tag-Names
/// as Parameters, was accepted;
///////////////////////////////////////////////////////////////////////////////////////////////////
class Describer {
public:
        Describer();
        virtual ~Describer();

        void setPointers(const PointerCollector& pc);

        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// Closes the files that was opened for the Serializer.
        /// It may writes a footer and should be called, Otherwise errors could appear.
        ///////////////////////////////////////////////////////////////////////////////////////////////
        virtual void close() = 0;

        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// Returns true if the Serializer writes into a file, if it's a reader false is returned
        ///////////////////////////////////////////////////////////////////////////////////////////////
        virtual bool isInWriteMode() = 0;

        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// returns the opposite of @isInWriteMode. This Function was created to tidy up your code.
        ///////////////////////////////////////////////////////////////////////////////////////////////
        bool isInReadMode();

        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// returns true if the Serializer doesn't read or write anything to / from the harddrive.
        /// This was written to recognize PointerCollector.
        ///////////////////////////////////////////////////////////////////////////////////////////////
        virtual bool isSilentCrawler();


        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// enters a childTag with the given Name, returns true if successful.
        /// In ReadMode it returns true if a tag with the given name Exists.
        /// Returns always true in WriteMode.
        ///////////////////////////////////////////////////////////////////////////////////////////////
        virtual bool push(const String tagName) = 0;

        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// writes if the condition is true; set's the condition to true if it's in the file.
        /// Returns the condition if it 's used in a writer.
        /// Set's the condition to true / false if the push could / couldn't be read.
        /// The return value is equivalent to the condition, still the return value should be used
        /// for conditions, because it will be surely true for the PointerCollector class
        /// Example:
        ///     if(file->conditionalPush("awesomeTag", awesomeness) {
        ///     // This will only be written if awesomeness is true
        ///             // and only be read if it exists in the file
        ///     file->serialize("thisIsAwesome", awesomenessLevel);
        ///             file->serialize("AwesomeStuff", otherAwesomeStuff);
        /// }
        ///////////////////////////////////////////////////////////////////////////////////////////////
        virtual bool conditionalPush(const String tagname, bool condition);
        virtual void pop() = 0; ///< leaves the current tag; jumps into it's parentTag. Like an end() for push()

        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// Open a simple array that contains comma separated values, or a base64 encrypted string.
        /// Data can be added by using pushValueToSimpleArray
        /// If arrayName is empty only the value will be written.
        ///////////////////////////////////////////////////////////////////////////////////////////////
//      virtual void describeSimpleArray(String arrayName, unsigned int size) = 0;
//
//      /// push a value the open simpleArray
//      template<class T> virtual bool pushValueToSimpleArray(T& value);

        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// Opens an array with the number of (size) elements.
        /// The Array is wrapped by a tag with the arrayName
        /// Each element in the array has the ElementsName as tagName if names in arrays are supported
        /// It fills the ToIterate list of enterNextElement;
        /// Use it before you loop through an array with enterNextElement
        /// If arrayName is empty, the elements will be created in the currentTag.
        ///////////////////////////////////////////////////////////////////////////////////////////////
        virtual void describeArray(const String arrayName, const String ElementsName, unsigned int size) = 0;

        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// Read / Write an array containing elements of a simple data.
        /// The elements must be simple values wich will be stored anonymously by using describeValue.
        /// The Datatype of the elements must be supported by Describer::describeValue.
        /// Describer::describeValue must be called only ONCE after enterNextElement has been called.
        /// If anonymous elements are not supported by the Derived Describer they will use a <value> tag
        /// If you want to store complex Objects use describeArray(string, string, uint).
        /// @parm arrayName Name of the Tag containing the Array.
        /// @parm size Only used when writing. Determins how long enterNextElement returns true.
        ///////////////////////////////////////////////////////////////////////////////////////////////
        virtual void describeValueArray(const String arrayName, unsigned int size) = 0;

        // //helps to reserve enough memory for vectors, instead of pushing all the time
        // //Maybe just really use references in serializeArray, it would take less code
        //virtual unsigned int getArraySize();


        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// Jumps into the next element in an array.
        ///
        /// Creates an arrayElement and returns true if the iterator is smaller than the current array's size
        /// use it as condition in a for loop with an unsigned int as Iterator.
        /// example: for(int i=0; describer->enterNextElement(i); ++i) { /* ... */ }
        /// Don't forget to call serializeArray before your "for" loop
        ///////////////////////////////////////////////////////////////////////////////////////////////
        virtual bool enterNextElement(unsigned int iterator) = 0;

        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// Extending classes will write/read the references; used to serialize your raw data.
        /// This functions cover all wide-spread data-types
        /// If the Serializer is a Writer it writes the reference to the file
        /// If the Serializer is a Reader it set's the reference to
        ///    the value of the childTag for the matching Name
        ///////////////////////////////////////////////////////////////////////////////////////////////
        /* Serialize functions */
        virtual void describeValue(bool&)            = 0; ///< Describe a  boolean          reference
        virtual void describeValue(char&)            = 0; ///< Describe a  character        reference
        virtual void describeValue(unsigned char&)   = 0; ///< Describe an unsigned char    reference
        virtual void describeValue(signed char&)     = 0; ///< Describe a  signed char      reference
        //2 byte
        virtual void describeValue(short&)           = 0; ///< Describe a  short            reference
        virtual void describeValue(unsigned short&)  = 0; ///< Describe an unsigned short   reference
        //4 byte
        virtual void describeValue(int&)             = 0; ///< Describe an integer          reference
        virtual void describeValue(unsigned int&)    = 0; ///< Describe an unsigned integer reference
        virtual void describeValue(long&)            = 0; ///< Describe a  long             reference
        virtual void describeValue(unsigned long&)   = 0; ///< Describe an unsigned long    reference
        virtual void describeValue(float&)           = 0; ///< Describe a  float            reference
        virtual void describeValue(Pointer)          = 0; ///< Describe a  PointerId        reference
        //8 byte
        virtual void describeValue(double&)          = 0; ///< Describe a double            reference
        virtual void describeValue(long long&)       = 0; ///< Describe a long long         reference
        //12 byte
        virtual void describeValue(long double&)     = 0; ///< Describe a long double       reference
        //variable size
        virtual void describeValue(String&)          = 0; ///< Describe a String reference
        virtual void describeBlob(const String blobName, nw::Pointer binaryBlob, unsigned int blobSize) = 0; ///< Describe Binary blobs
        virtual void comment(const String text) = 0;       ///< Write a comment if it's supported

        virtual void describeName(const String childName) = 0;

        void describe(const String childName,bool& ref)          {describeName(childName); describeValue(ref);}
        void describe(const String childName,char& ref)          {describeName(childName); describeValue(ref);}
        void describe(const String childName,unsigned char& ref) {describeName(childName); describeValue(ref);}
        void describe(const String childName,signed char& ref)   {describeName(childName); describeValue(ref);}
        void describe(const String childName,short& ref)         {describeName(childName); describeValue(ref);}
        void describe(const String childName,unsigned short& ref){describeName(childName); describeValue(ref);}
        void describe(const String childName,int& ref)           {describeName(childName); describeValue(ref);}
        void describe(const String childName,unsigned int& ref)  {describeName(childName); describeValue(ref);}
        void describe(const String childName,long& ref)          {describeName(childName); describeValue(ref);}
        void describe(const String childName,unsigned long& ref) {describeName(childName); describeValue(ref);}
        void describe(const String childName,float& ref)         {describeName(childName); describeValue(ref);}
        void describe(const String childName,Pointer ref)        {describeName(childName); describeValue(ref);}
        void describe(const String childName,double& ref)        {describeName(childName); describeValue(ref);}
        void describe(const String childName,long long& ref)     {describeName(childName); describeValue(ref);}
        void describe(const String childName,long double& ref)   {describeName(childName); describeValue(ref);}
        void describe(const String childName,String& ref)        {describeName(childName); describeValue(ref);}


        /* (De)Serialization functions with default values */
        void describe(const String childName,bool& ref, bool defaultValue);
        //Containers
//      template<class T> void describe(std::vector<T>&);
//      template<class T> void describe(std::stack<T>&);
//      template<class T> void describe(std::list<T>&);
//      template<class T> void describe(std::deque<T>&);
//      template<class T> void describe(std::queue<T>&);
//      template<class T> void describe(std::priority_queue<T>&);
        template<typename KeyT, typename ValueT> void describe(String mapName, std::map<KeyT, ValueT>& m)
        {
                if(isInWriteMode())
                {
                        push(mapName);
                        typename std::map<KeyT,ValueT>::iterator it;
                        for(it=m.begin(); it != m.end(); ++it)
                        {
                                std::stringstream ss(it->first);
                                String elementTagName;
                                ss >> elementTagName;
                                ss << it->second;
                                this->describeValue(elementTagName, it->second);
                        }
                        pop();
                }
                else if(isInReadMode())
                {
                        describeArray(mapName, "", 0);
                        for (int i = 0; enterNextElement(i); ++i)
                        {
                                Tag t;
//                              t = this->getNextTag();
                        }
                }
        }
//      template<class T> void describe(std::multimap<T>&);
//      template<class T> void describe(std::set<T>&);
//      template<class T> void describe(std::multiset<T>&);

        /// return error message or empty string if there was no error
        std::string getErrorMessage();


        ///////////////////////////////////////////////////////////////////////////////////////////////
        //
        // States
        // these functions are used to store custom states in a describer.
        // They can be used to check if a static value is already described.
        //
        ///////////////////////////////////////////////////////////////////////////////////////////////

        bool hasState(const String stateName);                                                  ///< Return true if a state was set.
        bool getBooleanState(String stateName);                                         ///< Return a boolean Value for the State
        void getState(const String stateName, void* pointerToPointer);  ///< Return a stored Pointer for the State
        void setState(const String stateName, bool value);                              ///< Add a new State and set it's value
        void setState(const String stateName, void* value);                             ///< Add a new State and set it's value

        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// Set this pointer to a function that returns a new Serialized Object for the classId
        /// You only have to set this if you want to serialize Classes, that derive from SerializedObject
        ///////////////////////////////////////////////////////////////////////////////////////////////
        static DescribedObject* (*createObjectForClassId)(ClassId);
        static String encodingUsed;

protected:
        void describePointers();                                        ///< Serialize the N0Slib:Header tag and all unhandled Pointers;
        bool pointerIsKnown(DescribedObject* pointer);                  ///< return true if the pointer was already collected
        std::vector<DescribedObject *> unhandledPointers;             ///< store Pointers temporary until they were written to the header
        std::vector<DescribedObject *> handledPointers;                      ///< Store pointers that were written to / read from the file
        DescribedObject* getSerializedObjectForId(unsigned int id);         ///< Get a handled Pointer for it's id
        unsigned int getIDForSerializedObject(Pointer pointerToPointer);///< Get an id for a handled Pointer

        std::stringstream errorMessage; ///< write error message into this stream
private:
        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// Save states to remember if static values were already serialized.
        /// Also save pointers to static values.
        /// The states can be accessed via getState and addState
        ///////////////////////////////////////////////////////////////////////////////////////////////
        std::vector<Tag*> states;

        ///////////////////////////////////////////////////////////////////////////////////////////////
        /// Saves the content of the collected Pointers and marks them as handled.
        ///////////////////////////////////////////////////////////////////////////////////////////////
        inline void serializePointerData();
};

}  // namespace nw
#endif /* DESCRIBER_H_ */