ROOTANA
Loading...
Searching...
No Matches
mxml.cxx
Go to the documentation of this file.
1/********************************************************************\
2
3 Name: mxml.c
4 Created by: Stefan Ritt
5 Copyright 2000 + Stefan Ritt
6
7 Contents: Midas XML Library
8
9 This is a simple implementation of XML functions for writing and
10 reading XML files. For writing an XML file from scratch, following
11 functions can be used:
12
13 writer = mxml_open_file(file_name);
14 mxml_start_element(writer, name);
15 mxml_write_attribute(writer, name, value);
16 mxml_write_value(writer, value);
17 mxml_end_element(writer);
18 ...
19 mxml_close_file(writer);
20
21 To read an XML file, the function
22
23 tree = mxml_parse_file(file_name, error, sizeof(error));
24
25 is used. It parses the complete XML file and stores it in a
26 hierarchical tree in memory. Nodes in that tree can be searched
27 for with
28
29 mxml_find_node(tree, xml_path);
30
31 or
32
33 mxml_find_nodes(tree, xml_path, &nodelist);
34
35 which support a subset of the XPath specification. Another set of
36 functions is available to retrieve attributes and values from nodes
37 in the tree and for manipulating nodes, like replacing, adding and
38 deleting nodes.
39
40
41 This file is part of MIDAS XML Library.
42
43 MIDAS XML Library is free software: you can redistribute it and/or modify
44 it under the terms of the GNU General Public License as published by
45 the Free Software Foundation, either version 2 of the License, or
46 (at your option) any later version.
47
48 MIDAS XML Library is distributed in the hope that it will be useful,
49 but WITHOUT ANY WARRANTY; without even the implied warranty of
50 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51 GNU General Public License for more details.
52
53 You should have received a copy of the GNU General Public License
54 along with MIDAS XML Library. If not, see <http://www.gnu.org/licenses/>.
55
56\********************************************************************/
57
58#include <stdio.h>
59#include <fcntl.h>
60#include <string.h>
61#include <assert.h>
62
63#include <string>
64
65#ifdef _MSC_VER
66
67#include <windows.h>
68#include <io.h>
69#include <time.h>
70
71#pragma warning( disable: 4996) /* disable "deprecated" warning */
72
73#else
74
75#define TRUE 1
76#define FALSE 0
77
78#ifndef O_TEXT
79#define O_TEXT 0
80#define O_BINARY 0
81#endif
82
83#include <stdlib.h>
84#include <unistd.h>
85#include <ctype.h>
86#include <stdarg.h>
87#include <errno.h>
88#ifndef OS_VXWORKS
89#include <sys/time.h>
90#endif
91#include <time.h>
92
93#endif
94
95#include "mxml.h"
96
97#define XML_INDENT " "
98
99#if defined(__GNUC__) && !defined(__MAKECINT__)
100# define MXML_GNUC_PRINTF( format_idx, arg_idx ) \
101 __attribute__((format (printf, format_idx, arg_idx)))
102# define MXML_GNUC_SCANF( format_idx, arg_idx ) \
103 __attribute__((format (scanf, format_idx, arg_idx)))
104# define MXML_GNUC_FORMAT( arg_idx ) \
105 __attribute__((format_arg (arg_idx)))
106#else
107# define MXML_GNUC_PRINTF( format_idx, arg_idx )
108# define MXML_GNUC_SCANF( format_idx, arg_idx )
109# define MXML_GNUC_FORMAT( arg_idx )
110#endif
111
112static int mxml_suppress_date_flag = 0; /* suppress writing date at the top of file. */
113
114/* local prototypes */
115static PMXML_NODE read_error(PMXML_NODE root, const char *file_name, int line_number, char *error, int error_size, int *error_line, const char *format, ...) MXML_GNUC_PRINTF(7, 8);
116static void mxml_encode(char* buf, int buf_size, const char *src, int src_len, int translate);
117static void mxml_decode(char *str);
118static int mxml_write_subtree(MXML_WRITER *writer, PMXML_NODE tree, int indent);
119static int mxml_write_line(MXML_WRITER *writer, const char *line);
120static int mxml_start_element1(MXML_WRITER *writer, const char *name, int indent);
121static int mxml_add_resultnode(PMXML_NODE node, const char *xml_path, PMXML_NODE **nodelist, int *found);
122static int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found);
123static void *mxml_malloc(size_t size);
124static void *mxml_realloc(void *p, size_t size);
125static void mxml_free(void *p);
126
127/*
128* Copy src to string dst of size siz. At most siz-1 characters
129* will be copied. Always NUL terminates (unless size == 0).
130* Returns strlen(src); if retval >= siz, truncation occurred.
131*/
132
133static size_t mxml_strlcpy(char *dst, const char *src, size_t size)
134{
135 char *d = dst;
136 const char *s = src;
137 size_t n = size;
138
139 /* Copy as many bytes as will fit */
140 if (n != 0 && --n != 0) {
141 do {
142 if ((*d++ = *s++) == 0)
143 break;
144 } while (--n != 0);
145 }
146
147 /* Not enough room in dst, add NUL and traverse rest of src */
148 if (n == 0) {
149 if (size != 0)
150 *d = '\0'; /* NUL-terminate dst */
151 while (*s++);
152 }
153
154 return (s - src - 1); /* count does not include NUL */
155}
156
157/*------------------------------------------------------------------*/
158
159static std::string toString(int i)
160{
161 char buf[100];
162 snprintf(buf, sizeof(buf), "%d", i);
163 return buf;
164}
165
166/*------------------------------------------------------------------*/
167
168static std::string toStrerror(int err)
169{
170 char buf[256];
171 snprintf(buf, sizeof(buf), "errno %d (%s)", err, strerror(err));
172 return buf;
173}
174
175/*------------------------------------------------------------------*/
176
177void *mxml_malloc(size_t size)
178{
179 return malloc(size);
180}
181
182/*------------------------------------------------------------------*/
183
184void *mxml_realloc(void *p, size_t size)
185{
186 return realloc(p, size);
187}
188
189/*------------------------------------------------------------------*/
190
191void mxml_free(void *p)
192{
193 free(p);
194}
195
196/*------------------------------------------------------------------*/
197
198int mxml_write_line(MXML_WRITER *writer, const char *line)
199{
200 int len = strlen(line);
201
202 if (writer->buffer) {
203 if (writer->buffer_len + len >= writer->buffer_size) {
204 writer->buffer_size += len + 10000;
205 writer->buffer = (char *)mxml_realloc(writer->buffer, writer->buffer_size);
206 assert(writer->buffer);
207 }
208 memcpy(writer->buffer + writer->buffer_len, line, len+1);
209 writer->buffer_len += len;
210 return len;
211 } else {
212 return (int)write(writer->fh, line, len);
213 }
214
215 return 0;
216}
217
218/*------------------------------------------------------------------*/
219
220/**
221 * open a memory buffer and write XML header
222 */
224{
225 MXML_WRITER *writer = (MXML_WRITER *)mxml_malloc(sizeof(MXML_WRITER));
226 memset(writer, 0, sizeof(MXML_WRITER));
227 writer->translate = 1;
228
229 writer->buffer_size = 10000;
230 writer->buffer = (char *)mxml_malloc(writer->buffer_size);
231 assert(writer->buffer != NULL);
232 writer->buffer[0] = 0;
233 writer->buffer_len = 0;
234
235 /* write XML header */
236 mxml_write_line(writer, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
237
238 if (mxml_suppress_date_flag == 0) {
239 time_t now = time(NULL);
240 std::string str = ctime(&now);
241 str.resize(24);
242 std::string line = "";
243 line += "<!-- created by MXML on ";
244 line += str;
245 line += " -->\n";
246 mxml_write_line(writer, line.c_str());
247 }
248
249 /* initialize stack */
250 writer->level = 0;
251 writer->element_is_open = 0;
252
253 return writer;
254}
255
256/*------------------------------------------------------------------*/
257
258/**
259 * suppress writing date at the top of file.
260 */
261void mxml_suppress_date(int suppress)
262{
263 mxml_suppress_date_flag = suppress;
264}
265
266/*------------------------------------------------------------------*/
267
268/**
269 * open a file and write XML header
270 */
271MXML_WRITER *mxml_open_file(const char *file_name)
272{
273 MXML_WRITER* writer = (MXML_WRITER *)mxml_malloc(sizeof(MXML_WRITER));
274 memset(writer, 0, sizeof(MXML_WRITER));
275 writer->translate = 1;
276
277 writer->fh = open(file_name, O_RDWR | O_CREAT | O_TRUNC | O_TEXT, 0644);
278
279 if (writer->fh == -1) {
280 std::string line = "";
281 line += "Unable to open file \"";
282 line += file_name;
283 line += "\": ";
284 line += toStrerror(errno);
285 fprintf(stderr, "%s\n", line.c_str());
286 mxml_free(writer);
287 return NULL;
288 }
289
290 /* write XML header */
291 mxml_write_line(writer, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
292 if (mxml_suppress_date_flag == 0) {
293 time_t now = time(NULL);
294 std::string str = ctime(&now);
295 str.resize(24);
296 std::string line = "";
297 line += "<!-- created by MXML on ";
298 line += str;
299 line += " -->\n";
300 mxml_write_line(writer, line.c_str());
301 }
302
303 /* initialize stack */
304 writer->level = 0;
305 writer->element_is_open = 0;
306
307 return writer;
308}
309
310/*------------------------------------------------------------------*/
311
312/**
313 * convert '<' '>' '&' '"' ''' into &xx;
314 */
315void mxml_encode(char* buf, int buf_size, const char *src, int src_len, int translate)
316{
317 if (buf_size <= 6*src_len) {
318 printf("mxml_encode: buffer size too small\n");
319 exit(0);
320 }
321 char *pd = buf;
322 const char* ps;
323 for (ps = src ; *ps ; ps++) {
324
325 if (translate) { /* tranlate "<", ">", "&", """, "'" */
326 switch (*ps) {
327 case '<':
328 strcpy(pd, "&lt;");
329 pd += 4;
330 break;
331 case '>':
332 strcpy(pd, "&gt;");
333 pd += 4;
334 break;
335 case '&':
336 strcpy(pd, "&amp;");
337 pd += 5;
338 break;
339 case '\"':
340 strcpy(pd, "&quot;");
341 pd += 6;
342 break;
343 case '\'':
344 strcpy(pd, "&apos;");
345 pd += 6;
346 break;
347 default:
348 *pd++ = *ps;
349 }
350 } else {
351 switch (*ps) { /* translate only special XML characters "<" and "&" */
352 case '<':
353 strcpy(pd, "&lt;");
354 pd += 4;
355 break;
356 case '&':
357 strcpy(pd, "&amp;");
358 pd += 5;
359 break;
360 default:
361 *pd++ = *ps;
362 }
363 }
364 }
365 *pd = 0;
366
367 //printf("mxml_encode: size %d, in %d, out %d, [%s] -> [%s]\n", buf_size, src_len, (int)strlen(buf), src, buf);
368}
369
370/*------------------------------------------------------------------*/
371
372/**
373 * reverse of mxml_encode, strip leading or trailing '"'
374 */
375void mxml_decode(char *str)
376{
377 char *p;
378
379 p = str;
380 while ((p = strchr(p, '&')) != NULL) {
381 if (strncmp(p, "&lt;", 4) == 0) {
382 *(p++) = '<';
383 memmove(p, p+3, strlen(p+3) + 1);
384 }
385 else if (strncmp(p, "&gt;", 4) == 0) {
386 *(p++) = '>';
387 memmove(p, p+3, strlen(p+3) + 1);
388 }
389 else if (strncmp(p, "&amp;", 5) == 0) {
390 *(p++) = '&';
391 memmove(p, p+4, strlen(p+4) + 1);
392 }
393 else if (strncmp(p, "&quot;", 6) == 0) {
394 *(p++) = '\"';
395 memmove(p, p+5, strlen(p+5) + 1);
396 }
397 else if (strncmp(p, "&apos;", 6) == 0) {
398 *(p++) = '\'';
399 memmove(p, p+5, strlen(p+5) + 1);
400 }
401 else {
402 p++; // skip unknown entity
403 }
404 }
405/* if (str[0] == '\"' && str[strlen(str)-1] == '\"') {
406 memmove(str, str+1, strlen(str+1) + 1);
407 str[strlen(str)-1] = 0;
408 }*/
409}
410
411/*------------------------------------------------------------------*/
412
413/**
414 * set translation of <,>,",',&, on/off in writer
415 */
416int mxml_set_translate(MXML_WRITER *writer, int flag)
417{
418 int old_flag;
419
420 old_flag = writer->translate;
421 writer->translate = flag;
422 return old_flag;
423}
424/*------------------------------------------------------------------*/
425
426/**
427 * start a new XML element, must be followed by mxml_end_elemnt
428 */
429int mxml_start_element1(MXML_WRITER *writer, const char *name, int indent)
430{
431 int i;
432
433 if (writer->element_is_open) {
434 mxml_write_line(writer, ">\n");
435 writer->element_is_open = FALSE;
436 }
437
438 std::string line = "";
439 if (indent)
440 for (i=0 ; i<writer->level ; i++)
441 line += XML_INDENT;
442 line += "<";
443
444 unsigned len = strlen(name);
445 unsigned name_enc_size = len*6+10;
446 char* name_enc = (char*)mxml_malloc(name_enc_size);
447 mxml_encode(name_enc, name_enc_size, name, strlen(name), writer->translate);
448 line += name_enc;
449
450 /* put element on stack */
451 if (writer->level == 0)
452 writer->stack = (char **)mxml_malloc(sizeof(char *));
453 else
454 writer->stack = (char **)mxml_realloc(writer->stack, sizeof(char *)*(writer->level+1));
455
456 writer->stack[writer->level] = name_enc;
457 writer->level++;
458 writer->element_is_open = TRUE;
459 writer->data_was_written = FALSE;
460
461 return mxml_write_line(writer, line.c_str()) == (int)line.length();
462}
463
464/*------------------------------------------------------------------*/
465
466int mxml_start_element(MXML_WRITER *writer, const char *name)
467{
468 return mxml_start_element1(writer, name, TRUE);
469}
470
471/*------------------------------------------------------------------*/
472
473int mxml_start_element_noindent(MXML_WRITER *writer, const char *name)
474{
475 return mxml_start_element1(writer, name, FALSE);
476}
477
478/*------------------------------------------------------------------*/
479
480/**
481 * close an open XML element
482 */
484{
485 int i;
486
487 if (writer->level == 0)
488 return 0;
489
490 writer->level--;
491
492 if (writer->element_is_open) {
493 writer->element_is_open = FALSE;
494 mxml_free(writer->stack[writer->level]);
495 if (writer->level == 0)
496 mxml_free(writer->stack);
497 const char* line = "/>\n";
498 return mxml_write_line(writer, line) == (int)strlen(line);
499 }
500
501 std::string line = "";
502 if (!writer->data_was_written) {
503 for (i=0 ; i<writer->level ; i++)
504 line += XML_INDENT;
505 }
506
507 line += "</";
508 line += writer->stack[writer->level];
509 mxml_free(writer->stack[writer->level]);
510 if (writer->level == 0)
511 mxml_free(writer->stack);
512 line += ">\n";
513 writer->data_was_written = FALSE;
514
515 return mxml_write_line(writer, line.c_str()) == (int)line.length();
516}
517
518/*------------------------------------------------------------------*/
519
520/**
521 * write an attribute to the currently open XML element
522 */
523int mxml_write_attribute(MXML_WRITER *writer, const char *name, const char *value)
524{
525 char buf[6*4096+10];
526
527 if (!writer->element_is_open)
528 return FALSE;
529
530 std::string line = "";
531 line += " ";
532 mxml_encode(buf, sizeof(buf), name, strlen(name), writer->translate);
533 line += buf;
534 line += "=\"";
535 mxml_encode(buf, sizeof(buf), value, strlen(value), writer->translate);
536 line += buf;
537 line += "\"";
538
539 return mxml_write_line(writer, line.c_str()) == (int)line.length();
540}
541
542/*------------------------------------------------------------------*/
543
544/**
545 * write value of an XML element, like <[name]>[value]</[name]>
546 */
547int mxml_write_value(MXML_WRITER *writer, const char *data)
548{
549 if (!writer->element_is_open)
550 return FALSE;
551
552 if (mxml_write_line(writer, ">") != 1)
553 return FALSE;
554 writer->element_is_open = FALSE;
555 writer->data_was_written = TRUE;
556
557 unsigned len = strlen(data);
558 unsigned size = 6*len + 1000;
559 char* buf = (char*)mxml_malloc(size);
560 memcpy(buf, data, len+1);
561 mxml_encode(buf, size, data, len, writer->translate);
562 int v = mxml_write_line(writer, buf) == (int)strlen(buf);
563 mxml_free(buf);
564 return v;
565}
566
567/*------------------------------------------------------------------*/
568
569/**
570 * write empty line
571 */
573{
574 if (writer->element_is_open) {
575 mxml_write_line(writer, ">\n");
576 writer->element_is_open = FALSE;
577 }
578
579 if (mxml_write_line(writer, "\n") != 1)
580 return FALSE;
581
582 return TRUE;
583}
584
585/*------------------------------------------------------------------*/
586
587/**
588 * write a comment to an XML file, enclosed in "<!--" and "-->"
589 */
590int mxml_write_comment(MXML_WRITER *writer, const char *string)
591{
592 int i;
593
594 if (writer->element_is_open) {
595 mxml_write_line(writer, ">\n");
596 writer->element_is_open = FALSE;
597 }
598
599 std::string line = "";
600 for (i=0 ; i<writer->level ; i++)
601 line += XML_INDENT;
602
603 line += "<!-- ";
604 line += string;
605 line += " -->\n";
606 if (mxml_write_line(writer, line.c_str()) != (int)line.length())
607 return FALSE;
608
609 return TRUE;
610}
611
612/*------------------------------------------------------------------*/
613
614/**
615 * shortcut to write an element with a value but without attribute
616 */
617int mxml_write_element(MXML_WRITER *writer, const char *name, const char *value)
618{
619 int i;
620
621 i = mxml_start_element(writer, name);
622 i += mxml_write_value(writer, value);
623 i += mxml_end_element(writer);
624 return i;
625}
626
627/*------------------------------------------------------------------*/
628
629/**
630 * close a file opened with mxml_open_writer
631 */
633{
634 int i;
635 char *p;
636
637 if (writer->element_is_open) {
638 writer->element_is_open = FALSE;
639 if (mxml_write_line(writer, ">\n") != 2)
640 return NULL;
641 }
642
643 /* close remaining open levels */
644 for (i = 0 ; i<writer->level ; i++)
645 mxml_end_element(writer);
646
647 p = writer->buffer;
648 mxml_free(writer);
649 return p;
650}
651
652/*------------------------------------------------------------------*/
653
654/**
655 * close a file opened with mxml_open_writer
656 */
658{
659 int i;
660
661 if (writer->element_is_open) {
662 writer->element_is_open = FALSE;
663 if (mxml_write_line(writer, ">\n") != 2)
664 return 0;
665 }
666
667 /* close remaining open levels */
668 for (i = 0 ; i<writer->level ; i++)
669 mxml_end_element(writer);
670
671 close(writer->fh);
672 mxml_free(writer);
673 return 1;
674}
675
676/*------------------------------------------------------------------*/
677
678/**
679 * create root node of an XML tree
680 */
682{
683 PMXML_NODE root;
684
685 root = (PMXML_NODE)calloc(sizeof(MXML_NODE), 1);
686 strcpy(root->name, "root"); // SAFE
687 root->node_type = DOCUMENT_NODE;
688
689 return root;
690}
691
692/*------------------------------------------------------------------*/
693
694/**
695 * add a subnode (child) to an existing parent node as a specific position
696 */
697PMXML_NODE mxml_add_special_node_at(PMXML_NODE parent, int node_type, const char *node_name, const char *value, int idx)
698{
699 PMXML_NODE pnode, pchild;
700 int i, j;
701
702 assert(parent);
703 if (parent->n_children == 0)
704 parent->child = (PMXML_NODE)mxml_malloc(sizeof(MXML_NODE));
705 else
706 parent->child = (PMXML_NODE)mxml_realloc(parent->child, sizeof(MXML_NODE)*(parent->n_children+1));
707 assert(parent->child);
708
709 /* move following nodes one down */
710 if (idx < parent->n_children)
711 for (i=parent->n_children ; i > idx ; i--)
712 memcpy(&parent->child[i], &parent->child[i-1], sizeof(MXML_NODE));
713
714 /* correct parent pointer for children */
715 for (i=0 ; i<parent->n_children ; i++) {
716 pchild = parent->child+i;
717 for (j=0 ; j<pchild->n_children ; j++)
718 pchild->child[j].parent = pchild;
719 }
720
721 /* initialize new node */
722 pnode = &parent->child[idx];
723 memset(pnode, 0, sizeof(MXML_NODE));
724 mxml_strlcpy(pnode->name, node_name, sizeof(pnode->name));
725 pnode->node_type = node_type;
726 pnode->parent = parent;
727
728 parent->n_children++;
729
730 if (value && *value) {
731 int len = strlen(value);
732 pnode->value = (char *)mxml_malloc(len+1);
733 assert(pnode->value);
734 memcpy(pnode->value, value, len+1);
735 }
736
737 return pnode;
738}
739
740/*------------------------------------------------------------------*/
741
742/**
743 * add a subnode (child) to an existing parent node at the end
744 */
745PMXML_NODE mxml_add_special_node(PMXML_NODE parent, int node_type, const char *node_name, const char *value)
746{
747 return mxml_add_special_node_at(parent, node_type, node_name, value, parent->n_children);
748}
749
750/*------------------------------------------------------------------*/
751
752/**
753 * write value of an XML element, like <[name]>[value]</[name]>
754 */
755PMXML_NODE mxml_add_node(PMXML_NODE parent, const char *node_name, const char *value)
756{
757 return mxml_add_special_node_at(parent, ELEMENT_NODE, node_name, value, parent->n_children);
758}
759
760/*------------------------------------------------------------------*/
761
762/**
763 * add a subnode (child) to an existing parent node at the end
764 */
765PMXML_NODE mxml_add_node_at(PMXML_NODE parent, const char *node_name, const char *value, int idx)
766{
767 return mxml_add_special_node_at(parent, ELEMENT_NODE, node_name, value, idx);
768}
769
770/*------------------------------------------------------------------*/
771
772/**
773 * add a whole node tree to an existing parent node at a specific position
774 */
775int mxml_add_tree_at(PMXML_NODE parent, PMXML_NODE tree, int idx)
776{
777 PMXML_NODE pchild;
778 int i, j, k;
779
780 assert(parent);
781 assert(tree);
782 if (parent->n_children == 0)
783 parent->child = (PMXML_NODE)mxml_malloc(sizeof(MXML_NODE));
784 else {
785 pchild = parent->child;
786 parent->child = (PMXML_NODE)mxml_realloc(parent->child, sizeof(MXML_NODE)*(parent->n_children+1));
787
788 if (parent->child != pchild) {
789 /* correct parent pointer for children */
790 for (i=0 ; i<parent->n_children ; i++) {
791 pchild = parent->child+i;
792 for (j=0 ; j<pchild->n_children ; j++)
793 pchild->child[j].parent = pchild;
794 }
795 }
796 }
797 assert(parent->child);
798
799 if (idx < parent->n_children)
800 for (i=parent->n_children ; i > idx ; i--) {
801 /* move following nodes one down */
802 memcpy(&parent->child[i], &parent->child[i-1], sizeof(MXML_NODE));
803
804 /* correct parent pointer for children */
805 for (j=0 ; j<parent->n_children ; j++) {
806 pchild = parent->child+j;
807 for (k=0 ; k<pchild->n_children ; k++)
808 pchild->child[k].parent = pchild;
809 }
810 }
811
812 /* initialize new node */
813 memcpy(parent->child+idx, tree, sizeof(MXML_NODE));
814 parent->n_children++;
815 parent->child[idx].parent = parent;
816
817 /* correct parent pointer for children */
818 for (i=0 ; i<parent->n_children ; i++) {
819 pchild = parent->child+i;
820 for (j=0 ; j<pchild->n_children ; j++)
821 pchild->child[j].parent = pchild;
822 }
823
824 return TRUE;
825}
826
827/*------------------------------------------------------------------*/
828
829/**
830 * add a whole node tree to an existing parent node at the end
831 */
833{
834 return mxml_add_tree_at(parent, tree, parent->n_children);
835}
836
837/*------------------------------------------------------------------*/
838
839/**
840 * add an attribute to an existing node
841 */
842int mxml_add_attribute(PMXML_NODE pnode, const char *attrib_name, const char *attrib_value)
843{
844 if (pnode->n_attributes == 0) {
846 pnode->attribute_value = (char**)mxml_malloc(sizeof(char *));
847 } else {
848 pnode->attribute_name = (char*)mxml_realloc(pnode->attribute_name, MXML_NAME_LENGTH*(pnode->n_attributes+1));
849 pnode->attribute_value = (char**)mxml_realloc(pnode->attribute_value, sizeof(char *)*(pnode->n_attributes+1));
850 }
851
853 int len = strlen(attrib_value);
854 pnode->attribute_value[pnode->n_attributes] = (char *)mxml_malloc(len+1);
855 assert(pnode->attribute_value[pnode->n_attributes] != NULL);
856 memcpy(pnode->attribute_value[pnode->n_attributes], attrib_value, len+1);
857 pnode->n_attributes++;
858
859 return TRUE;
860}
861
862/*------------------------------------------------------------------*/
863
864/**
865 * return number of subnodes (children) of a node
866 */
868{
869 assert(pnode);
870 return pnode->n_children;
871}
872
873/*------------------------------------------------------------------*/
874
875/**
876 * return number of subnodes (children) of a node
877 */
879{
880 assert(pnode);
881 if (idx < pnode->n_children)
882 return &pnode->child[idx];
883 return NULL;
884}
885
886/*------------------------------------------------------------------*/
887
888
889int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found);
890
891int mxml_add_resultnode(PMXML_NODE node, const char *xml_path, PMXML_NODE **nodelist, int *found)
892{
893 /* if at end of path, add this node */
894 if (*xml_path == 0) {
895 if (*found == 0)
896 *nodelist = (PMXML_NODE *)mxml_malloc(sizeof(PMXML_NODE));
897 else
898 *nodelist = (PMXML_NODE *)mxml_realloc(*nodelist, sizeof(PMXML_NODE)*(*found + 1));
899
900 (*nodelist)[*found] = node;
901 (*found)++;
902 } else {
903 /* if not at end of path, branch into subtree */
904 return mxml_find_nodes1(node, xml_path+1, nodelist, found);
905 }
906
907 return 1;
908}
909
910/*------------------------------------------------------------------*/
911
912/**
913 Return list of XML nodes with a subset of XPATH specifications.
914 Following elemets are possible
915
916 /<node>/<node>/..../<node> Find a node in the tree hierarchy
917 /<node>[idx] Find child #[idx] of node (index starts from 1)
918 /<node>[idx]/<node> Find subnode of the above
919 /<node>[<subnode>=<value>] Find a node which has a specific subnode
920 /<node>[<subnode>=<value>]/<node> Find subnode of the above
921 /<node>[@<attrib>=<value>]/<node> Find a node which has a specific attribute
922*/
923int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found)
924{
925 PMXML_NODE pnode;
926 const char *p1,*p2;
927 char *p3, node_name[256], condition[256];
928 char cond_name[MXML_MAX_CONDITION][256], cond_value[MXML_MAX_CONDITION][256];
929 int cond_type[MXML_MAX_CONDITION];
930 int i, j, k, idx, num_cond;
931 int cond_satisfied,cond_index;
932 size_t len;
933
934 p1 = xml_path;
935 pnode = tree;
936
937 /* skip leading '/' */
938 if (*p1 && *p1 == '/')
939 p1++;
940
941 do {
942 p2 = p1;
943 while (*p2 && *p2 != '/' && *p2 != '[')
944 p2++;
945 len = (size_t)p2 - (size_t)p1;
946 if (len >= sizeof(node_name))
947 return 0;
948
949 memcpy(node_name, p1, len);
950 node_name[len] = 0;
951 idx = 0;
952 num_cond = 0;
953 while (*p2 == '[') {
954 cond_name[num_cond][0] = cond_value[num_cond][0] = cond_type[num_cond] = 0;
955 p2++;
956 if (isdigit(*p2)) {
957 /* evaluate [idx] */
958 idx = atoi(p2);
959 p2 = strchr(p2, ']');
960 if (p2 == NULL)
961 return 0;
962 p2++;
963 } else {
964 /* evaluate [<@attrib>/<subnode>=<value>] */
965 while (*p2 && isspace((unsigned char)*p2))
966 p2++;
967 mxml_strlcpy(condition, p2, sizeof(condition));
968 if (strchr(condition, ']'))
969 *strchr(condition, ']') = 0;
970 else
971 return 0;
972 p2 = strchr(p2, ']')+1;
973 if ((p3 = strchr(condition, '=')) != NULL) {
974 if (condition[0] == '@') {
975 cond_type[num_cond] = 1;
976 mxml_strlcpy(cond_name[num_cond], &condition[1], sizeof(cond_name[num_cond]));
977 } else {
978 mxml_strlcpy(cond_name[num_cond], condition, sizeof(cond_name[num_cond]));
979 }
980
981 *strchr(cond_name[num_cond], '=') = 0;
982 while (cond_name[num_cond][0] && isspace(cond_name[num_cond][strlen(cond_name[num_cond])-1]))
983 cond_name[num_cond][strlen(cond_name[num_cond])-1] = 0;
984
985 p3++;
986 while (*p3 && isspace(*p3))
987 p3++;
988 if (*p3 == '\"') {
989 mxml_strlcpy(cond_value[num_cond], p3+1, sizeof(cond_value[num_cond]));
990 while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1]))
991 cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
992 if (cond_value[num_cond][0] && cond_value[num_cond][strlen(cond_value[num_cond])-1] == '\"')
993 cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
994 } else if (*p3 == '\'') {
995 mxml_strlcpy(cond_value[num_cond], p3+1, sizeof(cond_value[num_cond]));
996 while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1]))
997 cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
998 if (cond_value[num_cond][0] && cond_value[num_cond][strlen(cond_value[num_cond])-1] == '\'')
999 cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
1000 } else {
1001 mxml_strlcpy(cond_value[num_cond], p3, sizeof(cond_value[num_cond]));
1002 while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1]))
1003 cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
1004 }
1005 num_cond++;
1006 }
1007 }
1008 }
1009
1010 cond_index = 0;
1011 for (i=j=0 ; i<pnode->n_children ; i++) {
1012 if (num_cond) {
1013 cond_satisfied = 0;
1014 for (k=0;k<num_cond;k++) {
1015 if (cond_type[k]) {
1016 /* search node with attribute */
1017 if (strcmp(pnode->child[i].name, node_name) == 0)
1018 if (mxml_get_attribute(pnode->child+i, cond_name[k]) &&
1019 strcmp(mxml_get_attribute(pnode->child+i, cond_name[k]), cond_value[k]) == 0)
1020 cond_satisfied++;
1021 }
1022 else {
1023 /* search subnode */
1024 for (j=0 ; j<pnode->child[i].n_children ; j++)
1025 if (strcmp(pnode->child[i].child[j].name, cond_name[k]) == 0)
1026 if (strcmp(pnode->child[i].child[j].value, cond_value[k]) == 0)
1027 cond_satisfied++;
1028 }
1029 }
1030 if (cond_satisfied==num_cond) {
1031 cond_index++;
1032 if (idx == 0 || cond_index == idx) {
1033 if (!mxml_add_resultnode(pnode->child+i, p2, nodelist, found))
1034 return 0;
1035 }
1036 }
1037 } else {
1038 if (strcmp(pnode->child[i].name, node_name) == 0)
1039 if (idx == 0 || ++j == idx)
1040 if (!mxml_add_resultnode(pnode->child+i, p2, nodelist, found))
1041 return 0;
1042 }
1043 }
1044
1045 if (i == pnode->n_children)
1046 return 1;
1047
1048 pnode = &pnode->child[i];
1049 p1 = p2;
1050 if (*p1 == '/')
1051 p1++;
1052
1053 } while (*p2);
1054
1055 return 1;
1056}
1057
1058/*------------------------------------------------------------------*/
1059
1060int mxml_find_nodes(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist)
1061{
1062 int status, found = 0;
1063
1064 status = mxml_find_nodes1(tree, xml_path, nodelist, &found);
1065
1066 if (status == 0)
1067 return -1;
1068
1069 return found;
1070}
1071
1072/*------------------------------------------------------------------*/
1073
1074/**
1075 * Search for a specific XML node with a subset of XPATH specifications.
1076 * Return first found node. For syntax see mxml_find_nodes()
1077 */
1078PMXML_NODE mxml_find_node(PMXML_NODE tree, const char *xml_path)
1079{
1080 PMXML_NODE *node, pnode;
1081 int n;
1082
1083 n = mxml_find_nodes(tree, xml_path, &node);
1084 if (n > 0) {
1085 pnode = node[0];
1086 mxml_free(node);
1087 } else
1088 pnode = NULL;
1089
1090 return pnode;
1091}
1092
1093/*------------------------------------------------------------------*/
1094
1096{
1097 assert(pnode);
1098 return pnode->parent;
1099}
1100
1101/*------------------------------------------------------------------*/
1102
1104{
1105 assert(pnode);
1106 return pnode->name;
1107}
1108
1109/*------------------------------------------------------------------*/
1110
1112{
1113 assert(pnode);
1114 return pnode->value;
1115}
1116
1117/*------------------------------------------------------------------*/
1118
1120{
1121 assert(pnode);
1122 return pnode->line_number_start;
1123}
1124
1125/*------------------------------------------------------------------*/
1126
1128{
1129 assert(pnode);
1130 return pnode->line_number_end;
1131}
1132
1133/*------------------------------------------------------------------*/
1134
1135char *mxml_get_attribute(PMXML_NODE pnode, const char *name)
1136{
1137 int i;
1138
1139 assert(pnode);
1140 for (i=0 ; i<pnode->n_attributes ; i++)
1141 if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, name) == 0)
1142 return pnode->attribute_value[i];
1143
1144 return NULL;
1145}
1146
1147/*------------------------------------------------------------------*/
1148
1149int mxml_replace_node_name(PMXML_NODE pnode, const char *name)
1150{
1151 mxml_strlcpy(pnode->name, name, sizeof(pnode->name));
1152 return TRUE;
1153}
1154
1155/*------------------------------------------------------------------*/
1156
1157int mxml_replace_node_value(PMXML_NODE pnode, const char *value)
1158{
1159 int len = strlen(value);
1160 if (pnode->value)
1161 pnode->value = (char *)mxml_realloc(pnode->value, len+1);
1162 else if (value)
1163 pnode->value = (char *)mxml_malloc(len+1);
1164 else
1165 pnode->value = NULL;
1166
1167 if (value)
1168 memcpy(pnode->value, value, len+1);
1169
1170 return TRUE;
1171}
1172
1173/*------------------------------------------------------------------*/
1174
1175/**
1176 replace value os a subnode, like
1177
1178 <parent>
1179 <child>value</child>
1180 </parent>
1181
1182 if pnode=parent, and "name"="child", then "value" gets replaced
1183*/
1184int mxml_replace_subvalue(PMXML_NODE pnode, const char *name, const char *value)
1185{
1186 int i;
1187
1188 for (i=0 ; i<pnode->n_children ; i++)
1189 if (strcmp(pnode->child[i].name, name) == 0)
1190 break;
1191
1192 if (i == pnode->n_children)
1193 return FALSE;
1194
1195 return mxml_replace_node_value(&pnode->child[i], value);
1196}
1197
1198/*------------------------------------------------------------------*/
1199
1200/**
1201 * change the name of an attribute, keep its value
1202 */
1203int mxml_replace_attribute_name(PMXML_NODE pnode, const char *old_name, const char *new_name)
1204{
1205 int i;
1206
1207 for (i=0 ; i<pnode->n_attributes ; i++)
1208 if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, old_name) == 0)
1209 break;
1210
1211 if (i == pnode->n_attributes)
1212 return FALSE;
1213
1215 return TRUE;
1216}
1217
1218/*------------------------------------------------------------------*/
1219
1220/**
1221 * change the value of an attribute
1222 */
1223int mxml_replace_attribute_value(PMXML_NODE pnode, const char *attrib_name, const char *attrib_value)
1224{
1225 int i;
1226
1227 for (i=0 ; i<pnode->n_attributes ; i++)
1228 if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, attrib_name) == 0)
1229 break;
1230
1231 if (i == pnode->n_attributes)
1232 return FALSE;
1233
1234 int len = strlen(attrib_value);
1235 pnode->attribute_value[i] = (char *)mxml_realloc(pnode->attribute_value[i], len+1);
1236 memcpy(pnode->attribute_value[i], attrib_value, len+1);
1237 return TRUE;
1238}
1239
1240/*------------------------------------------------------------------*/
1241
1242/**
1243 * free memory of a node and remove it from the parent's child list
1244 */
1246{
1247 PMXML_NODE parent;
1248 int i, j;
1249
1250 /* remove node from parent's list */
1251 parent = pnode->parent;
1252
1253 if (parent) {
1254 for (i=0 ; i<parent->n_children ; i++)
1255 if (&parent->child[i] == pnode)
1256 break;
1257
1258 /* free allocated node memory recursively */
1259 mxml_free_tree(pnode);
1260
1261 if (i < parent->n_children) {
1262 for (j=i ; j<parent->n_children-1 ; j++)
1263 memcpy(&parent->child[j], &parent->child[j+1], sizeof(MXML_NODE));
1264 parent->n_children--;
1265 if (parent->n_children)
1266 parent->child = (PMXML_NODE)mxml_realloc(parent->child, sizeof(MXML_NODE)*(parent->n_children));
1267 else
1268 mxml_free(parent->child);
1269 }
1270 } else
1271 mxml_free_tree(pnode);
1272
1273 return TRUE;
1274}
1275
1276/*------------------------------------------------------------------*/
1277
1278int mxml_delete_attribute(PMXML_NODE pnode, const char *attrib_name)
1279{
1280 int i, j;
1281
1282 for (i=0 ; i<pnode->n_attributes ; i++)
1283 if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, attrib_name) == 0)
1284 break;
1285
1286 if (i == pnode->n_attributes)
1287 return FALSE;
1288
1289 mxml_free(pnode->attribute_value[i]);
1290 for (j=i ; j<pnode->n_attributes-1 ; j++) {
1292 pnode->attribute_value[j] = pnode->attribute_value[j+1];
1293 }
1294
1295 if (pnode->n_attributes > 0) {
1296 pnode->attribute_name = (char *)mxml_realloc(pnode->attribute_name, MXML_NAME_LENGTH*(pnode->n_attributes-1));
1297 pnode->attribute_value = (char **)mxml_realloc(pnode->attribute_value, sizeof(char *)*(pnode->n_attributes-1));
1298 } else {
1299 mxml_free(pnode->attribute_name);
1300 mxml_free(pnode->attribute_value);
1301 }
1302
1303 return TRUE;
1304}
1305
1306/*------------------------------------------------------------------*/
1307
1308#define HERE root, file_name, line_number, error, error_size, error_line
1309
1310/**
1311 * used inside mxml_parse_file for reporting errors
1312 */
1313PMXML_NODE read_error(PMXML_NODE root, const char *file_name, int line_number, char *error, int error_size, int *error_line, const char *format, ...)
1314{
1315 std::string msg;
1316 if (file_name && file_name[0]) {
1317 msg += "XML read error in file \"";
1318 msg += file_name;
1319 msg += "\", line ";
1320 msg += toString(line_number);
1321 msg += ": ";
1322 } else {
1323 msg += "XML read error, line ";
1324 msg += toString(line_number);
1325 msg += ": ";
1326 }
1327
1328 char str[1000];
1329 va_list argptr;
1330 va_start(argptr, format);
1331 vsnprintf(str, sizeof(str), (char *) format, argptr);
1332 va_end(argptr);
1333
1334 msg += str;
1335
1336 if (error) {
1337 mxml_strlcpy(error, msg.c_str(), error_size);
1338 }
1339 if (error_line) {
1340 *error_line = line_number;
1341 }
1342
1343 mxml_free_tree(root);
1344
1345 return NULL;
1346}
1347
1348/*------------------------------------------------------------------*/
1349
1350/**
1351 * Parse a XML buffer and convert it into a tree of MXML_NODE's.
1352 * Return NULL in case of an error, return error description.
1353 * Optional file_name is used for error reporting if called from mxml_parse_file()
1354 */
1355PMXML_NODE mxml_parse_buffer(const char *buf, char *error, int error_size, int *error_line)
1356{
1357 char node_name[256], attrib_name[256], attrib_value[1000], quote;
1358 const char *p, *pv;
1359 int i,j, line_number;
1360 PMXML_NODE root, ptree, pnew;
1361 int end_element;
1362 size_t len;
1363 char *file_name = NULL; /* dummy for 'HERE' */
1364
1365 p = buf;
1366 line_number = 1;
1367
1368 root = mxml_create_root_node();
1369 ptree = root;
1370
1371 /* parse file contents */
1372 do {
1373 if (*p == '<') {
1374
1375 end_element = FALSE;
1376
1377 /* found new element */
1378 p++;
1379 while (*p && isspace(*p)) {
1380 if (*p == '\n')
1381 line_number++;
1382 p++;
1383 }
1384 if (!*p)
1385 return read_error(HERE, "Unexpected end of file");
1386
1387 if (strncmp(p, "!--", 3) == 0) {
1388
1389 /* found comment */
1390
1391 pnew = mxml_add_special_node(ptree, COMMENT_NODE, "Comment", NULL);
1392 pnew->line_number_start = line_number;
1393 pv = p+3;
1394 while (*pv == ' ')
1395 pv++;
1396
1397 p += 3;
1398 if (strstr(p, "-->") == NULL)
1399 return read_error(HERE, "Unterminated comment");
1400
1401 while (strncmp(p, "-->", 3) != 0) {
1402 if (*p == '\n')
1403 line_number++;
1404 p++;
1405 }
1406
1407 len = (size_t)p - (size_t)pv;
1408 pnew->value = (char *)mxml_malloc(len+1);
1409 memcpy(pnew->value, pv, len);
1410 pnew->value[len] = 0;
1411 pnew->line_number_end = line_number;
1412 mxml_decode(pnew->value);
1413
1414 p += 3;
1415
1416 } else if (*p == '?') {
1417
1418 /* found ?...? element */
1419 pnew = mxml_add_special_node(ptree, PROCESSING_INSTRUCTION_NODE, "PI", NULL);
1420 pnew->line_number_start = line_number;
1421 pv = p+1;
1422
1423 p++;
1424 if (strstr(p, "?>") == NULL)
1425 return read_error(HERE, "Unterminated ?...? element");
1426
1427 while (strncmp(p, "?>", 2) != 0) {
1428 if (*p == '\n')
1429 line_number++;
1430 p++;
1431 }
1432
1433 len = (size_t)p - (size_t)pv;
1434 pnew->value = (char *)mxml_malloc(len+1);
1435 memcpy(pnew->value, pv, len);
1436 pnew->value[len] = 0;
1437 pnew->line_number_end = line_number;
1438 mxml_decode(pnew->value);
1439
1440 p += 2;
1441
1442 } else if (strncmp(p, "!DOCTYPE", 8) == 0 ) {
1443
1444 /* found !DOCTYPE element , skip it */
1445 p += 8;
1446 if (strstr(p, ">") == NULL)
1447 return read_error(HERE, "Unterminated !DOCTYPE element");
1448
1449 j = 0;
1450 while (*p && (*p != '>' || j > 0)) {
1451 if (*p == '\n')
1452 line_number++;
1453 else if (*p == '<')
1454 j++;
1455 else if (*p == '>')
1456 j--;
1457 p++;
1458 }
1459 if (!*p)
1460 return read_error(HERE, "Unexpected end of file");
1461
1462 p++;
1463
1464 } else {
1465
1466 /* found normal element */
1467 if (*p == '/') {
1468 end_element = TRUE;
1469 p++;
1470 while (*p && isspace((unsigned char)*p)) {
1471 if (*p == '\n')
1472 line_number++;
1473 p++;
1474 }
1475 if (!*p)
1476 return read_error(HERE, "Unexpected end of file");
1477 }
1478
1479 /* extract node name */
1480 i = 0;
1481 node_name[i] = 0;
1482 while (*p && !isspace((unsigned char)*p) && *p != '/' && *p != '>' && *p != '<')
1483 node_name[i++] = *p++;
1484 node_name[i] = 0;
1485 if (!*p)
1486 return read_error(HERE, "Unexpected end of file");
1487 if (*p == '<')
1488 return read_error(HERE, "Unexpected \'<\' inside element \"%s\"", node_name);
1489
1490 mxml_decode(node_name);
1491
1492 if (end_element) {
1493
1494 if (!ptree)
1495 return read_error(HERE, "Found unexpected </%s>", node_name);
1496
1497 /* close previously opened element */
1498 if (strcmp(ptree->name, node_name) != 0)
1499 return read_error(HERE, "Found </%s>, expected </%s>", node_name, ptree->name);
1500 ptree->line_number_end = line_number;
1501
1502 /* go up one level on the tree */
1503 ptree = ptree->parent;
1504
1505 } else {
1506
1507 if (ptree == NULL)
1508 return read_error(HERE, "Unexpected second top level node");
1509
1510 /* allocate new element structure in parent tree */
1511 pnew = mxml_add_node(ptree, node_name, NULL);
1512 pnew->line_number_start = line_number;
1513 pnew->line_number_end = line_number;
1514
1515 while (*p && isspace((unsigned char)*p)) {
1516 if (*p == '\n')
1517 line_number++;
1518 p++;
1519 }
1520 if (!*p)
1521 return read_error(HERE, "Unexpected end of file");
1522
1523 while (*p != '>' && *p != '/') {
1524
1525 /* found attribute */
1526 pv = p;
1527 while (*pv && !isspace((unsigned char)*pv) && *pv != '=' && *pv != '<' && *pv != '>')
1528 pv++;
1529 if (!*pv)
1530 return read_error(HERE, "Unexpected end of file");
1531 if (*pv == '<' || *pv == '>')
1532 return read_error(HERE, "Unexpected \'%c\' inside element \"%s\"", *pv, node_name);
1533
1534 /* extract attribute name */
1535 len = (size_t)pv - (size_t)p;
1536 if (len > sizeof(attrib_name)-1)
1537 len = sizeof(attrib_name)-1;
1538 memcpy(attrib_name, p, len);
1539 attrib_name[len] = 0;
1540 mxml_decode(attrib_name);
1541
1542 p = pv;
1543 while (*p && isspace((unsigned char)*p)) {
1544 if (*p == '\n')
1545 line_number++;
1546 p++;
1547 }
1548 if (!*p)
1549 return read_error(HERE, "Unexpected end of file");
1550 if (*p != '=')
1551 return read_error(HERE, "Expect \"=\" here");
1552
1553 p++;
1554 while (*p && isspace((unsigned char)*p)) {
1555 if (*p == '\n')
1556 line_number++;
1557 p++;
1558 }
1559 if (!*p)
1560 return read_error(HERE, "Unexpected end of file");
1561 if (*p != '\"' && *p != '\'')
1562 return read_error(HERE, "Expect \" or \' here");
1563 quote = *p;
1564 p++;
1565
1566 /* extract attribute value */
1567 pv = p;
1568 while (*pv && *pv != quote)
1569 pv++;
1570 if (!*pv)
1571 return read_error(HERE, "Unexpected end of file");
1572
1573 len = (size_t)pv - (size_t)p;
1574 if (len > sizeof(attrib_value)-1)
1575 len = sizeof(attrib_value)-1;
1576 memcpy(attrib_value, p, len);
1577 attrib_value[len] = 0;
1578 mxml_decode(attrib_value);
1579
1580 /* add attribute to current node */
1581 mxml_add_attribute(pnew, attrib_name, attrib_value);
1582
1583 p = pv+1;
1584 while (*p && isspace((unsigned char)*p)) {
1585 if (*p == '\n')
1586 line_number++;
1587 p++;
1588 }
1589 if (!*p)
1590 return read_error(HERE, "Unexpected end of file");
1591 }
1592
1593 if (*p == '/') {
1594
1595 /* found empty node, like <node/>, just skip closing bracket */
1596 p++;
1597
1598 while (*p && isspace((unsigned char)*p)) {
1599 if (*p == '\n')
1600 line_number++;
1601 p++;
1602 }
1603 if (!*p)
1604 return read_error(HERE, "Unexpected end of file");
1605 if (*p != '>')
1606 return read_error(HERE, "Expected \">\" after \"/\"");
1607 p++;
1608 }
1609
1610 if (*p == '>') {
1611
1612 p++;
1613
1614 /* check if we have sub-element or value */
1615 pv = p;
1616 while (*pv && isspace((unsigned char)*pv)) {
1617 if (*pv == '\n')
1618 line_number++;
1619 pv++;
1620 }
1621 if (!*pv)
1622 return read_error(HERE, "Unexpected end of file");
1623
1624 if (*pv == '<' && *(pv+1) != '/') {
1625
1626 /* start new subtree */
1627 ptree = pnew;
1628 p = pv;
1629
1630 } else {
1631
1632 /* extract value */
1633 while (*pv && *pv != '<') {
1634 if (*pv == '\n')
1635 line_number++;
1636 pv++;
1637 }
1638 if (!*pv)
1639 return read_error(HERE, "Unexpected end of file");
1640
1641 len = (size_t)pv - (size_t)p;
1642 pnew->value = (char *)mxml_malloc(len+1);
1643 memcpy(pnew->value, p, len);
1644 pnew->value[len] = 0;
1645 mxml_decode(pnew->value);
1646 p = pv;
1647
1648 ptree = pnew;
1649 }
1650 }
1651 }
1652 }
1653 }
1654
1655 /* go to next element */
1656 while (*p && *p != '<') {
1657 if (*p == '\n')
1658 line_number++;
1659 p++;
1660 }
1661 } while (*p);
1662
1663 return root;
1664}
1665
1666/*------------------------------------------------------------------*/
1667
1668/**
1669 * parse !ENTYTY entries of XML files and replace with references.
1670 * Return 0 in case of no errors, return error description.
1671 * Optional file_name is used for error reporting if called from mxml_parse_file()
1672 */
1673int mxml_parse_entity(char **buf, const char *file_name, char *error, int error_size, int *error_line)
1674{
1675 char *p;
1676 char *pv;
1677 char delimiter;
1678 int i, j, k, line_number, status;
1679 char *replacement;
1680 char entity_name[MXML_MAX_ENTITY][256];
1681 char entity_reference_name[MXML_MAX_ENTITY][256];
1682 char *entity_value[MXML_MAX_ENTITY];
1683 int entity_type[MXML_MAX_ENTITY]; /* internal or external */
1684 int entity_line_number[MXML_MAX_ENTITY];
1685 int nentity;
1686 int fh, length;
1687 int entity_value_length[MXML_MAX_ENTITY];
1688 int entity_name_length[MXML_MAX_ENTITY];
1689
1690 PMXML_NODE root = mxml_create_root_node(); /* dummy for 'HERE' */
1691
1692 for (int ip = 0; ip < MXML_MAX_ENTITY; ip++)
1693 entity_value[ip] = NULL;
1694
1695 line_number = 1;
1696 nentity = -1;
1697 status = 0;
1698
1699 if (!buf || !(*buf) || !strlen(*buf))
1700 return 0;
1701
1702 char directoryname[FILENAME_MAX];
1703 mxml_strlcpy(directoryname, file_name, FILENAME_MAX);
1704 mxml_dirname(directoryname);
1705
1706 /* copy string to temporary space */
1707 int len = strlen(*buf);
1708 char* buffer = (char *) mxml_malloc(len+1);
1709 if (buffer == NULL) {
1710 read_error(HERE, "Cannot allocate memory.");
1711 status = 1;
1712 goto error;
1713 }
1714 memcpy(buffer, *buf, len+1);
1715
1716 p = strstr(buffer, "!DOCTYPE");
1717 if (p == NULL) { /* no entities */
1718 status = 0;
1719 goto error;
1720 }
1721
1722 pv = strstr(p, "[");
1723 if (pv == NULL) { /* no entities */
1724 status = 1;
1725 goto error;
1726 }
1727
1728 p = pv + 1;
1729
1730 /* search !ENTITY */
1731 do {
1732 if (*p == ']')
1733 break;
1734
1735 if (*p == '<') {
1736
1737 /* found new entity */
1738 p++;
1739 while (*p && isspace((unsigned char)*p)) {
1740 if (*p == '\n')
1741 line_number++;
1742 p++;
1743 }
1744 if (!*p) {
1745 read_error(HERE, "Unexpected end of file");
1746 status = 1;
1747 goto error;
1748 }
1749
1750 if (strncmp(p, "!--", 3) == 0) {
1751 /* found comment */
1752 p += 3;
1753 if (strstr(p, "-->") == NULL) {
1754 read_error(HERE, "Unterminated comment");
1755 status = 1;
1756 goto error;
1757 }
1758
1759 while (strncmp(p, "-->", 3) != 0) {
1760 if (*p == '\n')
1761 line_number++;
1762 p++;
1763 }
1764 p += 3;
1765 }
1766
1767 else if (strncmp(p, "!ENTITY", 7) == 0) {
1768 /* found entity */
1769 nentity++;
1770 if (nentity >= MXML_MAX_ENTITY) {
1771 read_error(HERE, "Too much entities");
1772 status = 1;
1773 goto error;
1774 }
1775
1776 entity_line_number[nentity] = line_number;
1777
1778 pv = p + 7;
1779 while (*pv == ' ')
1780 pv++;
1781
1782 /* extract entity name */
1783 p = pv;
1784
1785 while (*p && isspace((unsigned char)*p) && *p != '<' && *p != '>') {
1786 if (*p == '\n')
1787 line_number++;
1788 p++;
1789 }
1790 if (!*p) {
1791 read_error(HERE, "Unexpected end of file");
1792 status = 1;
1793 goto error;
1794 }
1795 if (*p == '<' || *p == '>') {
1796 read_error(HERE, "Unexpected \'%c\' inside !ENTITY", *p);
1797 status = 1;
1798 goto error;
1799 }
1800
1801 pv = p;
1802 while (*pv && !isspace((unsigned char)*pv) && *pv != '<' && *pv != '>')
1803 pv++;
1804
1805 if (!*pv) {
1806 read_error(HERE, "Unexpected end of file");
1807 status = 1;
1808 goto error;
1809 }
1810 if (*pv == '<' || *pv == '>') {
1811 read_error(HERE, "Unexpected \'%c\' inside entity \"%s\"", *pv, &entity_name[nentity][1]);
1812 status = 1;
1813 goto error;
1814 }
1815
1816 entity_name[nentity][0] = '&';
1817 i = 1;
1818 entity_name[nentity][i] = 0;
1819 while (*p && !isspace((unsigned char)*p) && *p != '/' && *p != '>' && *p != '<' && i < 253)
1820 entity_name[nentity][i++] = *p++;
1821 entity_name[nentity][i++] = ';';
1822 entity_name[nentity][i] = 0;
1823
1824 if (!*p) {
1825 read_error(HERE, "Unexpected end of file");
1826 status = 1;
1827 goto error;
1828 }
1829 if (*p == '<') {
1830 read_error(HERE, "Unexpected \'<\' inside entity \"%s\"", &entity_name[nentity][1]);
1831 status = 1;
1832 goto error;
1833 }
1834
1835 /* extract replacement or SYSTEM */
1836 while (*p && isspace((unsigned char)*p)) {
1837 if (*p == '\n')
1838 line_number++;
1839 p++;
1840 }
1841 if (!*p) {
1842 read_error(HERE, "Unexpected end of file");
1843 status = 1;
1844 goto error;
1845 }
1846 if (*p == '>') {
1847 read_error(HERE, "Unexpected \'>\' inside entity \"%s\"", &entity_name[nentity][1]);
1848 status = 1;
1849 goto error;
1850 }
1851
1852 /* check if SYSTEM */
1853 if (strncmp(p, "SYSTEM", 6) == 0) {
1854 entity_type[nentity] = EXTERNAL_ENTITY;
1855 p += 6;
1856 } else {
1857 entity_type[nentity] = INTERNAL_ENTITY;
1858 }
1859
1860 /* extract replacement */
1861 while (*p && isspace((unsigned char)*p)) {
1862 if (*p == '\n')
1863 line_number++;
1864 p++;
1865 }
1866 if (!*p) {
1867 read_error(HERE, "Unexpected end of file");
1868 status = 1;
1869 goto error;
1870 }
1871 if (*p == '>') {
1872 read_error(HERE, "Unexpected \'>\' inside entity \"%s\"", &entity_name[nentity][1]);
1873 status = 1;
1874 goto error;
1875 }
1876
1877 if (*p != '\"' && *p != '\'') {
1878 read_error(HERE, "Replacement was not found for entity \"%s\"", &entity_name[nentity][1]);
1879 status = 1;
1880 goto error;
1881 }
1882 delimiter = *p;
1883 p++;
1884 if (!*p) {
1885 read_error(HERE, "Unexpected end of file");
1886 status = 1;
1887 goto error;
1888 }
1889 pv = p;
1890 while (*pv && *pv != delimiter)
1891 pv++;
1892
1893 if (!*pv) {
1894 read_error(HERE, "Unexpected end of file");
1895 status = 1;
1896 goto error;
1897 }
1898 if (*pv == '<') {
1899 read_error(HERE, "Unexpected \'%c\' inside entity \"%s\"", *pv, &entity_name[nentity][1]);
1900 status = 1;
1901 goto error;
1902 }
1903
1904 len = (int)((size_t) pv - (size_t) p);
1905 replacement = (char *) mxml_malloc(len + 1);
1906 if (replacement == NULL) {
1907 read_error(HERE, "Cannot allocate memory.");
1908 status = 1;
1909 goto error;
1910 }
1911
1912 memcpy(replacement, p, len);
1913 replacement[len] = 0;
1914 mxml_decode(replacement);
1915
1916 if (entity_type[nentity] == EXTERNAL_ENTITY) {
1917 mxml_strlcpy(entity_reference_name[nentity], replacement, sizeof(entity_reference_name[nentity]));
1918 } else {
1919 int rlen = strlen(replacement);
1920 entity_value[nentity] = (char *) mxml_malloc(rlen+1);
1921 if (entity_value[nentity] == NULL) {
1922 read_error(HERE, "Cannot allocate memory.");
1923 status = 1;
1924 goto error;
1925 }
1926 memcpy(entity_value[nentity], replacement, rlen+1);
1927 }
1928 mxml_free(replacement);
1929
1930 p = pv;
1931 while (*p && isspace((unsigned char)*p)) {
1932 if (*p == '\n')
1933 line_number++;
1934 p++;
1935 }
1936 if (!*p) {
1937 read_error(HERE, "Unexpected end of file");
1938 status = 1;
1939 goto error;
1940 }
1941 }
1942 }
1943
1944 /* go to next element */
1945 while (*p && *p != '<') {
1946 if (*p == '\n')
1947 line_number++;
1948 p++;
1949 }
1950 } while (*p);
1951 nentity++;
1952
1953 /* read external file */
1954 for (i = 0; i < nentity; i++) {
1955 if (entity_type[i] == EXTERNAL_ENTITY) {
1956 std::string filename;
1957 if ( entity_reference_name[i][0] == DIR_SEPARATOR ) { /* absolute path */
1958 filename = entity_reference_name[i];
1959 } else { /* relative path */
1960 filename += directoryname;
1961 filename += DIR_SEPARATOR;
1962 filename += entity_reference_name[i];
1963 }
1964 fh = open(filename.c_str(), O_RDONLY | O_TEXT, 0644);
1965
1966 if (fh == -1) {
1967 line_number = entity_line_number[i];
1968 read_error(HERE, "%s is missing", entity_reference_name[i]);
1969 status = 1;
1970 goto error;
1971 } else {
1972 length = (int)lseek(fh, 0, SEEK_END);
1973 lseek(fh, 0, SEEK_SET);
1974 if (length == 0) {
1975 entity_value[i] = (char *) mxml_malloc(1);
1976 if (entity_value[i] == NULL) {
1977 read_error(HERE, "Cannot allocate memory.");
1978 close(fh);
1979 status = 1;
1980 goto error;
1981 }
1982 entity_value[i][0] = 0;
1983 } else {
1984 entity_value[i] = (char *) mxml_malloc(length);
1985 if (entity_value[i] == NULL) {
1986 read_error(HERE, "Cannot allocate memory.");
1987 close(fh);
1988 status = 1;
1989 goto error;
1990 }
1991
1992 /* read complete file at once */
1993 length = (int)read(fh, entity_value[i], length);
1994 entity_value[i][length - 1] = 0;
1995 close(fh);
1996
1997 /* recursive parse */
1998 if (mxml_parse_entity(&entity_value[i], filename.c_str(), error, error_size, error_line) != 0) {
1999 status = 1;
2000 goto error;
2001 }
2002 }
2003 }
2004 }
2005 }
2006
2007 /* count length of output string */
2008 length = (int)strlen(buffer);
2009 for (i = 0; i < nentity; i++) {
2010 p = buffer;
2011 entity_value_length[i] = (int)strlen(entity_value[i]);
2012 entity_name_length[i] = (int)strlen(entity_name[i]);
2013 while (1) {
2014 pv = strstr(p, entity_name[i]);
2015 if (pv) {
2016 length += entity_value_length[i] - entity_name_length[i];
2017 p = pv + 1;
2018 } else {
2019 break;
2020 }
2021 }
2022 }
2023
2024 /* re-allocate memory */
2025 *buf = (char *) mxml_realloc(*buf, length + 1);
2026 if (*buf == NULL) {
2027 read_error(HERE, "Cannot allocate memory.");
2028 status = 1;
2029 goto error;
2030 }
2031
2032 /* replace entities */
2033 p = buffer;
2034 pv = *buf;
2035 do {
2036 if (*p == '&') {
2037 /* found entity */
2038 for (j = 0; j < nentity; j++) {
2039 if (strncmp(p, entity_name[j], entity_name_length[j]) == 0) {
2040 for (k = 0; k < (int) entity_value_length[j]; k++)
2041 *pv++ = entity_value[j][k];
2042 p += entity_name_length[j];
2043 break;
2044 }
2045 }
2046 }
2047 *pv++ = *p++;
2048 } while (*p);
2049 *pv = 0;
2050
2051 mxml_free_tree(root);
2052
2053error:
2054
2055 if (buffer != NULL)
2056 mxml_free(buffer);
2057 for (int ip = 0; ip < MXML_MAX_ENTITY; ip++)
2058 if (entity_value[ip] != NULL)
2059 mxml_free(entity_value[ip]);
2060
2061 return status;
2062}
2063
2064/*------------------------------------------------------------------*/
2065
2066/**
2067 * parse a XML file and convert it into a tree of MXML_NODE's.
2068 * Return NULL in case of an error, return error description
2069 */
2070PMXML_NODE mxml_parse_file(const char *file_name, char *error, int error_size, int *error_line)
2071{
2072 if (error)
2073 error[0] = 0;
2074
2075 int fh = open(file_name, O_RDONLY | O_TEXT, 0644);
2076
2077 if (fh == -1) {
2078 std::string msg = "";
2079 msg += "Cannot open file \"";
2080 msg += file_name;
2081 msg += "\": ";
2082 msg += toStrerror(errno);
2083 mxml_strlcpy(error, msg.c_str(), error_size);
2084 return NULL;
2085 }
2086
2087 off_t length = lseek(fh, 0, SEEK_END);
2088 lseek(fh, 0, SEEK_SET);
2089
2090 char* buf = (char *)mxml_malloc(length+1);
2091 if (buf == NULL) {
2092 close(fh);
2093 std::string msg = "";
2094 msg += "Cannot allocate buffer size ";
2095 msg += toString(length);
2096 msg += " for file \"";
2097 msg += file_name;
2098 msg += "\": ";
2099 msg += toStrerror(errno);
2100 mxml_strlcpy(error, msg.c_str(), error_size);
2101 return NULL;
2102 }
2103
2104 /* read complete file at once */
2105 int rd = read(fh, buf, length);
2106 if (rd != length) {
2107 std::string msg = "";
2108 msg += "Cannot read file \"";
2109 msg += file_name;
2110 msg += "\", read of ";
2111 msg += toString(length);
2112 msg += " returned ";
2113 msg += toString(rd);
2114 msg += ": ";
2115 msg += toStrerror(errno);
2116 mxml_strlcpy(error, msg.c_str(), error_size);
2117 mxml_free(buf);
2118 return NULL;
2119 }
2120
2121 buf[length] = 0;
2122 close(fh);
2123
2124 if (mxml_parse_entity(&buf, file_name, error, error_size, error_line) != 0) {
2125 mxml_free(buf);
2126 return NULL;
2127 }
2128
2129 PMXML_NODE root = mxml_parse_buffer(buf, error, error_size, error_line);
2130
2131 mxml_free(buf);
2132
2133 return root;
2134}
2135
2136/*------------------------------------------------------------------*/
2137
2138/**
2139 * write complete subtree recursively into file opened with mxml_open_document()
2140 */
2141int mxml_write_subtree(MXML_WRITER *writer, PMXML_NODE tree, int indent)
2142{
2143 int i;
2144
2145 mxml_start_element1(writer, tree->name, indent);
2146 for (i=0 ; i<tree->n_attributes ; i++)
2148 return FALSE;
2149
2150 if (tree->value)
2151 if (!mxml_write_value(writer, tree->value))
2152 return FALSE;
2153
2154 for (i=0 ; i<tree->n_children ; i++)
2155 if (!mxml_write_subtree(writer, &tree->child[i], (tree->value == NULL) || i > 0))
2156 return FALSE;
2157
2158 return mxml_end_element(writer);
2159}
2160
2161/*------------------------------------------------------------------*/
2162
2163/**
2164 * write a complete XML tree to a file
2165 */
2166int mxml_write_tree(const char *file_name, PMXML_NODE tree)
2167{
2168 MXML_WRITER *writer;
2169 int i;
2170
2171 assert(tree);
2172 writer = mxml_open_file(file_name);
2173 if (!writer)
2174 return FALSE;
2175
2176 for (i=0 ; i<tree->n_children ; i++)
2177 if (tree->child[i].node_type == ELEMENT_NODE) /* skip PI and comments */
2178 if (!mxml_write_subtree(writer, &tree->child[i], TRUE))
2179 return FALSE;
2180
2181 if (!mxml_close_file(writer))
2182 return FALSE;
2183
2184 return TRUE;
2185}
2186
2187/*------------------------------------------------------------------*/
2188
2189/**
2190 * write a complete XML tree to a buffer
2191 */
2192int mxml_print_tree(char *buffer, int *buffer_size, PMXML_NODE tree)
2193{
2194 int len;
2195 char *p;
2196 MXML_WRITER *writer;
2197
2198 /* open file */
2199 writer = mxml_open_buffer();
2200 if (writer == NULL)
2201 return FALSE;
2202
2203 for (int i=0 ; i<tree->n_children ; i++)
2204 if (tree->child[i].node_type == ELEMENT_NODE) /* skip PI and comments */
2205 if (!mxml_write_subtree(writer, &tree->child[i], TRUE))
2206 return FALSE;
2207
2208 p = mxml_close_buffer(writer);
2209 len = strlen(p) + 1;
2210 if (len > *buffer_size) {
2211 free(p);
2212 *buffer_size = 0;
2213 return FALSE;
2214 }
2215
2216 mxml_strlcpy(buffer, p, *buffer_size);
2217 free(p);
2218 *buffer_size = len;
2219 return TRUE;
2220}
2221
2222/*------------------------------------------------------------------*/
2223
2225{
2226 PMXML_NODE clone;
2227 int i;
2228
2229 clone = (PMXML_NODE)calloc(sizeof(MXML_NODE), 1);
2230
2231 /* copy name, node_type, n_attributes and n_children */
2232 memcpy(clone, tree, sizeof(MXML_NODE));
2233
2234 clone->value = NULL;
2235 mxml_replace_node_value(clone, tree->value);
2236
2237 clone->attribute_name = NULL;
2238 clone->attribute_value = NULL;
2239 for (i=0 ; i<tree->n_attributes ; i++)
2241
2242 clone->child = NULL;
2243 clone->n_children = 0;
2244 for (i=0 ; i<tree->n_children ; i++)
2245 mxml_add_tree(clone, mxml_clone_tree(mxml_subnode(tree, i)));
2246
2247 return clone;
2248}
2249
2250/*------------------------------------------------------------------*/
2251
2252/**
2253 * print XML tree for debugging
2254 */
2255void mxml_debug_tree(PMXML_NODE tree, int level)
2256{
2257 int i, j;
2258
2259 for (i=0 ; i<level ; i++)
2260 printf(" ");
2261 printf("Name: %s\n", tree->name);
2262 for (i=0 ; i<level ; i++)
2263 printf(" ");
2264 printf("Valu: %s\n", tree->value);
2265 for (i=0 ; i<level ; i++)
2266 printf(" ");
2267 printf("Type: %d\n", tree->node_type);
2268 for (i=0 ; i<level ; i++)
2269 printf(" ");
2270 printf("Lin1: %d\n", tree->line_number_start);
2271 for (i=0 ; i<level ; i++)
2272 printf(" ");
2273 printf("Lin2: %d\n", tree->line_number_end);
2274
2275 for (j=0 ; j<tree->n_attributes ; j++) {
2276 for (i=0 ; i<level ; i++)
2277 printf(" ");
2278 printf("%s: %s\n", tree->attribute_name+j*MXML_NAME_LENGTH,
2279 tree->attribute_value[j]);
2280 }
2281
2282 for (i=0 ; i<level ; i++)
2283 printf(" ");
2284 printf("Addr: %08zX\n", (size_t)tree);
2285 for (i=0 ; i<level ; i++)
2286 printf(" ");
2287 printf("Prnt: %08zX\n", (size_t)tree->parent);
2288 for (i=0 ; i<level ; i++)
2289 printf(" ");
2290 printf("NCld: %d\n", tree->n_children);
2291
2292 for (i=0 ; i<tree->n_children ; i++)
2293 mxml_debug_tree(tree->child+i, level+1);
2294
2295 if (level == 0)
2296 printf("\n");
2297}
2298
2299/*------------------------------------------------------------------*/
2300
2301/**
2302 * free memory of XML tree, must be called after any
2303 * mxml_create_root_node() or mxml_parse_file()
2304 */
2306{
2307 int i;
2308
2309 /* first free children recursively */
2310 for (i=0 ; i<tree->n_children ; i++)
2311 mxml_free_tree(&tree->child[i]);
2312 if (tree->n_children)
2313 mxml_free(tree->child);
2314
2315 /* now free dynamic data */
2316 for (i=0 ; i<tree->n_attributes ; i++)
2317 mxml_free(tree->attribute_value[i]);
2318
2319 if (tree->n_attributes) {
2322 }
2323
2324 if (tree->value)
2325 mxml_free(tree->value);
2326
2327 /* if we are the root node, free it */
2328 if (tree->parent == NULL)
2329 mxml_free(tree);
2330}
2331
2332/*------------------------------------------------------------------*/
2333
2334/*
2335void mxml_test()
2336{
2337 char err[256];
2338 PMXML_NODE tree, tree2, node;
2339
2340 tree = mxml_parse_file("c:\\tmp\\test.xml", err, sizeof(err));
2341 tree2 = mxml_clone_tree(tree);
2342
2343 printf("Orig:\n");
2344 mxml_debug_tree(tree, 0);
2345
2346 printf("\nClone:\n");
2347 mxml_debug_tree(tree2, 0);
2348
2349 printf("\nCombined:\n");
2350 node = mxml_find_node(tree2, "cddb");
2351 mxml_add_tree(tree, node);
2352 mxml_debug_tree(tree, 0);
2353
2354 mxml_free_tree(tree);
2355}
2356*/
2357
2358/*------------------------------------------------------------------*/
2359 /**
2360 mxml_basename deletes any prefix ending with the last slash '/' character
2361 present in path. mxml_dirname deletes the filename portion, beginning with
2362 the last slash '/' character to the end of path. Followings are examples
2363 from these functions
2364
2365 path dirname basename
2366 "/" "/" ""
2367 "." "." "."
2368 "" "" ""
2369 "/test.txt" "/" "test.txt"
2370 "path/to/test.txt" "path/to" "test.txt"
2371 "test.txt "." "test.txt"
2372
2373 Under Windows, '\\' and ':' are recognized ad separator too.
2374 */
2375
2376void mxml_basename(char *path)
2377{
2378 char str[FILENAME_MAX];
2379 char *p;
2380 char *name;
2381
2382 if (path) {
2383 strcpy(str, path);
2384 p = str;
2385 name = str;
2386 while (1) {
2387 if (*p == 0)
2388 break;
2389 if (*p == '/'
2390#ifdef _MSC_VER
2391 || *p == ':' || *p == '\\'
2392#endif
2393 )
2394 name = p + 1;
2395 p++;
2396 }
2397 strcpy(path, name);
2398 }
2399
2400 return;
2401}
2402
2403void mxml_dirname(char *path)
2404{
2405 char *p;
2406#ifdef _MSC_VER
2407 char *pv;
2408#endif
2409
2410 if (!path || strlen(path) == 0)
2411 return;
2412
2413 p = strrchr(path, '/');
2414#ifdef _MSC_VER
2415 pv = strrchr(path, ':');
2416 if (pv > p)
2417 p = pv;
2418 pv = strrchr(path, '\\');
2419 if (pv > p)
2420 p = pv;
2421#endif
2422
2423 if (p == 0) /* current directory */
2424 strcpy(path, ".");
2425 else if (p == path) /* root directory */
2426 snprintf(path, FILENAME_MAX, "%c", *p);
2427 else
2428 *p = 0;
2429
2430 return;
2431}
2432
2433/*------------------------------------------------------------------*/
2434
2435/**
2436 * Retieve node at a certain line number
2437 */
2439{
2440 int i;
2441 PMXML_NODE pn;
2442
2443 if (tree->line_number_start == line_number)
2444 return tree;
2445
2446 for (i=0 ; i<tree->n_children ; i++) {
2447 pn = mxml_get_node_at_line(&tree->child[i], line_number);
2448 if (pn)
2449 return pn;
2450 }
2451
2452 return NULL;
2453}
2454
2455/* emacs
2456 * Local Variables:
2457 * tab-width: 8
2458 * c-basic-offset: 3
2459 * indent-tabs-mode: nil
2460 * End:
2461 */
char * dst
Definition mlz4.h:354
#define DIR_SEPARATOR
Definition mxml.h:48
#define COMMENT_NODE
Definition mxml.h:36
#define PROCESSING_INSTRUCTION_NODE
Definition mxml.h:35
#define EXTERNAL_ENTITY
Definition mxml.h:40
#define ELEMENT_NODE
Definition mxml.h:33
#define MXML_MAX_ENTITY
Definition mxml.h:41
#define DOCUMENT_NODE
Definition mxml.h:37
struct mxml_struct * PMXML_NODE
Definition mxml.h:63
#define INTERNAL_ENTITY
Definition mxml.h:39
#define MXML_MAX_CONDITION
Definition mxml.h:43
#define MXML_NAME_LENGTH
Definition mxml.h:31
void mxml_free_tree(PMXML_NODE tree)
Definition mxml.cxx:2305
char * mxml_close_buffer(MXML_WRITER *writer)
Definition mxml.cxx:632
int mxml_write_comment(MXML_WRITER *writer, const char *string)
Definition mxml.cxx:590
MXML_WRITER * mxml_open_buffer(void)
Definition mxml.cxx:223
PMXML_NODE mxml_parse_file(const char *file_name, char *error, int error_size, int *error_line)
Definition mxml.cxx:2070
PMXML_NODE mxml_add_special_node(PMXML_NODE parent, int node_type, const char *node_name, const char *value)
Definition mxml.cxx:745
int mxml_get_line_number_start(PMXML_NODE pnode)
Definition mxml.cxx:1119
int mxml_start_element(MXML_WRITER *writer, const char *name)
Definition mxml.cxx:466
int mxml_add_attribute(PMXML_NODE pnode, const char *attrib_name, const char *attrib_value)
Definition mxml.cxx:842
static std::string toStrerror(int err)
Definition mxml.cxx:168
static void * mxml_realloc(void *p, size_t size)
Definition mxml.cxx:184
int mxml_end_element(MXML_WRITER *writer)
Definition mxml.cxx:483
#define XML_INDENT
Definition mxml.cxx:97
int mxml_replace_subvalue(PMXML_NODE pnode, const char *name, const char *value)
Definition mxml.cxx:1184
void mxml_dirname(char *path)
Definition mxml.cxx:2403
#define HERE
Definition mxml.cxx:1308
static int mxml_start_element1(MXML_WRITER *writer, const char *name, int indent)
Definition mxml.cxx:429
PMXML_NODE mxml_find_node(PMXML_NODE tree, const char *xml_path)
Definition mxml.cxx:1078
void mxml_suppress_date(int suppress)
Definition mxml.cxx:261
static void * mxml_malloc(size_t size)
Definition mxml.cxx:177
int mxml_delete_node(PMXML_NODE pnode)
Definition mxml.cxx:1245
static int mxml_write_line(MXML_WRITER *writer, const char *line)
Definition mxml.cxx:198
int mxml_replace_node_value(PMXML_NODE pnode, const char *value)
Definition mxml.cxx:1157
int mxml_replace_attribute_name(PMXML_NODE pnode, const char *old_name, const char *new_name)
Definition mxml.cxx:1203
PMXML_NODE mxml_parse_buffer(const char *buf, char *error, int error_size, int *error_line)
Definition mxml.cxx:1355
static size_t mxml_strlcpy(char *dst, const char *src, size_t size)
Definition mxml.cxx:133
static int mxml_add_resultnode(PMXML_NODE node, const char *xml_path, PMXML_NODE **nodelist, int *found)
Definition mxml.cxx:891
int mxml_write_tree(const char *file_name, PMXML_NODE tree)
Definition mxml.cxx:2166
int mxml_find_nodes(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist)
Definition mxml.cxx:1060
PMXML_NODE mxml_get_parent(PMXML_NODE pnode)
Definition mxml.cxx:1095
PMXML_NODE mxml_clone_tree(PMXML_NODE tree)
Definition mxml.cxx:2224
int mxml_close_file(MXML_WRITER *writer)
Definition mxml.cxx:657
int mxml_write_attribute(MXML_WRITER *writer, const char *name, const char *value)
Definition mxml.cxx:523
PMXML_NODE mxml_subnode(PMXML_NODE pnode, int idx)
Definition mxml.cxx:878
static PMXML_NODE read_error(PMXML_NODE root, const char *file_name, int line_number, char *error, int error_size, int *error_line, const char *format,...) MXML_GNUC_PRINTF(7
Definition mxml.cxx:1313
static void mxml_decode(char *str)
Definition mxml.cxx:375
int mxml_write_empty_line(MXML_WRITER *writer)
Definition mxml.cxx:572
static int mxml_suppress_date_flag
Definition mxml.cxx:112
int mxml_replace_node_name(PMXML_NODE pnode, const char *name)
Definition mxml.cxx:1149
int mxml_delete_attribute(PMXML_NODE pnode, const char *attrib_name)
Definition mxml.cxx:1278
PMXML_NODE mxml_add_node_at(PMXML_NODE parent, const char *node_name, const char *value, int idx)
Definition mxml.cxx:765
PMXML_NODE mxml_create_root_node(void)
Definition mxml.cxx:681
int mxml_add_tree_at(PMXML_NODE parent, PMXML_NODE tree, int idx)
Definition mxml.cxx:775
#define O_TEXT
Definition mxml.cxx:79
MXML_WRITER * mxml_open_file(const char *file_name)
Definition mxml.cxx:271
int mxml_parse_entity(char **buf, const char *file_name, char *error, int error_size, int *error_line)
Definition mxml.cxx:1673
int mxml_write_value(MXML_WRITER *writer, const char *data)
Definition mxml.cxx:547
void mxml_basename(char *path)
Definition mxml.cxx:2376
char * mxml_get_value(PMXML_NODE pnode)
Definition mxml.cxx:1111
#define TRUE
Definition mxml.cxx:75
#define FALSE
Definition mxml.cxx:76
static int mxml_write_subtree(MXML_WRITER *writer, PMXML_NODE tree, int indent)
Definition mxml.cxx:2141
PMXML_NODE mxml_get_node_at_line(PMXML_NODE tree, int line_number)
Definition mxml.cxx:2438
static PMXML_NODE static void mxml_encode(char *buf, int buf_size, const char *src, int src_len, int translate)
Definition mxml.cxx:315
static int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found)
Definition mxml.cxx:923
int mxml_get_line_number_end(PMXML_NODE pnode)
Definition mxml.cxx:1127
#define MXML_GNUC_PRINTF(format_idx, arg_idx)
Definition mxml.cxx:107
static void mxml_free(void *p)
Definition mxml.cxx:191
int mxml_write_element(MXML_WRITER *writer, const char *name, const char *value)
Definition mxml.cxx:617
static std::string toString(int i)
Definition mxml.cxx:159
PMXML_NODE mxml_add_special_node_at(PMXML_NODE parent, int node_type, const char *node_name, const char *value, int idx)
Definition mxml.cxx:697
int mxml_replace_attribute_value(PMXML_NODE pnode, const char *attrib_name, const char *attrib_value)
Definition mxml.cxx:1223
void mxml_debug_tree(PMXML_NODE tree, int level)
Definition mxml.cxx:2255
char * mxml_get_name(PMXML_NODE pnode)
Definition mxml.cxx:1103
char * mxml_get_attribute(PMXML_NODE pnode, const char *name)
Definition mxml.cxx:1135
int mxml_get_number_of_children(PMXML_NODE pnode)
Definition mxml.cxx:867
int mxml_start_element_noindent(MXML_WRITER *writer, const char *name)
Definition mxml.cxx:473
int mxml_print_tree(char *buffer, int *buffer_size, PMXML_NODE tree)
Definition mxml.cxx:2192
int mxml_add_tree(PMXML_NODE parent, PMXML_NODE tree)
Definition mxml.cxx:832
PMXML_NODE mxml_add_node(PMXML_NODE parent, const char *node_name, const char *value)
Definition mxml.cxx:755
int mxml_set_translate(MXML_WRITER *writer, int flag)
Definition mxml.cxx:416
int element_is_open
Definition mxml.h:57
int level
Definition mxml.h:56
int data_was_written
Definition mxml.h:58
char * buffer
Definition mxml.h:53
int translate
Definition mxml.h:60
int buffer_size
Definition mxml.h:54
int buffer_len
Definition mxml.h:55
char ** stack
Definition mxml.h:59
int fh
Definition mxml.h:52
int node_type
Definition mxml.h:67
char * value
Definition mxml.h:68
int n_children
Definition mxml.h:75
PMXML_NODE parent
Definition mxml.h:74
char name[MXML_NAME_LENGTH]
Definition mxml.h:66
int line_number_start
Definition mxml.h:72
char * attribute_name
Definition mxml.h:70
int line_number_end
Definition mxml.h:73
char ** attribute_value
Definition mxml.h:71
int n_attributes
Definition mxml.h:69
PMXML_NODE child
Definition mxml.h:76