TORCS  1.3.9
The Open Racing Car Simulator
xml.cpp
Go to the documentation of this file.
1 /***************************************************************************
2 
3  file : xml.cpp
4  created : Sat Mar 18 23:50:46 CET 2000
5  copyright : (C) 2000 by Eric Espie
6  email : torcs@free.fr
7  version : $Id$
8 
9  ***************************************************************************/
10 
11 /***************************************************************************
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * *
18  ***************************************************************************/
19 
20 /*
21  * This set of function is used to store and retrieve
22  * values in parameters files written in XML.
23  */
24 
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <cstring>
28 #include <sys/stat.h>
29 #include "xmlparse.h"
30 #include <xml.h>
31 #include <portability.h>
32 
33 #define BUFMAX 256
34 
35 /*
36  * NAME:
37  * NewElt
38  *
39  * FUNCTION:
40  * Creates a new element
41  *
42  * PARAMETERS:
43  * name and attributes
44  *
45  * RETURNS:
46  * new element created
47  *
48  */
49 static txmlElement *
50 NewElt(const char *name, const char **atts)
51 {
52  int nAtts;
53  const char **p;
54  const char *s1, *s2;
55  txmlElement *newElt;
56  txmlAttribute *newAttr;
57 
58 
59  /* Create a new element */
60  if ((newElt = (txmlElement*)malloc(sizeof(txmlElement))) == NULL) {
61  return (txmlElement*)NULL;
62  }
63  newElt->name = strdup(name);
64  newElt->pcdata = (char*)NULL;
65  newElt->attr = (txmlAttribute*)NULL;
66  newElt->sub = (txmlElement*)NULL;
67  newElt->up = (txmlElement*)NULL;
68  newElt->next = newElt;
69  newElt->level = 0;
70 
71  /* attributes */
72  p = atts;
73  while (*p)
74  ++p;
75  nAtts = (p - atts) >> 1;
76  if (nAtts > 1) {
77  qsort((void *)atts, nAtts, sizeof(char *) * 2, (int (*)(const void *, const void *))strcmp);
78  }
79 
80  while (*atts) {
81  s1 = *atts++;
82  s2 = *atts++;
83  if ((newAttr = (txmlAttribute*)malloc(sizeof(txmlAttribute))) == NULL) {
84  return (txmlElement*)NULL;
85  }
86  newAttr->name = strdup(s1);
87  newAttr->value = strdup(s2);
88  /* insert in attributes ring */
89  if (newElt->attr == NULL) {
90  newElt->attr = newAttr;
91  newAttr->next = newAttr;
92  } else {
93  newAttr->next = newElt->attr->next;
94  newElt->attr->next = newAttr;
95  newElt->attr = newAttr;
96  }
97  }
98 
99  return newElt;
100 }
101 
102 
103 /*
104  * NAME:
105  * xmlInsertElt
106  *
107  * FUNCTION:
108  * Create and Insert a new element in the sub-list of
109  * the element given in parameter
110  *
111  * PARAMETERS:
112  * curElt element
113  * name name of the new element
114  * atts attribute list of the new element
115  *
116  * RETURNS:
117  * the new element created.
118  *
119  * NOTE:
120  * Use NULL as current element to create a new tree
121  */
122 txmlElement *
123 xmlInsertElt(txmlElement *curElt, const char *name, const char **atts)
124 {
125  txmlElement *newElt;
126 
127  newElt = NewElt(name, atts);
128 
129  if (curElt) {
130  if (curElt->sub == NULL) {
131  curElt->sub = newElt;
132  newElt->next = newElt;
133  } else {
134  newElt->next = curElt->sub->next;
135  curElt->sub->next = newElt;
136  curElt->sub = newElt;
137  }
138  newElt->up = curElt;
139  newElt->level = curElt->level + 1;
140  }
141 
142  return newElt;
143 }
144 
145 /*
146  * Function
147  * startElement
148  *
149  * Description
150  *
151  *
152  * Parameters
153  *
154  *
155  * Return
156  *
157  */
158 static void
159 startElement(void *userData, const char *name, const char **atts)
160 {
161  txmlElement **curElt = (txmlElement **)userData;
162 
163  *curElt = xmlInsertElt(*curElt, name, atts);
164 }
165 
166 /*
167  * Function
168  * endElement
169  *
170  * Description
171  *
172  *
173  * Parameters
174  *
175  *
176  * Return
177  * none
178  */
179 static void
180 endElement(void *userData, const char * /* name */)
181 {
182  txmlElement **curElt = (txmlElement **)userData;
183 
184  if ((*curElt)->up != NULL) {
185  *curElt = (*curElt)->up;
186  }
187 }
188 
189 static void
190 CharacterData(void *userData, const char *s, int len)
191 {
192  char *s1,*s2,*s3;
193  txmlElement **curElt = (txmlElement **)userData;
194 
195  if ((s1 = (char*)malloc(len+1)) == NULL) {
196  return;
197  }
198  strncpy(s1, s, len);
199 
200  /* remove spaces in front */
201  s2 = s1;
202  while ((*s2 == ' ') || (*s2 == '\t') || (*s2 == '\n')) {
203  s2++;
204  }
205 
206  /* remove spaces at the end */
207  s3 = s1+len-1;
208  while (((*s3 == ' ') || (*s3 == '\t') || (*s3 == '\n')) && (s3 > s2)) {
209  s3--;
210  }
211 
212  if (s3 > s2) {
213  *(s3+1) = 0;
214  (*curElt)->pcdata = strdup(s2);
215  }
216  free(s1);
217 }
218 
219 /*
220  * Function
221  * xmlReadFile
222  *
223  * Description
224  * Read a config file
225  *
226  * Parameters
227  * file name of the config file
228  *
229  * Return
230  * root of the tree
231  * NULL error.
232  *
233  * Remarks
234  *
235  */
236 txmlElement *
237 xmlReadFile(const char *file)
238 {
239  FILE *in;
240  char buf[BUFSIZ];
241  XML_Parser parser;
242  int done;
243  txmlElement *retElt;
244 
245  if ((in = fopen(file, "r")) == NULL) {
246  fprintf(stderr, "xmlReadFile: file %s has pb (access rights ?)\n", file);
247  return (txmlElement*)NULL;
248  }
249 
250  parser = XML_ParserCreate((XML_Char*)NULL);
251  XML_SetUserData(parser, &retElt);
254  do {
255  size_t len = fread(buf, 1, sizeof(buf), in);
256  done = len < sizeof(buf);
257  if (!XML_Parse(parser, buf, len, done)) {
258  fprintf(stderr, "file: %s -> %s at line %d\n", file, XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
259 
260  XML_ParserFree(parser);
261  fclose(in);
262  return (txmlElement*)NULL;
263  }
264  } while (!done);
265 
266  XML_ParserFree(parser);
267  fclose(in);
268 
269  return retElt;
270 }
271 
272 static void
273 wr(int indent, const char *buf, FILE *out)
274 {
275  char blank[BUFMAX];
276  int i;
277 
278  for(i = 0; i < indent*2; i++) blank[i] = ' ';
279  blank[i] = 0;
280  fprintf(out, "%s%s", blank, buf);
281 }
282 
283 static void
284 wrrec(txmlElement *startElt, FILE *out)
285 {
286  txmlElement *curElt;
287  txmlAttribute *curAttr;
288  char buf[BUFMAX];
289 
290  curElt = startElt;
291 
292  if (curElt) {
293  wr(0, "\n", out);
294  do {
295  curElt = curElt->next;
296  snprintf(buf, BUFMAX, "<%s", curElt->name);
297  wr(curElt->level, buf, out);
298  curAttr = curElt->attr;
299  if (curAttr) {
300  do {
301  curAttr = curAttr->next;
302  snprintf(buf, BUFMAX, " %s=\"%s\"", curAttr->name, curAttr->value);
303  wr(0, buf, out);
304  } while (curAttr != curElt->attr);
305  }
306  snprintf(buf, BUFMAX, ">");
307  wr(0, buf, out);
308  if (curElt->pcdata) {
309  snprintf(buf, BUFMAX, "%s", curElt->pcdata);
310  wr(0, buf, out);
311  }
312  /* recurse the nested elements */
313  wrrec(curElt->sub, out);
314  snprintf(buf, BUFMAX, "</%s>\n", curElt->name);
315  wr(0, buf, out);
316  } while (curElt != startElt);
317  wr(curElt->level-1, "", out);
318  }
319 }
320 
321 /*
322  * Function
323  * xmlWriteFile
324  *
325  * Description
326  * Write a parameter file
327  *
328  * Parameters
329  * file name of the config file
330  * startElt root of the tree to write
331  *
332  * Return
333  * 0 ok
334  * -1 failed
335  *
336  * Remarks
337  * the file is created if necessary
338  */
339 int
340 xmlWriteFile(const char *file, txmlElement *startElt, char *dtd)
341 {
342  char buf[BUFMAX];
343  FILE *out;
344 
345  if ((out = fopen(file, "w")) == NULL) {
346  fprintf(stderr, "xmlWriteFile: file %s has pb (access rights ?)\n", file);
347  return -1;
348  }
349 
350  snprintf(buf, BUFMAX, "<?xml version=\"1.0\" ?>\n");
351  wr(0, buf, out);
352  snprintf(buf, BUFMAX, "\n<!DOCTYPE params SYSTEM \"%s\">\n\n", dtd);
353  wr(0, buf, out);
354 
355  wrrec(startElt, out);
356  wr(0, "\n", out);
357 
358  fclose(out);
359  return 0;
360 }
361 
362 /*
363  * NAME:
364  * xmlGetAttr
365  *
366  * FUNCTION:
367  * Get the attribute value of an element
368  *
369  * PARAMETERS:
370  * curElt element to consider
371  * attrname name of the attribute
372  *
373  * RETURNS:
374  * the attribute value or NULL if attribute is not present
375  *
376  */
377 char *
378 xmlGetAttr(txmlElement *curElt, char *attrname)
379 {
380  txmlAttribute *cutAttr;
381 
382  cutAttr = curElt->attr;
383  if (cutAttr) {
384  do {
385  cutAttr = cutAttr->next;
386  if (strcmp(cutAttr->name, attrname) == 0) {
387  return strdup(cutAttr->value);
388  }
389  } while (cutAttr != curElt->attr);
390  }
391  return (char*)NULL;
392 }
393 
394 /*
395  * NAME:
396  * xmlNextElt
397  *
398  * FUNCTION:
399  * Get the next element (same level)
400  *
401  * PARAMETERS:
402  * startElt element to start with
403  *
404  * RETURNS:
405  * the next element or NULL if no more element
406  * at the same level
407  *
408  */
409 txmlElement *
411 {
412  txmlElement *curElt;
413 
414  curElt = startElt->next;
415  if (curElt->up != NULL) {
416  if (curElt->up->sub->next == curElt) {
417  return (txmlElement*)NULL;
418  }
419  return curElt;
420  }
421  return (txmlElement*)NULL;
422 }
423 
424 
425 /*
426  * NAME:
427  * xmlSubElt
428  *
429  * FUNCTION:
430  * Get the first sub-element (nested level)
431  *
432  * PARAMETERS:
433  * startElt element to start with
434  *
435  * RETURNS:
436  * the first sub-element or NULL if no sub-element
437  *
438  */
439 txmlElement *
441 {
442  if (startElt->sub != NULL) {
443  return startElt->sub->next;
444  }
445 
446  return (txmlElement*)NULL;
447 }
448 
449 
450 /*
451  * NAME:
452  * xmlWalkElt
453  *
454  * FUNCTION:
455  * Walk all the tree
456  *
457  * PARAMETERS:
458  * startElt element to start with
459  *
460  * RETURNS:
461  * the next element in the tree or NULL if all the tree
462  * has been parsed.
463  *
464  */
465 txmlElement *
467 {
468  txmlElement *curElt;
469 
470  curElt = startElt;
471  /* in depth first */
472  if (curElt->sub != NULL) {
473  return curElt->sub->next;
474  }
475 
476  /* go to the next element */
477  if ((curElt->up != NULL) && (curElt != curElt->up->sub)) {
478  return curElt->next;
479  }
480 
481  /* end of the ring should go upward */
482  while (curElt->up != NULL) {
483  curElt = curElt->up;
484  if ((curElt->up != NULL) && (curElt != curElt->up->sub)) {
485  return curElt->next;
486  }
487  }
488 
489  return (txmlElement*)NULL;
490 }
491 
492 
493 /*
494  * NAME:
495  * xmlWalkSubElt
496  *
497  * FUNCTION:
498  * walk a sub-tree
499  *
500  * PARAMETERS:
501  * startElt element to start with
502  * topElt sub-tree root
503  *
504  * RETURNS:
505  * next element in in-depth search or NULL if all sub-tree has been parsed
506  *
507  */
508 txmlElement *
510 {
511  txmlElement *curElt;
512 
513  curElt = startElt;
514  /* in depth first */
515  if (curElt->sub != NULL) {
516  return curElt->sub->next;
517  }
518 
519  /* go to the next element */
520  if ((curElt->up != NULL) && (curElt != curElt->up->sub) && (curElt != topElt)) {
521  return curElt->next;
522  }
523 
524  /* end of the ring should go upward */
525  while ((curElt->up != NULL) && (curElt != topElt)) {
526  curElt = curElt->up;
527  if ((curElt->up != NULL) && (curElt != curElt->up->sub)) {
528  return curElt->next;
529  }
530  }
531 
532  return (txmlElement*)NULL;
533 }
534 
535 
536 /*
537  * NAME:
538  * xmlFindNextElt
539  *
540  * FUNCTION:
541  * Find the next element corresponding to name
542  *
543  * PARAMETERS:
544  * startElt element to start with
545  * name name of the element to find
546  *
547  * RETURNS:
548  * pointer on next element corresponding to name
549  * or NULL if no more.
550  *
551  */
552 txmlElement *
553 xmlFindNextElt(txmlElement *startElt, char *name)
554 {
555  txmlElement *curElt;
556 
557  curElt = startElt;
558  curElt = xmlWalkElt(curElt);
559  while (curElt) {
560  if (strcmp(curElt->name, name) == 0) {
561  return curElt;
562  }
563  curElt = xmlWalkElt(curElt);
564  }
565  return (txmlElement*)NULL;
566 }
567 
568 
569 /*
570  * NAME:
571  * xmlFindEltAttr
572  *
573  * FUNCTION:
574  * Find an element with its name an an attribute value
575  *
576  * PARAMETERS:
577  * startElt element to start with
578  * name name of the element to search
579  * attrname attribute name
580  * attrvalue attribute value of the searched element
581  *
582  * RETURNS:
583  * the corresponding element or NULL if not found
584  *
585  */
586 txmlElement *
587 xmlFindEltAttr(txmlElement *startElt, char *name, char *attrname, char *attrvalue)
588 {
589  txmlElement *curElt;
590  txmlAttribute *cutAttr;
591 
592  curElt = startElt;
593  curElt = xmlWalkElt(curElt);
594  while (curElt) {
595  if (strcmp(curElt->name, name) == 0) {
596  cutAttr = curElt->attr;
597  if (cutAttr) {
598  do {
599  cutAttr = cutAttr->next;
600  if (strcmp(cutAttr->name, attrname) == 0) {
601  if (strcmp(cutAttr->value, attrvalue) == 0) {
602  return curElt;
603  } else {
604  cutAttr = curElt->attr;
605  }
606  }
607  } while (cutAttr != curElt->attr);
608  }
609  }
610  curElt = xmlWalkElt(curElt);
611  }
612  return (txmlElement*)NULL;
613 }
614 
615 
616 
617 
618 
619 
int XMLPARSEAPI XML_GetCurrentLineNumber(XML_Parser parser)
void XMLPARSEAPI XML_SetUserData(XML_Parser parser, void *userData)
static void startElement(void *userData, const char *name, const char **atts)
Definition: xml.cpp:159
static void CharacterData(void *userData, const char *s, int len)
Definition: xml.cpp:190
txmlElement * xmlSubElt(txmlElement *startElt)
Definition: xml.cpp:440
static void wr(int indent, const char *buf, FILE *out)
Definition: xml.cpp:273
char * name
Definition: xml.h:17
int xmlWriteFile(const char *file, txmlElement *startElt, char *dtd)
Definition: xml.cpp:340
struct xmlAttribute * attr
Definition: xml.h:19
char * value
Definition: xml.h:12
void XMLPARSEAPI XML_ParserFree(XML_Parser parser)
void XMLPARSEAPI XML_SetCharacterDataHandler(XML_Parser parser, XML_CharacterDataHandler handler)
txmlElement * xmlInsertElt(txmlElement *curElt, const char *name, const char **atts)
Definition: xml.cpp:123
char * pcdata
Definition: xml.h:18
struct xmlElement * sub
Definition: xml.h:22
struct xmlElement * next
Definition: xml.h:21
static void endElement(void *userData, const char *)
Definition: xml.cpp:180
char * name
Definition: xml.h:11
int XMLPARSEAPI XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
txmlElement * xmlWalkSubElt(txmlElement *startElt, txmlElement *topElt)
Definition: xml.cpp:509
Definition: xml.h:16
txmlElement * xmlWalkElt(txmlElement *startElt)
Definition: xml.cpp:466
static Point p[4]
Definition: Convex.cpp:54
enum XML_Error XMLPARSEAPI XML_GetErrorCode(XML_Parser parser)
XML_Parser XMLPARSEAPI XML_ParserCreate(const XML_Char *encoding)
txmlElement * xmlFindNextElt(txmlElement *startElt, char *name)
Definition: xml.cpp:553
const XML_LChar XMLPARSEAPI * XML_ErrorString(int code)
static void wrrec(txmlElement *startElt, FILE *out)
Definition: xml.cpp:284
txmlElement * xmlNextElt(txmlElement *startElt)
Definition: xml.cpp:410
char * xmlGetAttr(txmlElement *curElt, char *attrname)
Definition: xml.cpp:378
struct xmlAttribute * next
Definition: xml.h:13
txmlElement * xmlReadFile(const char *file)
Definition: xml.cpp:237
#define BUFMAX
Definition: xml.cpp:33
char XML_Char
Definition: xmlparse.h:60
int level
Definition: xml.h:20
void * XML_Parser
Definition: xmlparse.h:33
txmlElement * xmlFindEltAttr(txmlElement *startElt, char *name, char *attrname, char *attrvalue)
Definition: xml.cpp:587
struct xmlElement * up
Definition: xml.h:23
void XMLPARSEAPI XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start, XML_EndElementHandler end)
static txmlElement * NewElt(const char *name, const char **atts)
Definition: xml.cpp:50