xoreos  0.0.5
xml.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <cstdarg>
26 #include <cstdio>
27 
28 #include <libxml/parser.h>
29 #include <libxml/xmlerror.h>
30 
31 #include <boost/scope_exit.hpp>
32 
33 #include "src/common/xml.h"
34 #include "src/common/util.h"
35 #include "src/common/error.h"
36 #include "src/common/readstream.h"
37 
38 namespace Common {
39 
40 static void errorFuncUString(void *ctx, const char *msg, ...) {
41  UString *str = static_cast<UString *>(ctx);
42  assert(str);
43 
44  char buf[STRINGBUFLEN];
45  va_list va;
46 
47  va_start(va, msg);
48  vsnprintf(buf, STRINGBUFLEN, msg, va);
49  va_end(va);
50 
51  *str += buf;
52 }
53 
54 static int readStream(void *context, char *buffer, int len) {
55  ReadStream *stream = static_cast<ReadStream *>(context);
56  if (!stream)
57  return -1;
58 
59  return stream->read(buffer, len);
60 }
61 
62 static int closeStream(void *UNUSED(context)) {
63  return 0;
64 }
65 
66 void initXML() {
67  // Initialize libxml2 and make sure the library version matches
68  LIBXML_TEST_VERSION
69 }
70 
71 void deinitXML() {
72  xmlCleanupParser();
73 }
74 
75 XMLParser::XMLParser(ReadStream &stream, bool makeLower, const UString &fileName) {
76  UString parseError;
77  xmlSetGenericErrorFunc(static_cast<void *>(&parseError), errorFuncUString);
78 
79  const int options = XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS | XML_PARSE_NONET |
80  XML_PARSE_NSCLEAN | XML_PARSE_NOCDATA;
81 
82  xmlDocPtr xml = xmlReadIO(readStream, closeStream, static_cast<void *>(&stream),
83  fileName.c_str(), 0, options);
84  if (!xml) {
85  Exception e;
86 
87  if (!parseError.empty())
88  e.add("%s", parseError.c_str());
89 
90  e.add("XML document failed to parse");
91  throw e;
92  }
93 
94  BOOST_SCOPE_EXIT( (&xml) ) {
95  xmlFreeDoc(xml);
96  } BOOST_SCOPE_EXIT_END
97 
98  xmlNodePtr root = xmlDocGetRootElement(xml);
99  if (!root)
100  throw Exception("XML document has no root node");
101 
102  _rootNode.reset(new XMLNode(*root, makeLower));
103 }
104 
106 }
107 
108 const XMLNode &XMLParser::getRoot() const {
109  return *_rootNode;
110 }
111 
112 
113 XMLNode::XMLNode(_xmlNode &node, bool makeLower, XMLNode *parent) : _parent(parent) {
114  load(node, makeLower);
115 }
116 
118 }
119 
120 const UString &XMLNode::getName() const {
121  return _name;
122 }
123 
124 const UString &XMLNode::getContent() const {
125  return _content;
126 }
127 
128 const XMLNode *XMLNode::getParent() const {
129  return _parent;
130 }
131 
133  return _children;
134 }
135 
136 const XMLNode *XMLNode::findChild(const UString &name) const {
137  ChildMap::const_iterator child = _childMap.find(name);
138  if (child != _childMap.end())
139  return child->second;
140 
141  return 0;
142 }
143 
145  return _properties;
146 }
147 
148 UString XMLNode::getProperty(const UString &name, const UString &def) const {
149  Properties::const_iterator property = _properties.find(name);
150  if (property != _properties.end())
151  return property->second;
152 
153  return def;
154 }
155 
156 void XMLNode::load(_xmlNode &node, bool makeLower) {
157  _name = node.name ? reinterpret_cast<const char *>(node.name) : "";
158  _content = node.content ? reinterpret_cast<const char *>(node.content) : "";
159 
160  if (makeLower)
161  _name.makeLower();
162 
163  for (xmlAttrPtr attrib = node.properties; attrib; attrib = attrib->next) {
164  UString name (attrib->name ? reinterpret_cast<const char *>(attrib->name) : "");
165  UString value(attrib->children ? reinterpret_cast<const char *>(attrib->children->content) : "");
166 
167  if (makeLower)
168  name.makeLower();
169 
170  _properties.insert(std::make_pair(name, value));
171  }
172 
173  for (xmlNodePtr child = node.children; child; child = child->next) {
174  _children.push_back(new XMLNode(*child, makeLower, this));
175 
176  _childMap.insert(std::make_pair(_children.back()->getName(), _children.back()));
177  }
178 }
179 
180 } // End of namespace Common
void add(const char *s,...) GCC_PRINTF(2
Definition: error.cpp:58
UString _content
Definition: xml.h:96
Generic interface for a readable data stream.
Definition: readstream.h:64
Definition: 2dafile.h:39
static int readStream(void *context, char *buffer, int len)
Definition: xml.cpp:54
A class holding an UTF-8 string.
Definition: ustring.h:48
const UString & getName() const
Definition: xml.cpp:120
const XMLNode * getParent() const
Return the parent node, or 0 if this is the root node.
Definition: xml.cpp:128
const Children & getChildren() const
Return a list of children.
Definition: xml.cpp:132
std::map< UString, UString > Properties
Definition: xml.h:71
Exception that provides a stack of explanations.
Definition: error.h:36
XMLNode * _parent
Definition: xml.h:98
Basic exceptions to throw.
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
Properties _properties
Definition: xml.h:103
#define UNUSED(x)
Definition: system.h:170
Utility templates and functions.
static void errorFuncUString(void *ctx, const char *msg,...)
Definition: xml.cpp:40
const Properties & getProperties() const
Return all the properties on this node.
Definition: xml.cpp:144
Children _children
Definition: xml.h:100
virtual size_t read(void *dataPtr, size_t dataSize)=0
Read data from the stream.
XML parsing helpers, using libxml2.
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
StackException Exception
Definition: error.h:59
ChildMap _childMap
Definition: xml.h:101
UString getProperty(const UString &name, const UString &def="") const
Return a certain property on this node.
Definition: xml.cpp:148
Basic reading stream interfaces.
UString _name
Definition: xml.h:95
const XMLNode * findChild(const UString &name) const
Find a child node by name.
Definition: xml.cpp:136
void deinitXML()
Deinitialize the XML subsystem.
Definition: xml.cpp:71
#define STRINGBUFLEN
Definition: system.h:415
XMLParser(ReadStream &stream, bool makeLower=false, const UString &fileName="stream.xml")
Parse an XML file out of a stream.
Definition: xml.cpp:75
const UString & getContent() const
Definition: xml.cpp:124
const XMLNode & getRoot() const
Return the XML root node.
Definition: xml.cpp:108
void initXML()
Initialize the XML subsystem.
Definition: xml.cpp:66
static int closeStream(void *context)
Definition: xml.cpp:62
XMLNode(_xmlNode &node, bool makeLower=false, XMLNode *parent=0)
Definition: xml.cpp:113
void load(_xmlNode &node, bool makeLower)
Definition: xml.cpp:156
void makeLower()
Convert the string to lowercase.
Definition: ustring.cpp:473
ScopedPtr< XMLNode > _rootNode
Definition: xml.h:66