root/src/MarkupReader.cpp

////////////////////////////////////////////////////////////////////////
// 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
////////////////////////////////////////////////////////////////////////




#include "MarkupReader.h"

namespace nw {

MarkupReader::MarkupReader()
{
        // Use init() as constructor
        // Abstract calls are not allowed in c++ constructor
        init();
}

MarkupReader::~MarkupReader()
{
        if(motherTag)
        {
                delete motherTag; // delete recursively
                motherTag = NULL;
        }
}

void MarkupReader::init()
{
        motherTag = new Tag("");
        parentTag = motherTag;
        selectedTag = parentTag;
}

void MarkupReader::init(const String filepath)
{
        init();

        std::ifstream file;
        file.open(filepath.c_str());
        if(!file.fail()) {
                int error = readWholeDocument(file);
                file.close();

                if(error != 0) {
                        std::cout << "Failed to parse the document: " << filepath << std::endl;
                }

                describePointers();

        } else {
                std::cout << "failed to open file " << filepath << std::endl;
        }
}


bool MarkupReader::push(const String tagName)
{
        if (!parentTag) {
                return false;
        }

        Tag* child = this->parentTag->getChildWithName(tagName);

        if(child != NULL)
        {
                this->parentTag = child;
                return true;
        }
        return false;
}

void MarkupReader::describeArray(const String arrayName, const String elementsName, unsigned int size)
{
        MarkupReaderArray array;

        if(!arrayName.empty())
        {
                 //TODO push already inited in the mothertag?
                if (!push(arrayName)) {
                        array.hasWrapperTag = false;
                        //this->tagArrays.push(array);
                        //return; // add an empty array, so enterNextElement returns false on first call
                } else {
                        array.hasWrapperTag = true;
                }
        }
        else
        {
                array.hasWrapperTag = false;
        }

        if(parentTag != NULL)
        {
                std::vector<Tag*> children = this->parentTag->getChildren();
                int numberOfChildren = children.size();
                std::stack<Tag*> tags;
                for (int i = numberOfChildren-1; i > -1; --i)
                {
                        if(children.at(i)->getName() == elementsName)
                        {
                                array.tags.push(children.at(i));
                        }
                }
        }
        array.isValueArray = false;
        this->tagArrays.push(array);
}

/// by default assume that anonymous values are not available,
/// otherwise the childclass can overwrite this method
void MarkupReader::describeValueArray(const String arrayName, unsigned int size)
{
//      MarkupReaderArray array;
//
//      if(!arrayName.empty())
//      {
//              push(arrayName); //TODO already inited in the mothertag
//              array.hasWrapperTag = true;
//      }
//
////    if(currentTag != NULL)
////    {
////            array.tags = currentTag->getCsvTags();
////    }
//
//      if(currentTag != NULL)
//      {
//              std::vector<Tag*> children = this->currentTag->getChildren();
//              int numberOfChildren = children.size();
//              std::stack<Tag*> tags;
//              for (int i = numberOfChildren-1; i > -1; --i)
//              {
//                      if(children.at(i)->getName() == "value")
//                      {
//                              array.tags.push(children.at(i));
//                      }
//              }
//      }
//      array.isValueArray = false;
//      this->tagArrays.push(array);
        describeArray(arrayName, "", size);
        tagArrays.top().isValueArray = true;
}

bool MarkupReader::enterNextElement(unsigned int iterator)
{
        if(!tagArrays.empty()) //There are any Arrays
        {
                if(tagArrays.top().isValueArray)
                {
                        if(!tagArrays.top().tags.empty()) //The Array still has Elements
                        {
                                //Directly select the next tag. Works, if anonymous tags are allowed
                                selectedTag = tagArrays.top().tags.top();
                                tagArrays.top().tags.pop(); //Drop Pointer from list
                                return true;
                        }
                }
                else
                {
                        if(!tagArrays.top().tags.empty()) //The Array still has Elements
                        {
                                parentTag = tagArrays.top().tags.top(); //Direct Jump into Element
                                tagArrays.top().tags.pop(); //Drop Pointer from list
                                return true;
                        } else if (iterator > 0) {
                                pop(); // Leave last element
                        }
                }

                if(tagArrays.top().hasWrapperTag)
                        pop(); // Leave array

                tagArrays.pop(); //Array finished!
        }

        return false;
}


void MarkupReader::pop()
{
        this->parentTag = this->parentTag->getParent();
        if(this->parentTag == NULL)
        {
                this->parentTag = motherTag;
        }
}

Tag* MarkupReader::extractMotherTag()
{
        Tag* ret = motherTag;
        motherTag = NULL; // prevent it from being deleted in the destructor
        return ret;
}

Tag* MarkupReader::extractTags()
{
        Tag* ret = new Tag();
        std::vector<Tag*>& children = parentTag->getChildren();
        for (int i = 0; i < children.size(); ++i)
        {
                ret->addChild(children.at(i));
        }
        children.clear();
        return ret;
}

void MarkupReader::close()
{
        //we read all the stuff earlier, so there is nothing to close anymore;
        // file should be closed after reading
}
void MarkupReader::describeName(const String name)
{
        if (parentTag) {
                selectedTag = parentTag->getChildWithName(name);
        } else {
                selectedTag = NULL;
        }
}

void MarkupReader::describeValue(String& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue(double& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue(char& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue(unsigned char& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue(int& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue(unsigned int& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue(float& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue(bool& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue( Pointer ref)
{
        unsigned int id;
        getTagValue(id);
        ref = Describer::getSerializedObjectForId(id);
}

void MarkupReader::describeBlob(const String blobName, nw::Pointer blob, unsigned int blobSize)
{
        Tag* child = this->parentTag->getChildWithName(blobName);
                if(child != NULL)
                {
                        if(child->hasChildren())
                        {
                                Tag* encodingTag = child->getChildWithName(N0Slib_BinaryToTextEncoding_EncodingTagName);
                                Tag* valueTag = child->getChildWithName(N0Slib_BinaryToTextEncoding_ValueTagName);
                                if(encodingTag != NULL && valueTag != NULL)
                                {
                                        String encoding = encodingTag->getValue();
                                        if(encoding == N0Slib_BinaryToTextEncoding_Base64)
                                                blob = valueTag->getBase64Value();
                                        else if(encoding == N0Slib_BinaryToTextEncoding_Base95)
                                                std::cout << "Base95 not implemented, yet" << std::endl;
                                        else if(encoding == N0Slib_BinaryToTextEncoding_Hexadecimal)
                                                blob = valueTag->getHexValue();
                                        else
                                                std::cout << "Unkown encoding: " << encoding << std::endl;
                                }
                                else
                                {
                                        std::cout << "Warning: Broken Blob: EncodingTag or ValueTag not specified, trying base64" << std::endl;
                                }
                        }
                        else
                        {
                                blob = child->getBase64Value();
                        }
                }
}
void MarkupReader::describeValue( signed char& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue( short& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue( unsigned short& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue( long& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue( unsigned long& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue( long long& ref)
{
        getTagValue(ref);
}
void MarkupReader::describeValue( long double& ref)
{
        getTagValue(ref);
}

void MarkupReader::comment(const String text) {} //Don't read comments

bool MarkupReader::isInWriteMode()
{
        return false;
}

template<class T> inline void MarkupReader::getTagValue(T& ref)
{
        if(selectedTag)
        {
                ref = selectedTag->getValueAs<T>();
        }
}

}  // namespace nw