//////////////////////////////////////////////////////////////////////// // 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 #include #include #include #include #include #include #include #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 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 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 void describe(std::vector&); // template void describe(std::stack&); // template void describe(std::list&); // template void describe(std::deque&); // template void describe(std::queue&); // template void describe(std::priority_queue&); template void describe(String mapName, std::map& m) { if(isInWriteMode()) { push(mapName); typename std::map::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 void describe(std::multimap&); // template void describe(std::set&); // template void describe(std::multiset&); /// 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 unhandledPointers; ///< store Pointers temporary until they were written to the header std::vector 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 states; /////////////////////////////////////////////////////////////////////////////////////////////// /// Saves the content of the collected Pointers and marks them as handled. /////////////////////////////////////////////////////////////////////////////////////////////// inline void serializePointerData(); }; } // namespace nw #endif /* DESCRIBER_H_ */