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