ManaPlus
libxml.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2018 The ManaPlus Developers
6  *
7  * This file is part of The ManaPlus Client.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #ifdef ENABLE_LIBXML
24 
25 #include "utils/xml/libxml.h"
26 
27 #include "fs/virtfs/fs.h"
28 
29 #include "utils/cast.h"
30 #include "utils/checkutils.h"
31 #include "utils/fuzzer.h"
32 #include "utils/stringutils.h"
33 
35 
36 #include "debug.h"
37 
38 namespace
39 {
40  bool valid = false;
41 } // namespace
42 
43 static void xmlErrorLogger(void *ctx A_UNUSED, const char *msg A_UNUSED, ...)
44 #ifdef __GNUC__
45 #ifdef __OpenBSD__
46  __attribute__((__format__(printf, 2, 3)))
47 #else // __OpenBSD__
48  __attribute__((__format__(gnu_printf, 2, 3)))
49 #endif // __OpenBSD__
50 #endif // __GNUC__
51 ;
52 
53 static void xmlErrorLogger(void *ctx A_UNUSED, const char *msg, ...)
54 {
55  if (msg == nullptr)
56  return;
57 
58  size_t size = 1024;
59  const size_t msgSize = strlen(msg);
60  if (msgSize * 3 > size)
61  size = msgSize * 3;
62 
63  char* buf = new char[size + 1];
64  va_list ap;
65 
66  // Use a temporary buffer to fill in the variables
67  va_start(ap, msg);
68  vsnprintf(buf, size, msg, ap);
69  buf[size] = 0;
70  va_end(ap);
71 
72  if (logger != nullptr)
73  logger->log_r("%s", buf);
74  else
75  puts(buf);
76 
77  // Delete temporary buffer
78  delete [] buf;
79  valid = false;
80 }
81 
82 namespace XML
83 {
84  Document::Document(const std::string &filename,
85  const UseVirtFs useResman,
86  const SkipError skipError) :
87  Resource(),
88  mDoc(nullptr),
89  mIsValid(false)
90  {
91 #ifdef USE_FUZZER
92  if (Fuzzer::conditionTerminate(filename.c_str()))
93  return;
94 #endif // USE_FUZZER
95 
96  BLOCK_START("XML::Document::Document")
97  int size = 0;
98  char *data = nullptr;
99  valid = true;
100  if (useResman == UseVirtFs_true)
101  {
102  data = const_cast<char*>(VirtFs::loadFile(
103  filename,
104  size));
105  }
106  else
107  {
108  std::ifstream file;
109  file.open(filename.c_str(), std::ios::in);
110 
111  if (file.is_open())
112  {
113  // Get length of file
114  file.seekg(0, std::ios::end);
115  size = CAST_S32(file.tellg());
116  if (size < 0)
117  {
118  reportAlways("Error loading XML file %s",
119  filename.c_str());
120  }
121  else
122  {
123  file.seekg(0, std::ios::beg);
124  data = new char[size];
125  file.read(data, size);
126  }
127  file.close();
128  }
129  else if (skipError == SkipError_false)
130  {
131  reportAlways("Error loading XML file %s",
132  filename.c_str());
133  }
134  }
135 
136  if (data != nullptr)
137  {
138  mDoc = xmlParseMemory(data, size);
139  delete [] data;
140 
141  if (mDoc == nullptr)
142  {
143  reportAlways("Error parsing XML file %s", filename.c_str());
144  }
145  }
146  else if (skipError == SkipError_false)
147  {
148  reportAlways("Error loading XML file %s", filename.c_str());
149  }
150  mIsValid = valid;
151  BLOCK_END("XML::Document::Document")
152  }
153 
154  Document::Document(const char *const data, const int size) :
155  mDoc(data != nullptr ? xmlParseMemory(data, size) : nullptr),
156  mIsValid(true)
157  {
158  }
159 
161  {
162  if (mDoc != nullptr)
163  xmlFreeDoc(mDoc);
164  }
165 
166  XmlNodePtr Document::rootNode()
167  {
168  return mDoc != nullptr ? xmlDocGetRootElement(mDoc) : nullptr;
169  }
170 
171  int getProperty(XmlNodeConstPtr node,
172  const char *const name,
173  int def)
174  {
175  int &ret = def;
176 
177  xmlChar *const prop = XmlGetProp(node, name);
178  if (prop != nullptr)
179  {
180  ret = atoi(reinterpret_cast<const char*>(prop));
181  xmlFree(prop);
182  }
183 
184  return ret;
185  }
186 
187  int getIntProperty(XmlNodeConstPtr node,
188  const char *const name,
189  int def,
190  const int min,
191  const int max)
192  {
193  int &ret = def;
194 
195  xmlChar *const prop = XmlGetProp(node, name);
196  if (prop != nullptr)
197  {
198  ret = atoi(reinterpret_cast<char*>(prop));
199  xmlFree(prop);
200  }
201  if (ret < min)
202  ret = min;
203  else if (ret > max)
204  ret = max;
205  return ret;
206  }
207 
208  float getFloatProperty(XmlNodeConstPtr node,
209  const char *const name,
210  float def)
211  {
212  float &ret = def;
213 
214  xmlChar *const prop = XmlGetProp(node, name);
215  if (prop != nullptr)
216  {
217  ret = static_cast<float>(atof(reinterpret_cast<char*>(prop)));
218  xmlFree(prop);
219  }
220 
221  return ret;
222  }
223 
224  double getDoubleProperty(XmlNodeConstPtr node,
225  const char *const name,
226  double def)
227  {
228  double &ret = def;
229 
230  xmlChar *const prop = XmlGetProp(node, name);
231  if (prop != nullptr)
232  {
233  ret = atof(reinterpret_cast<char*>(prop));
234  xmlFree(prop);
235  }
236 
237  return ret;
238  }
239 
240  std::string getProperty(XmlNodeConstPtr node,
241  const char *const name,
242  const std::string &def)
243  {
244  xmlChar *const prop = XmlGetProp(node, name);
245  if (prop != nullptr)
246  {
247  std::string val = reinterpret_cast<char*>(prop);
248  xmlFree(prop);
249  return val;
250  }
251 
252  return def;
253  }
254 
255  std::string langProperty(XmlNodeConstPtr node,
256  const char *const name,
257  const std::string &def)
258  {
259  std::string str = getProperty(node, name, def);
260  if (translator == nullptr)
261  return str;
262 
263  return translator->getStr(str);
264  }
265 
266  bool getBoolProperty(XmlNodeConstPtr node,
267  const char *const name,
268  const bool def)
269  {
270  xmlChar *const prop = XmlGetProp(node, name);
271 
272  if (XmlStrEqual(prop, "true"))
273  {
274  XmlFree(prop);
275  return true;
276  }
277  if (XmlStrEqual(prop, "false"))
278  {
279  XmlFree(prop);
280  return false;
281  }
282  XmlFree(prop);
283  return def;
284  }
285 
286  XmlNodePtr findFirstChildByName(XmlNodeConstPtrConst parent,
287  const char *const name)
288  {
289  if (parent == nullptr)
290  return nullptr;
291  for_each_xml_child_node(child, parent)
292  {
293  if (xmlNameEqual(child, name))
294  return child;
295  }
296 
297  return nullptr;
298  }
299 
300  // Initialize libxml2 and check for potential ABI mismatches between
301  // compiled version and the shared library actually used.
302  void initXML()
303  {
304  xmlInitParser();
305  LIBXML_TEST_VERSION;
306 
307  // Suppress libxml2 error messages
308  xmlSetGenericErrorFunc(nullptr, &xmlErrorLogger);
309  }
310 
311  // Shutdown libxml
312  void cleanupXML()
313  {
314  xmlCleanupParser();
315  }
316 
317  bool Document::validateXml(const std::string &fileName)
318  {
319  const xmlDocPtr doc = xmlReadFile(fileName.c_str(),
320  nullptr, XML_PARSE_PEDANTIC);
321  const bool valid1(doc != nullptr);
322  xmlFreeDoc(doc);
323  if (!valid1)
324  return false;
325 
326  std::ifstream file;
327  file.open(fileName.c_str(), std::ios::in);
328  if (!file.is_open())
329  {
330  file.close();
331  return false;
332  }
333  char line[101];
334  if (!file.getline(line, 100))
335  return false;
336  file.close();
337 
338  const std::string str = line;
339  if (!strStartWith(str, "<?xml "))
340  return false;
341 
342  return true;
343  }
344 } // namespace XML
345 
346 #endif // ENABLE_LIBXML
bool strStartWith(const std::string &str1, const std::string &str2)
bool mIsValid
Definition: libxml.h:95
const bool SkipError_false
Definition: skiperror.h:29
void initXML()
Definition: libxml.cpp:302
EAthena::ItemHandler __attribute__
float getFloatProperty(const xmlNodePtr node, const char *const name, float def)
Definition: libxml.cpp:208
std::string fileName
Definition: testmain.cpp:36
#define BLOCK_START(name)
Definition: perfomance.h:78
int getProperty(const xmlNodePtr node, const char *const name, int def)
Definition: libxml.cpp:171
#define BLOCK_END(name)
Definition: perfomance.h:79
bool msg(InputEvent &event)
Definition: chat.cpp:38
void log_r(const char *const log_text,...)
Definition: logger.cpp:319
xmlDocPtr mDoc
Definition: libxml.h:94
Logger * logger
Definition: logger.cpp:95
#define gnu_printf
Definition: localconsts.h:174
int getIntProperty(const xmlNodePtr node, const char *const name, int def, const int min, const int max)
Definition: libxml.cpp:187
const bool UseVirtFs_true
Definition: usevirtfs.h:29
#define CAST_S32
Definition: cast.h:29
xmlNodePtr findFirstChildByName(const xmlNode *const parent, const char *const name)
Definition: libxml.cpp:286
bool getBoolProperty(const xmlNodePtr node, const char *const name, const bool def)
Definition: libxml.cpp:266
Definition: libxml.cpp:82
uint32_t data
double getDoubleProperty(const xmlNodePtr node, const char *const name, double def)
Definition: libxml.cpp:224
static bool validateXml(const std::string &fileName)
Definition: libxml.cpp:317
Document(const std::string &filename, const UseVirtFs useResman, const SkipError skipError)
Definition: libxml.cpp:84
#define nullptr
Definition: localconsts.h:44
const char * loadFile(std::string filename, int &fileSize)
Definition: fs.cpp:858
xmlNodePtr rootNode()
Definition: libxml.cpp:166
std::string langProperty(const xmlNodePtr node, const char *const name, const std::string &def)
Definition: libxml.cpp:255
#define A_UNUSED
Definition: localconsts.h:171
#define for_each_xml_child_node(var, parent)
Definition: libxml.h:160
void cleanupXML()
Definition: libxml.cpp:312
const std::string getStr(const std::string &str)
Definition: podict.cpp:44
PoDict * translator
Definition: podict.cpp:27
#define reportAlways(...)
Definition: checkutils.h:252
static void xmlErrorLogger(void *ctx, const char *msg,...)
Definition: libxml.cpp:53