/* * 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 #include namespace Mad { namespace Common { void XmlData::Element::updateStr() { Core::String typeStr; if(type == NONE) { str = ""; } else if(type == BINARY) { str = Base64Encoder::encode(boost::get >(value)).c_str(); typeStr = "binary"; } else if(type == TIME) { str = Core::String::fromString(boost::posix_time::to_iso_string(boost::get(value))); typeStr = "time"; } 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"; case BINARY: case STRING: case TIME: case NONE: break; } str = buf.str().c_str(); } else typeStr = "string"; xmlNodePtr newNode = xmlNewText((xmlChar*)str.toUTF8().c_str()); xmlNodePtr oldNode = elementNode->children; xmlReplaceNode(oldNode, newNode); xmlFreeNode(oldNode); xmlSetProp(elementNode, (xmlChar*)"type", (xmlChar*)typeStr.toUTF8().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 = Core::String::fromUTF8((char*)content); std::istringstream buf(str.toString()); if(!xmlStrcmp(typestr, (xmlChar*)"binary")) { type = BINARY; value = Base64Encoder::decode(str.toString()); } else if(!xmlStrcmp(typestr, (xmlChar*)"time")) { type = TIME; try { value = boost::posix_time::from_iso_string(str.toString()); } catch(...) { value = boost::posix_time::ptime(boost::posix_time::not_a_date_time); } } 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(Core::String::fromUTF8((char*)name), new List(element))); else if(!xmlStrcmp(element->name, (xmlChar*)"value")) elements.insert(std::make_pair(Core::String::fromUTF8((char*)name), new Element(element))); xmlFree(name); } } template <> Core::String XmlData::Entry::get(const Core::String &name) const { Element *element = getElement(name); if(!element) return Core::String(); return element->str; } template <> const Core::String& XmlData::Entry::get(const Core::String &name) const { static const Core::String empty; Element *element = getElement(name); if(!element) return empty; return element->str; } template <> std::vector XmlData::Entry::get >(const Core::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 Core::String &name) const { static const 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; } } template <> boost::posix_time::ptime XmlData::Entry::get(const Core::String &name) const { Element *element = getElement(name); if(!element) return boost::posix_time::ptime(boost::posix_time::not_a_date_time); switch(element->type) { case Element::TIME: return boost::get(element->value); default: return boost::posix_time::ptime(boost::posix_time::not_a_date_time); } } 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(const std::string &filename) throw (Core::Exception) { doc = xmlParseFile(filename.c_str()); if(!doc) throw Core::Exception(Core::Exception::NOT_AVAILABLE); 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; } Core::String XmlData::getType() const { xmlChar *type = xmlGetProp(rootNode, (xmlChar*)"type"); Core::String ret(type ? Core::String::fromUTF8((char*)type) : ""); xmlFree(type); return ret; } void XmlData::setType(const Core::String &type) { xmlSetProp(rootNode, (xmlChar*)"type", (xmlChar*)type.toUTF8().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; } void XmlData::toFile(const std::string &filename) const throw (Core::Exception) { std::FILE *file = std::fopen(filename.c_str(), "w"); if(!file) throw Core::Exception(Core::Exception::INTERNAL_ERRNO, errno); if(!xmlDocDump(file, doc)) throw Core::Exception(Core::Exception::NOT_AVAILABLE); std::fclose(file); } } }