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 <fstream>
37 
38 #include "debug.h"
39 
40 namespace
41 {
42  bool valid = false;
43 } // namespace
44 
45 static void xmlErrorLogger(void *ctx A_UNUSED, const char *msg A_UNUSED, ...)
46 #ifdef __GNUC__
47 #ifdef __OpenBSD__
48  __attribute__((__format__(printf, 2, 3)))
49 #else // __OpenBSD__
50  __attribute__((__format__(gnu_printf, 2, 3)))
51 #endif // __OpenBSD__
52 #endif // __GNUC__
53 ;
54 
55 static void xmlErrorLogger(void *ctx A_UNUSED, const char *msg, ...)
56 {
57  if (msg == nullptr)
58  return;
59 
60  size_t size = 1024;
61  const size_t msgSize = strlen(msg);
62  if (msgSize * 3 > size)
63  size = msgSize * 3;
64 
65  char* buf = new char[size + 1];
66  va_list ap;
67 
68  // Use a temporary buffer to fill in the variables
69  va_start(ap, msg);
70  vsnprintf(buf, size, msg, ap);
71  buf[size] = 0;
72  va_end(ap);
73 
74  if (logger != nullptr)
75  logger->log_r("%s", buf);
76  else
77  puts(buf);
78 
79  // Delete temporary buffer
80  delete [] buf;
81  valid = false;
82 }
83 
84 namespace XML
85 {
86  Document::Document(const std::string &filename,
87  const UseVirtFs useResman,
88  const SkipError skipError) :
89  Resource(),
90  mDoc(nullptr),
91  mIsValid(false)
92  {
93 #ifdef USE_FUZZER
94  if (Fuzzer::conditionTerminate(filename.c_str()))
95  return;
96 #endif // USE_FUZZER
97 
98  BLOCK_START("XML::Document::Document")
99  int size = 0;
100  char *data = nullptr;
101  valid = true;
102  if (useResman == UseVirtFs_true)
103  {
104  data = const_cast<char*>(VirtFs::loadFile(
105  filename,
106  size));
107  }
108  else
109  {
110  std::ifstream file;
111  file.open(filename.c_str(), std::ios::in);
112 
113  if (file.is_open())
114  {
115  // Get length of file
116  file.seekg(0, std::ios::end);
117  size = CAST_S32(file.tellg());
118  if (size < 0)
119  {
120  reportAlways("Error loading XML file %s",
121  filename.c_str())
122  }
123  else
124  {
125  file.seekg(0, std::ios::beg);
126  data = new char[size];
127  file.read(data, size);
128  }
129  file.close();
130  }
131  else if (skipError == SkipError_false)
132  {
133  reportAlways("Error loading XML file %s",
134  filename.c_str())
135  }
136  }
137 
138  if (data != nullptr)
139  {
140  mDoc = xmlParseMemory(data, size);
141  delete [] data;
142 
143  if (mDoc == nullptr)
144  {
145  reportAlways("Error parsing XML file %s", filename.c_str())
146  }
147  }
148  else if (skipError == SkipError_false)
149  {
150  reportAlways("Error loading XML file %s", filename.c_str())
151  }
152  mIsValid = valid;
153  BLOCK_END("XML::Document::Document")
154  }
155 
156  Document::Document(const char *const data, const int size) :
157  mDoc(data != nullptr ? xmlParseMemory(data, size) : nullptr),
158  mIsValid(true)
159  {
160  }
161 
163  {
164  if (mDoc != nullptr)
165  xmlFreeDoc(mDoc);
166  }
167 
168  XmlNodePtr Document::rootNode()
169  {
170  return mDoc != nullptr ? xmlDocGetRootElement(mDoc) : nullptr;
171  }
172 
173  int getProperty(XmlNodeConstPtr node,
174  const char *const name,
175  int def)
176  {
177  int &ret = def;
178 
179  xmlChar *const prop = XmlGetProp(node, name);
180  if (prop != nullptr)
181  {
182  ret = atoi(reinterpret_cast<const char*>(prop));
183  xmlFree(prop);
184  }
185 
186  return ret;
187  }
188 
189  int getIntProperty(XmlNodeConstPtr node,
190  const char *const name,
191  int def,
192  const int min,
193  const int max)
194  {
195  int &ret = def;
196 
197  xmlChar *const prop = XmlGetProp(node, name);
198  if (prop != nullptr)
199  {
200  ret = atoi(reinterpret_cast<char*>(prop));
201  xmlFree(prop);
202  }
203  if (ret < min)
204  ret = min;
205  else if (ret > max)
206  ret = max;
207  return ret;
208  }
209 
210  float getFloatProperty(XmlNodeConstPtr node,
211  const char *const name,
212  float def)
213  {
214  float &ret = def;
215 
216  xmlChar *const prop = XmlGetProp(node, name);
217  if (prop != nullptr)
218  {
219  ret = static_cast<float>(atof(reinterpret_cast<char*>(prop)));
220  xmlFree(prop);
221  }
222 
223  return ret;
224  }
225 
226  double getDoubleProperty(XmlNodeConstPtr node,
227  const char *const name,
228  double def)
229  {
230  double &ret = def;
231 
232  xmlChar *const prop = XmlGetProp(node, name);
233  if (prop != nullptr)
234  {
235  ret = atof(reinterpret_cast<char*>(prop));
236  xmlFree(prop);
237  }
238 
239  return ret;
240  }
241 
242  std::string getProperty(XmlNodeConstPtr node,
243  const char *const name,
244  const std::string &def)
245  {
246  xmlChar *const prop = XmlGetProp(node, name);
247  if (prop != nullptr)
248  {
249  std::string val = reinterpret_cast<char*>(prop);
250  xmlFree(prop);
251  return val;
252  }
253 
254  return def;
255  }
256 
257  std::string langProperty(XmlNodeConstPtr node,
258  const char *const name,
259  const std::string &def)
260  {
261  std::string str = getProperty(node, name, def);
262  if (translator == nullptr)
263  return str;
264 
265  return translator->getStr(str);
266  }
267 
268  bool getBoolProperty(XmlNodeConstPtr node,
269  const char *const name,
270  const bool def)
271  {
272  xmlChar *const prop = XmlGetProp(node, name);
273 
274  if (XmlStrEqual(prop, "true"))
275  {
276  XmlFree(prop);
277  return true;
278  }
279  if (XmlStrEqual(prop, "false"))
280  {
281  XmlFree(prop);
282  return false;
283  }
284  XmlFree(prop);
285  return def;
286  }
287 
288  XmlNodePtr findFirstChildByName(XmlNodeConstPtrConst parent,
289  const char *const name)
290  {
291  if (parent == nullptr)
292  return nullptr;
293  for_each_xml_child_node(child, parent)
294  {
295  if (xmlNameEqual(child, name))
296  return child;
297  }
298 
299  return nullptr;
300  }
301 
302  // Initialize libxml2 and check for potential ABI mismatches between
303  // compiled version and the shared library actually used.
304  void initXML()
305  {
306  xmlInitParser();
307  LIBXML_TEST_VERSION
308 
309  // Suppress libxml2 error messages
310  xmlSetGenericErrorFunc(nullptr, &xmlErrorLogger);
311  }
312 
313  // Shutdown libxml
314  void cleanupXML()
315  {
316  xmlCleanupParser();
317  }
318 
319  bool Document::validateXml(const std::string &fileName)
320  {
321  const xmlDocPtr doc = xmlReadFile(fileName.c_str(),
322  nullptr, XML_PARSE_PEDANTIC);
323  const bool valid1(doc != nullptr);
324  xmlFreeDoc(doc);
325  if (!valid1)
326  return false;
327 
328  std::ifstream file;
329  file.open(fileName.c_str(), std::ios::in);
330  if (!file.is_open())
331  {
332  file.close();
333  return false;
334  }
335  char line[101];
336  if (!file.getline(line, 100))
337  return false;
338  file.close();
339 
340  const std::string str = line;
341  if (!strStartWith(str, "<?xml "))
342  return false;
343 
344  return true;
345  }
346 } // namespace XML
347 
348 #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:304
EAthena::ItemHandler __attribute__
float getFloatProperty(const xmlNodePtr node, const char *const name, float def)
Definition: libxml.cpp:210
std::string fileName
Definition: testmain.cpp:38
#define BLOCK_START(name)
Definition: perfomance.h:78
int getProperty(const xmlNodePtr node, const char *const name, int def)
Definition: libxml.cpp:173
#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:360
xmlDocPtr mDoc
Definition: libxml.h:94
Logger * logger
Definition: logger.cpp:88
#define gnu_printf
Definition: localconsts.h:162
int getIntProperty(const xmlNodePtr node, const char *const name, int def, const int min, const int max)
Definition: libxml.cpp:189
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:288
bool getBoolProperty(const xmlNodePtr node, const char *const name, const bool def)
Definition: libxml.cpp:268
Definition: libxml.cpp:84
uint32_t data
double getDoubleProperty(const xmlNodePtr node, const char *const name, double def)
Definition: libxml.cpp:226
static bool validateXml(const std::string &fileName)
Definition: libxml.cpp:319
Document(const std::string &filename, const UseVirtFs useResman, const SkipError skipError)
Definition: libxml.cpp:86
#define nullptr
Definition: localconsts.h:44
const char * loadFile(std::string filename, int &fileSize)
Definition: fs.cpp:858
xmlNodePtr rootNode()
Definition: libxml.cpp:168
std::string langProperty(const xmlNodePtr node, const char *const name, const std::string &def)
Definition: libxml.cpp:257
#define A_UNUSED
Definition: localconsts.h:159
#define for_each_xml_child_node(var, parent)
Definition: libxml.h:160
void cleanupXML()
Definition: libxml.cpp:314
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:55