/* * XmlProcessor.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 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include #include "XmlPacket.h" #include "Base64Encoder.h" #include #include namespace Mad { namespace Common { XmlPacket::Entry XmlPacket::Element::nilEntry(0); XmlPacket::Element XmlPacket::Entry::nilElement(0); void XmlPacket::Element::updateStr() { if(type == NONE || type == LIST) return; if(type == BINARY) { str = Base64Encoder::encode(std::vector((boost::uint8_t*)binData, ((boost::uint8_t*)binData)+value.var_size)); } else if(type != STRING) { std::ostringstream buf; switch(type) { case INT: buf << value.var_int; break; case UINT: buf << value.var_uint; break; case INT64: buf << value.var_int64; break; case UINT64: buf << value.var_uint64; break; case FLOAT: buf << value.var_float; break; case DOUBLE: buf << value.var_double; break; case LONGDOUBLE: buf << value.var_ldouble; default: break; } str = buf.str(); } xmlNodePtr newNode = xmlNewText((xmlChar*)str.c_str()); xmlNodePtr oldNode = elementNode->children; xmlReplaceNode(oldNode, newNode); xmlFreeNode(oldNode); } XmlPacket::Element::Element(xmlNodePtr node) : elementNode(node), binData(0), 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; if(!xmlStrcmp(typestr, (xmlChar*)"binary")) { type = BINARY; std::vector v = Base64Encoder::decode(str); value.var_size = v.size(); binData = std::malloc(value.var_size); std::memcpy(binData, v.data(), value.var_size); } else if(!xmlStrcmp(typestr, (xmlChar*)"int")) { type = INT; value.var_int = std::strtol((char*)content, 0, 10); } else if(!xmlStrcmp(typestr, (xmlChar*)"uint")) { type = UINT; value.var_uint = std::strtoul((char*)content, 0, 10); } else if(!xmlStrcmp(typestr, (xmlChar*)"int64")) { type = INT64; value.var_int64 = std::strtoll((char*)content, 0, 10); } else if(!xmlStrcmp(typestr, (xmlChar*)"uint64")) { type = UINT64; value.var_uint64 = std::strtoull((char*)content, 0, 10); } else if(!xmlStrcmp(typestr, (xmlChar*)"float")) { type = FLOAT; value.var_float = std::strtof((char*)content, 0); } else if(!xmlStrcmp(typestr, (xmlChar*)"double")) { type = DOUBLE; value.var_double = std::strtod((char*)content, 0); } else if(!xmlStrcmp(typestr, (xmlChar*)"longdouble")) { type = LONGDOUBLE; value.var_ldouble = std::strtold((char*)content, 0); } else if(!xmlStrcmp(typestr, (xmlChar*)"string")) { type = STRING; } xmlFree(typestr); xmlFree(content); updateStr(); } XmlPacket::Element::~Element() { if(binData) std::free(binData); } void XmlPacket::Element::setBinaryData(const void *data, size_t size) { if(type != BINARY) return; if(binData) std::free(binData); binData = std::malloc(size); std::memcpy(binData, data, size); updateStr(); } XmlPacket::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); } } XmlPacket::Entry::~Entry() { for(std::map::iterator element = elements.begin(); element != elements.end(); ++element) delete element->second; for(std::map::iterator list = lists.begin(); list != lists.end(); ++list) delete list->second; } XmlPacket::Element& XmlPacket::Entry::operator[](const std::string &name) { std::map::iterator it = elements.find(name); if(it != elements.end()) return *it->second; std::map::iterator it2 = lists.find(name); if(it2 != lists.end()) return *it2->second; return nilElement; } const XmlPacket::Element& XmlPacket::Entry::operator[](const std::string &name) const { std::map::const_iterator it = elements.find(name); if(it != elements.end()) return *it->second; std::map::const_iterator it2 = lists.find(name); if(it2 != lists.end()) return *it2->second; return nilElement; } bool XmlPacket::Entry::addBinary(const std::string &name, const void *data, size_t size) { if(!entryNode) return false; if(elements.find(name) != elements.end() || lists.find(name) != lists.end()) return false; std::string base64Data = Base64Encoder::encode(std::vector((boost::uint8_t*)data, ((boost::uint8_t*)data)+size));; return add(name, base64Data, "binary"); } XmlPacket::List::List(xmlNodePtr node) : Element(node, LIST) { 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)); } } XmlPacket::List::~List() { for(std::vector::iterator entry = entries.begin(); entry != entries.end(); ++entry) delete *entry; } XmlPacket::XmlPacket() { doc = xmlNewDoc((xmlChar*)"1.0"); packetNode = xmlNewNode(0, (xmlChar*)"packet"); xmlDocSetRootElement(doc, packetNode); entry = new Entry(packetNode); } XmlPacket::XmlPacket(const XmlPacket &o) { doc = xmlCopyDoc(o.doc, 1); packetNode = xmlDocGetRootElement(doc); entry = new Entry(packetNode); } XmlPacket::XmlPacket(const Net::Packet &packet) { doc = xmlParseMemory((const char*)packet.getData(), packet.getLength()); packetNode = xmlDocGetRootElement(doc); entry = new Entry(packetNode); } XmlPacket& XmlPacket::operator=(const XmlPacket &o) { delete entry; xmlFreeDoc(doc); doc = xmlCopyDoc(o.doc, 1); packetNode = xmlDocGetRootElement(doc); entry = new Entry(packetNode); return *this; } std::string XmlPacket::getType() const { xmlChar *type = xmlGetProp(packetNode, (xmlChar*)"type"); std::string ret(type ? (char*)type : ""); xmlFree(type); return ret; } void XmlPacket::setType(const std::string &type) { xmlSetProp(packetNode, (xmlChar*)"type", (xmlChar*)type.c_str()); } Net::Packet XmlPacket::encode(uint16_t requestId) const { xmlChar *buf; int length; xmlDocDumpMemory(doc, &buf, &length); Net::Packet packet(requestId, buf, length); xmlFree(buf); return packet; } } }