1 /**
2  * @file
3  * @brief UFO:AI interface functions to mxml
4  */
5 
6 /*
7 Copyright (C) 2002-2013 UFO: Alien Invasion.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) 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.
17 
18 See the 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, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 
24 */
25 
26 #include "xml.h"
27 #include "../shared/cxx.h"
28 
29 /**
30  * @brief add a String attribute to the XML Node
31  * @param[out] parent XML Node structure to add to
32  * @param[in] name Name of the attribute
33  * @param[in] value Value of the attribute
34  */
XML_AddString(xmlNode_t * parent,const char * name,const char * value)35 void XML_AddString (xmlNode_t* parent, const char* name, const char* value)
36 {
37 	if (value)
38 		mxmlElementSetAttr(parent, name, value);
39 }
40 
41 /**
42  * @brief add a non-empty String attribute to the XML Node
43  * @param[out] parent XML Node structure to add to
44  * @param[in] name Name of the attribute
45  * @param[in] value Value of the attribute
46  * @note if the value is empty nothing will be added
47  */
XML_AddStringValue(xmlNode_t * parent,const char * name,const char * value)48 void XML_AddStringValue (xmlNode_t* parent, const char* name, const char* value)
49 {
50 	if (value && value[0] != '\0')
51 		mxmlElementSetAttr(parent, name, value);
52 }
53 
54 /**
55  * @brief add a Boolean attribute to the XML Node
56  * @param[out] parent XML Node structure to add to
57  * @param[in] name Name of the attribute
58  * @param[in] value Value of the attribute
59  */
XML_AddBool(xmlNode_t * parent,const char * name,bool value)60 void XML_AddBool (xmlNode_t* parent, const char* name, bool value)
61 {
62 	mxmlElementSetAttr(parent, name, value ? "true" : "false");
63 }
64 
65 /**
66  * @brief add a non-false Boolean attribute to the XML Node
67  * @param[out] parent XML Node structure to add to
68  * @param[in] name Name of the attribute
69  * @param[in] value Value of the attribute
70  * @note if the value is false nothing will be added
71  */
XML_AddBoolValue(xmlNode_t * parent,const char * name,bool value)72 void XML_AddBoolValue (xmlNode_t* parent, const char* name, bool value)
73 {
74 	if (value)
75 		mxmlElementSetAttr(parent, name, "true");
76 }
77 
78 /**
79  * @brief add a Float attribute to the XML Node
80  * @param[out] parent XML Node structure to add to
81  * @param[in] name Name of the attribute
82  * @param[in] value Value of the attribute
83  */
XML_AddFloat(xmlNode_t * parent,const char * name,float value)84 void XML_AddFloat (xmlNode_t* parent, const char* name, float value)
85 {
86 	XML_AddDouble(parent, name, value);
87 }
88 
89 /**
90  * @brief add a non-zero Float attribute to the XML Node
91  * @param[out] parent XML Node structure to add to
92  * @param[in] name Name of the attribute
93  * @param[in] value Value of the attribute
94  * @note if the value is zero nothing will be added
95  */
XML_AddFloatValue(xmlNode_t * parent,const char * name,float value)96 void XML_AddFloatValue (xmlNode_t* parent, const char* name, float value)
97 {
98 	XML_AddDoubleValue(parent, name, value);
99 }
100 
101 /**
102  * @brief add a Double attribute to the XML Node
103  * @param[out] parent XML Node structure to add to
104  * @param[in] name Name of the attribute
105  * @param[in] value Value of the attribute
106  */
XML_AddDouble(xmlNode_t * parent,const char * name,double value)107 void XML_AddDouble (xmlNode_t* parent, const char* name, double value)
108 {
109 	char txt[50];
110 	snprintf(txt, sizeof(txt), "%f", value);
111 	mxmlElementSetAttr(parent, name, txt);
112 }
113 
114 /**
115  * @brief add a non-zero Double attribute to the XML Node
116  * @param[out] parent XML Node structure to add to
117  * @param[in] name Name of the attribute
118  * @param[in] value Value of the attribute
119  * @note if the value is zero nothing will be added
120  */
XML_AddDoubleValue(xmlNode_t * parent,const char * name,double value)121 void XML_AddDoubleValue (xmlNode_t* parent, const char* name, double value)
122 {
123 	if (value) {
124 		char txt[50];
125 		snprintf(txt, sizeof(txt), "%f", value);
126 		mxmlElementSetAttr(parent, name, txt);
127 	}
128 }
129 
130 /**
131  * @brief add a Byte attribute to the XML Node
132  * @param[out] parent XML Node structure to add to
133  * @param[in] name Name of the attribute
134  * @param[in] value Value of the attribute
135  */
XML_AddByte(xmlNode_t * parent,const char * name,byte value)136 void XML_AddByte (xmlNode_t* parent, const char* name, byte value)
137 {
138 	XML_AddLong(parent, name, value);
139 }
140 
141 /**
142  * @brief add a non-zero Byte attribute to the XML Node
143  * @param[out] parent XML Node structure to add to
144  * @param[in] name Name of the attribute
145  * @param[in] value Value of the attribute
146  * @note if the value is zero nothing will be added
147  */
XML_AddByteValue(xmlNode_t * parent,const char * name,byte value)148 void XML_AddByteValue (xmlNode_t* parent, const char* name, byte value)
149 {
150 	XML_AddLongValue(parent, name, value);
151 }
152 
153 /**
154  * @brief add a Short attribute to the XML Node
155  * @param[out] parent XML Node structure to add to
156  * @param[in] name Name of the attribute
157  * @param[in] value Value of the attribute
158  */
XML_AddShort(xmlNode_t * parent,const char * name,short value)159 void XML_AddShort (xmlNode_t* parent, const char* name, short value)
160 {
161 	XML_AddLong(parent, name, value);
162 }
163 
164 /**
165  * @brief add a non-zero Short attribute to the XML Node
166  * @param[out] parent XML Node structure to add to
167  * @param[in] name Name of the attribute
168  * @param[in] value Value of the attribute
169  * @note if the value is zero nothing will be added
170  */
XML_AddShortValue(xmlNode_t * parent,const char * name,short value)171 void XML_AddShortValue (xmlNode_t* parent, const char* name, short value)
172 {
173 	XML_AddLongValue(parent, name, value);
174 }
175 
176 /**
177  * @brief add an Int attribute to the XML Node
178  * @param[out] parent XML Node structure to add to
179  * @param[in] name Name of the attribute
180  * @param[in] value Value of the attribute
181  */
XML_AddInt(xmlNode_t * parent,const char * name,int value)182 void XML_AddInt (xmlNode_t* parent, const char* name, int value)
183 {
184 	XML_AddLong(parent, name, value);
185 }
186 
187 /**
188  * @brief add a non-zero Int attribute to the XML Node
189  * @param[out] parent XML Node structure to add to
190  * @param[in] name Name of the attribute
191  * @param[in] value Value of the attribute
192  * @note if the value is zero nothing will be added
193  */
XML_AddIntValue(xmlNode_t * parent,const char * name,int value)194 void XML_AddIntValue (xmlNode_t* parent, const char* name, int value)
195 {
196 	XML_AddLongValue(parent, name, value);
197 }
198 
199 /**
200  * @brief add a Long attribute to the XML Node
201  * @param[out] parent XML Node structure to add to
202  * @param[in] name Name of the attribute
203  * @param[in] value Value of the attribute
204  */
XML_AddLong(xmlNode_t * parent,const char * name,long value)205 void XML_AddLong (xmlNode_t* parent, const char* name, long value)
206 {
207 	char txt[50];
208 	snprintf(txt, sizeof(txt), "%ld", value);
209 	mxmlElementSetAttr(parent, name, txt);
210 }
211 
212 /**
213  * @brief add a non-zero Long attribute to the XML Node
214  * @param[out] parent XML Node structure to add to
215  * @param[in] name Name of the attribute
216  * @param[in] value Value of the attribute
217  * @note if the value is zero nothing will be added
218  */
XML_AddLongValue(xmlNode_t * parent,const char * name,long value)219 void XML_AddLongValue (xmlNode_t* parent, const char* name, long value)
220 {
221 	if (value) {
222 		char txt[50];
223 		snprintf(txt, sizeof(txt), "%ld", value);
224 		mxmlElementSetAttr(parent, name, txt);
225 	}
226 }
227 
228 /**
229  * @brief add a Pos3 data to the XML Tree
230  * @param[out] parent XML Node structure to add to
231  * @param[in] name Name of the node to add
232  * @param[in] pos Pos3 structure with position data
233  * @note it creates a new node and adds coordinate(s) to the node as attributes
234  */
XML_AddPos3(xmlNode_t * parent,const char * name,const vec3_t pos)235 void XML_AddPos3 (xmlNode_t* parent, const char* name, const vec3_t pos)
236 {
237 	xmlNode_t* t;
238 	t = mxmlNewElement(parent, name);
239 	XML_AddFloat(t, "x", pos[0]);
240 	XML_AddFloat(t, "y", pos[1]);
241 	XML_AddFloat(t, "z", pos[2]);
242 }
243 
244 /**
245  * @brief add a Pos2 data to the XML Tree
246  * @param[out] parent XML Node structure to add to
247  * @param[in] name Name of the node to add
248  * @param[in] pos Pos2 structure with position data
249  * @note it creates a new node and adds coordinate(s) to the node as attributes
250  */
XML_AddPos2(xmlNode_t * parent,const char * name,const vec2_t pos)251 void XML_AddPos2 (xmlNode_t* parent, const char* name, const vec2_t pos)
252 {
253 	xmlNode_t* t;
254 	t = mxmlNewElement(parent, name);
255 	XML_AddFloat(t, "x", pos[0]);
256 	XML_AddFloat(t, "y", pos[1]);
257 }
258 
259 /**
260  * @brief add a date data to the XML Tree
261  * @param[out] parent XML Node structure to add to
262  * @param[in] name Name of the node to add
263  * @param[in] day Day part of the date
264  * @param[in] sec Second part of the date
265  * @note it creates a new node and adds day/sec attributes to the node
266  */
XML_AddDate(xmlNode_t * parent,const char * name,const int day,const int sec)267 void XML_AddDate (xmlNode_t* parent, const char* name, const int day, const int sec)
268 {
269 	xmlNode_t* t;
270 	t = mxmlNewElement(parent, name);
271 	XML_AddInt(t, "day", day);
272 	XML_AddInt(t, "sec", sec);
273 }
274 
275 /**
276  * @brief add a new node to the XML tree
277  * @param[out] parent XML Node structure to add to
278  * @param[in] name Name of the new node
279  * return pointer to the new XML Node structure
280  */
XML_AddNode(xmlNode_t * parent,const char * name)281 xmlNode_t* XML_AddNode (xmlNode_t* parent, const char* name)
282 {
283 	return mxmlNewElement(parent,name);
284 }
285 
286 /**
287  * @brief retrieve a Boolean attribute from an XML Node
288  * @param[in] parent XML Node structure to get from
289  * @param[in] name Name of the attribute
290  * @param[in] defaultval Default value to return if no such attribute defined
291  */
XML_GetBool(xmlNode_t * parent,const char * name,const bool defaultval)292 bool XML_GetBool (xmlNode_t* parent, const char* name, const bool defaultval)
293 {
294 	const char* txt;
295 	txt = mxmlElementGetAttr(parent, name);
296 	if (!txt)
297 		return defaultval;
298 
299 	if (!strcmp(txt, "true") || !strcmp(txt, "1"))
300 		return true;
301 	if (!strcmp(txt, "false") || !strcmp(txt, "0"))
302 		return false;
303 
304 	return defaultval;
305 }
306 
307 /**
308  * @brief retrieve an Int attribute from an XML Node
309  * @param[in] parent XML Node structure to get from
310  * @param[in] name Name of the attribute
311  * @param[in] defaultval Default value to return if no such attribute defined
312  */
XML_GetInt(xmlNode_t * parent,const char * name,const int defaultval)313 int XML_GetInt (xmlNode_t* parent, const char* name, const int defaultval)
314 {
315 	const char* txt;
316 	txt = mxmlElementGetAttr(parent, name);
317 	if (!txt)
318 		return defaultval;
319 	return atoi(txt);
320 }
321 
322 /**
323  * @brief retrieve a Short attribute from an XML Node
324  * @param[in] parent XML Node structure to get from
325  * @param[in] name Name of the attribute
326  * @param[in] defaultval Default value to return if no such attribute defined
327  */
XML_GetShort(xmlNode_t * parent,const char * name,const short defaultval)328 short XML_GetShort (xmlNode_t* parent, const char* name, const short defaultval)
329 {
330 	const char* txt;
331 	txt = mxmlElementGetAttr(parent, name);
332 	if (!txt)
333 		return defaultval;
334 	return atoi(txt);
335 }
336 
337 /**
338  * @brief retrieve a Long attribute from an XML Node
339  * @param[in] parent XML Node structure to get from
340  * @param[in] name Name of the attribute
341  * @param[in] defaultval Default value to return if no such attribute defined
342  */
XML_GetLong(xmlNode_t * parent,const char * name,const long defaultval)343 long XML_GetLong (xmlNode_t* parent, const char* name, const long defaultval)
344 {
345 	const char* txt;
346 	txt = mxmlElementGetAttr(parent, name);
347 	if (!txt)
348 		return defaultval;
349 	return atol(txt);
350 }
351 
352 /**
353  * @brief retrieve a String attribute from an XML Node
354  * @param[in] parent XML Node structure to get from
355  * @param[in] name Name of the attribute
356  * @return empty string if no such attribute defined
357  */
XML_GetString(xmlNode_t * parent,const char * name)358 const char*  XML_GetString (xmlNode_t* parent, const char* name)
359 {
360 	const char* str = mxmlElementGetAttr(parent, name);
361 	if (!str)
362 		return "";
363 	return str;
364 }
365 
366 /**
367  * @brief retrieve a Float attribute from an XML Node
368  * @param[in] parent XML Node structure to get from
369  * @param[in] name Name of the attribute
370  * @param[in] defaultval Default value to return if no such attribute defined
371  */
XML_GetFloat(xmlNode_t * parent,const char * name,const float defaultval)372 float XML_GetFloat (xmlNode_t* parent, const char* name, const float defaultval)
373 {
374 	const char* txt;
375 	txt = mxmlElementGetAttr(parent, name);
376 	if (!txt)
377 		return defaultval;
378 	return atof(txt);
379 }
380 
381 /**
382  * @brief retrieve a Double attribute from an XML Node
383  * @param[in] parent XML Node structure to get from
384  * @param[in] name Name of the attribute
385  * @param[in] defaultval Default value to return if no such attribute defined
386  */
XML_GetDouble(xmlNode_t * parent,const char * name,const double defaultval)387 double XML_GetDouble (xmlNode_t* parent, const char* name, const double defaultval)
388 {
389 	const char* txt;
390 	txt = mxmlElementGetAttr(parent, name);
391 	if (!txt)
392 		return defaultval;
393 	return atof(txt);
394 }
395 
396 /**
397  * @brief retrieve the first Pos2 data from an XML Node
398  * @param[in] parent XML Node structure to get child from
399  * @param[in] name Name of the pos node
400  * @param[out] pos vec2_t structure to fill
401  * @return pointer to the node the data was retrieved from
402  * @return nullptr if no node with name found
403  */
XML_GetPos2(xmlNode_t * parent,const char * name,vec2_t pos)404 xmlNode_t* XML_GetPos2 (xmlNode_t* parent, const char* name, vec2_t pos)
405 {
406 	xmlNode_t* p = XML_GetNode(parent, name);
407 	if (!p)
408 		return nullptr;
409 	pos[0] = XML_GetFloat(p, "x", 0);
410 	pos[1] = XML_GetFloat(p, "y", 0);
411 	return p;
412 }
413 
414 /**
415  * @brief retrieve the next Pos2 data from an XML Node
416  * @param[in] actual XML Node pointer of the previous pos data
417  * @param[in] parent XML Node structure to get child from
418  * @param[in] name Name of the pos node
419  * @param[out] pos vec2_t structure to fill
420  * @return pointer to the node the data was retrieved from
421  * @return nullptr if no Node with name found
422  */
XML_GetNextPos2(xmlNode_t * actual,xmlNode_t * parent,const char * name,vec2_t pos)423 xmlNode_t* XML_GetNextPos2 (xmlNode_t* actual, xmlNode_t* parent, const char* name, vec2_t pos)
424 {
425 	xmlNode_t* p = XML_GetNextNode(actual, parent, name);
426 	if (!p)
427 		return nullptr;
428 	pos[0] = XML_GetFloat(p, "x", 0);
429 	pos[1] = XML_GetFloat(p, "y", 0);
430 	return p;
431 }
432 
433 /**
434  * @brief retrieve the first Pos3 data from an XML Node
435  * @param[in] parent XML Node structure to get child from
436  * @param[in] name Name of the pos node
437  * @param[out] pos vec3_t structure to fill
438  * @return pointer to the node the data was retrieved from
439  * @return nullptr if no node with name found
440  */
XML_GetPos3(xmlNode_t * parent,const char * name,vec3_t pos)441 xmlNode_t* XML_GetPos3 (xmlNode_t* parent, const char* name, vec3_t pos)
442 {
443 	xmlNode_t* p = XML_GetNode(parent, name);
444 	if (!p)
445 		return nullptr;
446 	pos[0] = XML_GetFloat(p, "x", 0);
447 	pos[1] = XML_GetFloat(p, "y", 0);
448 	pos[2] = XML_GetFloat(p, "z", 0);
449 	return p;
450 }
451 
452 /**
453  * @brief retrieve the next Pos3 data from an XML Node
454  * @param[in] actual XML Node pointer of the previous pos data
455  * @param[in] parent XML Node structure to get child from
456  * @param[in] name Name of the pos node
457  * @param[out] pos vec3_t structure to fill
458  * @return pointer to the node the data was retrieved from
459  * @return nullptr if no Node with name found
460  */
XML_GetNextPos3(xmlNode_t * actual,xmlNode_t * parent,const char * name,vec3_t pos)461 xmlNode_t* XML_GetNextPos3 (xmlNode_t* actual, xmlNode_t* parent, const char* name, vec3_t pos)
462 {
463 	xmlNode_t* p = XML_GetNextNode(actual, parent, name);
464 	if (!p)
465 		return nullptr;
466 	pos[0] = XML_GetFloat(p, "x", 0);
467 	pos[1] = XML_GetFloat(p, "y", 0);
468 	pos[2] = XML_GetFloat(p, "z", 0);
469 	return p;
470 }
471 
472 /**
473  * @brief retrieve the date data from an XML Node
474  * @param[in] parent XML Node structure to get child from
475  * @param[in] name Name of the pos node
476  * @param[out] day Day part of the date to fill
477  * @param[out] sec Second part of the date to fill
478  * @return pointer to the node the data was retrieved from
479  * @return nullptr if no node with name found
480  */
XML_GetDate(xmlNode_t * parent,const char * name,int * day,int * sec)481 xmlNode_t* XML_GetDate (xmlNode_t* parent, const char* name, int* day, int* sec)
482 {
483 	xmlNode_t* p = XML_GetNode(parent, name);
484 	if (!p)
485 		return nullptr;
486 	*day = XML_GetInt(p, "day", 0);
487 	*sec = XML_GetInt(p, "sec", 0);
488 	return p;
489 }
490 
491 /**
492  * @brief Get first Node of the XML tree by name
493  * @param[in] parent Parent XML Node structure
494  * @param[in] name Name of the node to retrieve
495  * @return pointer to the found XML Node structure or nullptr
496  */
XML_GetNode(xmlNode_t * parent,const char * name)497 xmlNode_t* XML_GetNode (xmlNode_t* parent, const char* name)
498 {
499 	return mxmlFindElement(parent, parent, name, nullptr, nullptr, MXML_DESCEND_FIRST);
500 }
501 
502 /**
503  * @brief Get next Node of the XML tree by name
504  * @param[in] current Pointer to the previous Node was found
505  * @param[in] parent Parent XML Node structure
506  * @param[in] name Name of the node to retrieve
507  * @return pointer to the found XML Node structure or nullptr
508  */
XML_GetNextNode(xmlNode_t * current,xmlNode_t * parent,const char * name)509 xmlNode_t* XML_GetNextNode (xmlNode_t* current, xmlNode_t* parent, const char* name)
510 {
511 	return mxmlFindElement(current, parent, name, nullptr, nullptr, MXML_NO_DESCEND);
512 }
513 
514 /**
515  * @brief callback function for parsing the node tree
516  */
mxml_ufo_type_cb(xmlNode_t * node)517 static mxml_type_t mxml_ufo_type_cb (xmlNode_t* node)
518 {
519 	/* You can lookup attributes and/or use the
520 	 * element name, hierarchy, etc... */
521 	const char* type = mxmlElementGetAttr(node, "type");
522 	if (type == nullptr) {
523 #ifdef MXML_MAJOR_VERSION
524 		type = mxmlGetElement(node);
525 #else
526 		type = node->value.element.name;
527 #endif
528 	}
529 
530 	if (!strcmp(type, "int"))
531 		return MXML_INTEGER;
532 	else if (!strcmp(type, "opaque"))
533 		return MXML_OPAQUE;
534 	else if (!strcmp(type, "string"))
535 		return MXML_OPAQUE;
536 	else if (!strcmp(type, "double"))
537 		return MXML_REAL;
538 	else
539 		return MXML_TEXT;
540 }
541 
XML_Parse(const char * buffer)542 xmlNode_t* XML_Parse (const char* buffer)
543 {
544 	return mxmlLoadString(nullptr, buffer, mxml_ufo_type_cb);
545 }
546