/* * XmlData.cpp * * Copyright (C) 2009 Matthias Schiffer * * This program 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. * * This program 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 this program. If not, see . */ #include "XmlData.h" #include "Base64Encoder.h" #include #include #include namespace Mad { namespace Common { void XmlData::Element::updateStr() { std::string typeStr; if(type == NONE) { str = ""; } else if(type == BINARY) { str = Base64Encoder::encode(boost::get >(value)); typeStr = "binary"; } else if(type != STRING) { std::ostringstream buf; switch(type) { case INT: buf << boost::get(value); typeStr = "int"; break; case UINT: buf << boost::get(value); typeStr = "uint"; break; case INT64: buf << boost::get(value); typeStr = "int64"; break; case UINT64: buf << boost::get(value); typeStr = "uint64"; break; case FLOAT: buf << boost::get(value); typeStr = "float"; break; case DOUBLE: buf << boost::get(value); typeStr = "double"; break; case LONGDOUBLE: buf << boost::get(value); typeStr = "longdouble"; default: break; } str = buf.str(); } else typeStr = "string"; xmlNodePtr newNode = xmlNewText((xmlChar*)str.c_str()); xmlNodePtr oldNode = elementNode->children; xmlReplaceNode(oldNode, newNode); xmlFreeNode(oldNode); xmlSetProp(elementNode, (xmlChar*)"type", (xmlChar*)typeStr.c_str()); } XmlData::Element::Element(xmlNodePtr node) : elementNode(node), type(NONE) { if(!node) return; xmlChar *typestr = xmlGetProp(node, (xmlChar*)"type"); if(!typestr) return; xmlChar *content = xmlNodeGetContent(node->children); if(!content) { xmlFree(typestr); return; } str = (char*)content; std::istringstream buf(str); if(!xmlStrcmp(typestr, (xmlChar*)"binary")) { type = BINARY; value = Base64Encoder::decode(str); } else if(!xmlStrcmp(typestr, (xmlChar*)"int")) { type = INT; long tmp; buf >> tmp; value = tmp; } else if(!xmlStrcmp(typestr, (xmlChar*)"uint")) { type = UINT; unsigned long tmp; buf >> tmp; value = tmp; } else if(!xmlStrcmp(typestr, (xmlChar*)"int64")) { type = INT64; long long tmp; buf >> tmp; value = tmp; } else if(!xmlStrcmp(typestr, (xmlChar*)"uint64")) { type = UINT64; unsigned long long tmp; buf >> tmp; value = tmp; } else if(!xmlStrcmp(typestr, (xmlChar*)"float")) { type = FLOAT; float tmp; buf >> tmp; value = tmp; } else if(!xmlStrcmp(typestr, (xmlChar*)"double")) { type = DOUBLE; double tmp; buf >> tmp; value = tmp; } else if(!xmlStrcmp(typestr, (xmlChar*)"longdouble")) { type = LONGDOUBLE; long double tmp; buf >> tmp; value = tmp; } else if(!xmlStrcmp(typestr, (xmlChar*)"string")) { type = STRING; } xmlFree(typestr); xmlFree(content); if(type != NONE) updateStr(); } XmlData::Entry::Entry(xmlNodePtr node) : entryNode(node) { if(!node) return; for(xmlNodePtr element = node->children; element != 0; element = element->next) { if(element->type != XML_ELEMENT_NODE) continue; xmlChar *name = xmlGetProp(element, (xmlChar*)"name"); if(!xmlStrcmp(element->name, (xmlChar*)"list")) lists.insert(std::make_pair(std::string((char*)name), new List(element))); else if(!xmlStrcmp(element->name, (xmlChar*)"value")) elements.insert(std::make_pair(std::string((char*)name), new Element(element))); xmlFree(name); } } template <> std::string XmlData::Entry::get(const std::string &name) const { Element *element = getElement(name); if(!element) return std::string(); return element->str; } template <> const std::string& XmlData::Entry::get(const std::string &name) const { static std::string empty; Element *element = getElement(name); if(!element) return empty; return element->str; } template <> std::vector XmlData::Entry::get >(const std::string &name) const { Element *element = getElement(name); if(!element) return std::vector(); switch(element->type) { case Element::BINARY: return boost::get >(element->value); default: return std::vector(); } } template <> const std::vector& XmlData::Entry::get&>(const std::string &name) const { static std::vector empty; Element *element = getElement(name); if(!element) return empty; switch(element->type) { case Element::BINARY: return boost::get >(element->value); default: return empty; } } XmlData::List::List(xmlNodePtr node) : elementNode(node) { for(xmlNodePtr entry = node->children; entry != 0; entry = entry->next) { if(entry->type != XML_ELEMENT_NODE || xmlStrcmp(entry->name, (xmlChar*)"entry")) continue; entries.push_back(new Entry(entry)); } } XmlData::XmlData() { doc = xmlNewDoc((xmlChar*)"1.0"); rootNode = xmlNewNode(0, (xmlChar*)"mad"); xmlDocSetRootElement(doc, rootNode); entry = new Entry(rootNode); } XmlData::XmlData(const XmlData &o) { doc = xmlCopyDoc(o.doc, 1); rootNode = xmlDocGetRootElement(doc); entry = new Entry(rootNode); } XmlData::XmlData(const Net::Packet &packet) { doc = xmlParseMemory((const char*)packet.getData(), packet.getLength()); rootNode = xmlDocGetRootElement(doc); entry = new Entry(rootNode); } XmlData& XmlData::operator=(const XmlData &o) { delete entry; xmlFreeDoc(doc); doc = xmlCopyDoc(o.doc, 1); rootNode = xmlDocGetRootElement(doc); entry = new Entry(rootNode); return *this; } std::string XmlData::getType() const { xmlChar *type = xmlGetProp(rootNode, (xmlChar*)"type"); std::string ret(type ? (char*)type : ""); xmlFree(type); return ret; } void XmlData::setType(const std::string &type) { xmlSetProp(rootNode, (xmlChar*)"type", (xmlChar*)type.c_str()); } Net::Packet XmlData::toPacket(boost::uint16_t requestId) const { xmlChar *buf; int length; xmlDocDumpMemory(doc, &buf, &length); Net::Packet packet(requestId, buf, length); xmlFree(buf); return packet; } } }