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