PageRenderTime 33ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/mxml.cxx

https://bitbucket.org/muegamma/rome3
C++ | 2373 lines | 1600 code | 399 blank | 374 comment | 608 complexity | d80d03cb437b773bd8ef2138e1352413 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /********************************************************************\
  2. Name: mxml.c
  3. Created by: Stefan Ritt
  4. Copyright 2000 + Stefan Ritt
  5. Contents: Midas XML Library
  6. This is a simple implementation of XML functions for writing and
  7. reading XML files. For writing an XML file from scratch, following
  8. functions can be used:
  9. writer = mxml_open_file(file_name);
  10. mxml_start_element(writer, name);
  11. mxml_write_attribute(writer, name, value);
  12. mxml_write_value(writer, value);
  13. mxml_end_element(writer);
  14. ...
  15. mxml_close_file(writer);
  16. To read an XML file, the function
  17. tree = mxml_parse_file(file_name, error, sizeof(error));
  18. is used. It parses the complete XML file and stores it in a
  19. hierarchical tree in memory. Nodes in that tree can be searched
  20. for with
  21. mxml_find_node(tree, xml_path);
  22. or
  23. mxml_find_nodes(tree, xml_path, &nodelist);
  24. which support a subset of the XPath specification. Another set of
  25. functions is availabe to retrieve attributes and values from nodes
  26. in the tree and for manipulating nodes, like replacing, adding and
  27. deleting nodes.
  28. This file is part of MIDAS XML Library.
  29. MIDAS XML Library is free software: you can redistribute it and/or modify
  30. it under the terms of the GNU General Public License as published by
  31. the Free Software Foundation, either version 2 of the License, or
  32. (at your option) any later version.
  33. MIDAS XML Library is distributed in the hope that it will be useful,
  34. but WITHOUT ANY WARRANTY; without even the implied warranty of
  35. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  36. GNU General Public License for more details.
  37. You should have received a copy of the GNU General Public License
  38. along with MIDAS XML Library. If not, see <http://www.gnu.org/licenses/>.
  39. \********************************************************************/
  40. #include <stdio.h>
  41. #include <fcntl.h>
  42. #include <string.h>
  43. #include <assert.h>
  44. #include <string>
  45. #ifdef _MSC_VER
  46. #include <windows.h>
  47. #include <io.h>
  48. #include <time.h>
  49. #pragma warning( disable: 4996) /* disable "deprecated" warning */
  50. #else
  51. #define TRUE 1
  52. #define FALSE 0
  53. #ifndef O_TEXT
  54. #define O_TEXT 0
  55. #define O_BINARY 0
  56. #endif
  57. #include <stdlib.h>
  58. #include <unistd.h>
  59. #include <ctype.h>
  60. #include <stdarg.h>
  61. #include <errno.h>
  62. #ifndef OS_VXWORKS
  63. #include <sys/time.h>
  64. #endif
  65. #include <time.h>
  66. #endif
  67. #include "mxml.h"
  68. #define XML_INDENT " "
  69. #if defined(__GNUC__) && !defined(__MAKECINT__)
  70. # define MXML_GNUC_PRINTF( format_idx, arg_idx ) \
  71. __attribute__((format (printf, format_idx, arg_idx)))
  72. # define MXML_GNUC_SCANF( format_idx, arg_idx ) \
  73. __attribute__((format (scanf, format_idx, arg_idx)))
  74. # define MXML_GNUC_FORMAT( arg_idx ) \
  75. __attribute__((format_arg (arg_idx)))
  76. #else
  77. # define MXML_GNUC_PRINTF( format_idx, arg_idx )
  78. # define MXML_GNUC_SCANF( format_idx, arg_idx )
  79. # define MXML_GNUC_FORMAT( arg_idx )
  80. #endif
  81. static int mxml_suppress_date_flag = 0; /* suppress writing date at the top of file. */
  82. /* local prototypes */
  83. 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, 8);
  84. static void mxml_encode(char* buf, int buf_size, const char *src, int src_len, int translate);
  85. static void mxml_decode(char *str);
  86. static int mxml_write_subtree(MXML_WRITER *writer, PMXML_NODE tree, int indent);
  87. static int mxml_write_line(MXML_WRITER *writer, const char *line);
  88. static int mxml_start_element1(MXML_WRITER *writer, const char *name, int indent);
  89. static int mxml_add_resultnode(PMXML_NODE node, const char *xml_path, PMXML_NODE **nodelist, int *found);
  90. static int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found);
  91. static void *mxml_malloc(size_t size);
  92. static void *mxml_realloc(void *p, size_t size);
  93. static void mxml_free(void *p);
  94. /*
  95. * Copy src to string dst of size siz. At most siz-1 characters
  96. * will be copied. Always NUL terminates (unless size == 0).
  97. * Returns strlen(src); if retval >= siz, truncation occurred.
  98. */
  99. static size_t mxml_strlcpy(char *dst, const char *src, size_t size)
  100. {
  101. char *d = dst;
  102. const char *s = src;
  103. size_t n = size;
  104. /* Copy as many bytes as will fit */
  105. if (n != 0 && --n != 0) {
  106. do {
  107. if ((*d++ = *s++) == 0)
  108. break;
  109. } while (--n != 0);
  110. }
  111. /* Not enough room in dst, add NUL and traverse rest of src */
  112. if (n == 0) {
  113. if (size != 0)
  114. *d = '\0'; /* NUL-terminate dst */
  115. while (*s++);
  116. }
  117. return (s - src - 1); /* count does not include NUL */
  118. }
  119. /*------------------------------------------------------------------*/
  120. void *mxml_malloc(size_t size)
  121. {
  122. return malloc(size);
  123. }
  124. /*------------------------------------------------------------------*/
  125. void *mxml_realloc(void *p, size_t size)
  126. {
  127. return realloc(p, size);
  128. }
  129. /*------------------------------------------------------------------*/
  130. void mxml_free(void *p)
  131. {
  132. free(p);
  133. }
  134. /*------------------------------------------------------------------*/
  135. int mxml_write_line(MXML_WRITER *writer, const char *line)
  136. {
  137. unsigned len;
  138. len = strlen(line);
  139. if (writer->buffer) {
  140. if (writer->buffer_len + (int)len >= writer->buffer_size) {
  141. writer->buffer_size += len + 10000;
  142. writer->buffer = (char *)mxml_realloc(writer->buffer, writer->buffer_size);
  143. assert(writer->buffer);
  144. }
  145. strcpy(writer->buffer + writer->buffer_len, line);
  146. writer->buffer_len += len;
  147. return len;
  148. } else {
  149. return (int)write(writer->fh, line, len);
  150. }
  151. return 0;
  152. }
  153. /*------------------------------------------------------------------*/
  154. /**
  155. * open a memory buffer and write XML header
  156. */
  157. MXML_WRITER *mxml_open_buffer(void)
  158. {
  159. char str[256], line[1000];
  160. time_t now;
  161. MXML_WRITER *writer;
  162. writer = (MXML_WRITER *)mxml_malloc(sizeof(MXML_WRITER));
  163. memset(writer, 0, sizeof(MXML_WRITER));
  164. writer->translate = 1;
  165. writer->buffer_size = 10000;
  166. writer->buffer = (char *)mxml_malloc(10000);
  167. writer->buffer[0] = 0;
  168. writer->buffer_len = 0;
  169. /* write XML header */
  170. strcpy(line, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
  171. mxml_write_line(writer, line);
  172. time(&now);
  173. strcpy(str, ctime(&now));
  174. str[24] = 0;
  175. sprintf(line, "<!-- created by MXML on %s -->\n", str);
  176. if (mxml_suppress_date_flag == 0)
  177. mxml_write_line(writer, line);
  178. /* initialize stack */
  179. writer->level = 0;
  180. writer->element_is_open = 0;
  181. return writer;
  182. }
  183. /*------------------------------------------------------------------*/
  184. /**
  185. * suppress writing date at the top of file.
  186. */
  187. void mxml_suppress_date(int suppress)
  188. {
  189. mxml_suppress_date_flag = suppress;
  190. }
  191. /*------------------------------------------------------------------*/
  192. /**
  193. * open a file and write XML header
  194. */
  195. MXML_WRITER *mxml_open_file(const char *file_name)
  196. {
  197. char str[256], line[1000];
  198. time_t now;
  199. MXML_WRITER *writer;
  200. writer = (MXML_WRITER *)mxml_malloc(sizeof(MXML_WRITER));
  201. memset(writer, 0, sizeof(MXML_WRITER));
  202. writer->translate = 1;
  203. writer->fh = open(file_name, O_RDWR | O_CREAT | O_TRUNC | O_TEXT, 0644);
  204. if (writer->fh == -1) {
  205. sprintf(line, "Unable to open file \"%s\": ", file_name);
  206. perror(line);
  207. mxml_free(writer);
  208. return NULL;
  209. }
  210. /* write XML header */
  211. strcpy(line, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
  212. mxml_write_line(writer, line);
  213. time(&now);
  214. strcpy(str, ctime(&now));
  215. str[24] = 0;
  216. sprintf(line, "<!-- created by MXML on %s -->\n", str);
  217. if (mxml_suppress_date_flag == 0)
  218. mxml_write_line(writer, line);
  219. /* initialize stack */
  220. writer->level = 0;
  221. writer->element_is_open = 0;
  222. return writer;
  223. }
  224. /*------------------------------------------------------------------*/
  225. /**
  226. * convert '<' '>' '&' '"' ''' into &xx;
  227. */
  228. void mxml_encode(char* buf, int buf_size, const char *src, int src_len, int translate)
  229. {
  230. assert(buf_size > 6*src_len); // each input byte is expanded into 6 bytes at most
  231. char *pd = buf;
  232. const char* ps;
  233. for (ps = src ; *ps ; ps++) {
  234. if (translate) { /* tranlate "<", ">", "&", """, "'" */
  235. switch (*ps) {
  236. case '<':
  237. strcpy(pd, "&lt;");
  238. pd += 4;
  239. break;
  240. case '>':
  241. strcpy(pd, "&gt;");
  242. pd += 4;
  243. break;
  244. case '&':
  245. strcpy(pd, "&amp;");
  246. pd += 5;
  247. break;
  248. case '\"':
  249. strcpy(pd, "&quot;");
  250. pd += 6;
  251. break;
  252. case '\'':
  253. strcpy(pd, "&apos;");
  254. pd += 6;
  255. break;
  256. default:
  257. *pd++ = *ps;
  258. }
  259. } else {
  260. switch (*ps) { /* translate only special XML characters "<" and "&" */
  261. case '<':
  262. strcpy(pd, "&lt;");
  263. pd += 4;
  264. break;
  265. case '&':
  266. strcpy(pd, "&amp;");
  267. pd += 5;
  268. break;
  269. default:
  270. *pd++ = *ps;
  271. }
  272. }
  273. }
  274. *pd = 0;
  275. //printf("mxml_encode: size %d, in %d, out %d, [%s] -> [%s]\n", buf_size, src_len, (int)strlen(buf), src, buf);
  276. }
  277. /*------------------------------------------------------------------*/
  278. /**
  279. * reverse of mxml_encode, strip leading or trailing '"'
  280. */
  281. void mxml_decode(char *str)
  282. {
  283. char *p;
  284. p = str;
  285. while ((p = strchr(p, '&')) != NULL) {
  286. if (strncmp(p, "&lt;", 4) == 0) {
  287. *(p++) = '<';
  288. memmove(p, p+3, strlen(p+3) + 1);
  289. }
  290. else if (strncmp(p, "&gt;", 4) == 0) {
  291. *(p++) = '>';
  292. memmove(p, p+3, strlen(p+3) + 1);
  293. }
  294. else if (strncmp(p, "&amp;", 5) == 0) {
  295. *(p++) = '&';
  296. memmove(p, p+4, strlen(p+4) + 1);
  297. }
  298. else if (strncmp(p, "&quot;", 6) == 0) {
  299. *(p++) = '\"';
  300. memmove(p, p+5, strlen(p+5) + 1);
  301. }
  302. else if (strncmp(p, "&apos;", 6) == 0) {
  303. *(p++) = '\'';
  304. memmove(p, p+5, strlen(p+5) + 1);
  305. }
  306. else {
  307. p++; // skip unknown entity
  308. }
  309. }
  310. /* if (str[0] == '\"' && str[strlen(str)-1] == '\"') {
  311. memmove(str, str+1, strlen(str+1) + 1);
  312. str[strlen(str)-1] = 0;
  313. }*/
  314. }
  315. /*------------------------------------------------------------------*/
  316. /**
  317. * set translation of <,>,",',&, on/off in writer
  318. */
  319. int mxml_set_translate(MXML_WRITER *writer, int flag)
  320. {
  321. int old_flag;
  322. old_flag = writer->translate;
  323. writer->translate = flag;
  324. return old_flag;
  325. }
  326. /*------------------------------------------------------------------*/
  327. /**
  328. * start a new XML element, must be followed by mxml_end_elemnt
  329. */
  330. int mxml_start_element1(MXML_WRITER *writer, const char *name, int indent)
  331. {
  332. int i;
  333. if (writer->element_is_open) {
  334. mxml_write_line(writer, ">\n");
  335. writer->element_is_open = FALSE;
  336. }
  337. std::string line = "";
  338. if (indent)
  339. for (i=0 ; i<writer->level ; i++)
  340. line += XML_INDENT;
  341. line += "<";
  342. unsigned len = strlen(name);
  343. unsigned name_enc_size = len*6+10;
  344. char* name_enc = (char*)mxml_malloc(name_enc_size);
  345. mxml_encode(name_enc, name_enc_size, name, strlen(name), writer->translate);
  346. line += name_enc;
  347. /* put element on stack */
  348. if (writer->level == 0)
  349. writer->stack = (char **)mxml_malloc(sizeof(char *));
  350. else
  351. writer->stack = (char **)mxml_realloc(writer->stack, sizeof(char *)*(writer->level+1));
  352. writer->stack[writer->level] = name_enc;
  353. writer->level++;
  354. writer->element_is_open = TRUE;
  355. writer->data_was_written = FALSE;
  356. return mxml_write_line(writer, line.c_str()) == (int)line.length();
  357. }
  358. /*------------------------------------------------------------------*/
  359. int mxml_start_element(MXML_WRITER *writer, const char *name)
  360. {
  361. return mxml_start_element1(writer, name, TRUE);
  362. }
  363. /*------------------------------------------------------------------*/
  364. int mxml_start_element_noindent(MXML_WRITER *writer, const char *name)
  365. {
  366. return mxml_start_element1(writer, name, FALSE);
  367. }
  368. /*------------------------------------------------------------------*/
  369. /**
  370. * close an open XML element
  371. */
  372. int mxml_end_element(MXML_WRITER *writer)
  373. {
  374. int i;
  375. if (writer->level == 0)
  376. return 0;
  377. writer->level--;
  378. if (writer->element_is_open) {
  379. writer->element_is_open = FALSE;
  380. mxml_free(writer->stack[writer->level]);
  381. if (writer->level == 0)
  382. mxml_free(writer->stack);
  383. char line[10];
  384. strcpy(line, "/>\n");
  385. return mxml_write_line(writer, line) == (int)strlen(line);
  386. }
  387. std::string line = "";
  388. if (!writer->data_was_written) {
  389. for (i=0 ; i<writer->level ; i++)
  390. line += XML_INDENT;
  391. }
  392. line += "</";
  393. line += writer->stack[writer->level];
  394. mxml_free(writer->stack[writer->level]);
  395. if (writer->level == 0)
  396. mxml_free(writer->stack);
  397. line += ">\n";
  398. writer->data_was_written = FALSE;
  399. return mxml_write_line(writer, line.c_str()) == (int)line.length();
  400. }
  401. /*------------------------------------------------------------------*/
  402. /**
  403. * write an attribute to the currently open XML element
  404. */
  405. int mxml_write_attribute(MXML_WRITER *writer, const char *name, const char *value)
  406. {
  407. char buf[6*4096+10];
  408. if (!writer->element_is_open)
  409. return FALSE;
  410. std::string line = "";
  411. line += " ";
  412. mxml_encode(buf, sizeof(buf), name, strlen(name), writer->translate);
  413. line += buf;
  414. line += "=\"";
  415. mxml_encode(buf, sizeof(buf), value, strlen(value), writer->translate);
  416. line += buf;
  417. line += "\"";
  418. return mxml_write_line(writer, line.c_str()) == (int)line.length();
  419. }
  420. /*------------------------------------------------------------------*/
  421. /**
  422. * write value of an XML element, like <[name]>[value]</[name]>
  423. */
  424. int mxml_write_value(MXML_WRITER *writer, const char *data)
  425. {
  426. if (!writer->element_is_open)
  427. return FALSE;
  428. if (mxml_write_line(writer, ">") != 1)
  429. return FALSE;
  430. writer->element_is_open = FALSE;
  431. writer->data_was_written = TRUE;
  432. unsigned len = strlen(data);
  433. unsigned size = 6*len + 1000;
  434. char* buf = (char*)mxml_malloc(size);
  435. strcpy(buf, data);
  436. mxml_encode(buf, size, data, len, writer->translate);
  437. int v = mxml_write_line(writer, buf) == (int)strlen(buf);
  438. mxml_free(buf);
  439. return v;
  440. }
  441. /*------------------------------------------------------------------*/
  442. /**
  443. * write empty line
  444. */
  445. int mxml_write_empty_line(MXML_WRITER *writer)
  446. {
  447. if (writer->element_is_open) {
  448. mxml_write_line(writer, ">\n");
  449. writer->element_is_open = FALSE;
  450. }
  451. if (mxml_write_line(writer, "\n") != 1)
  452. return FALSE;
  453. return TRUE;
  454. }
  455. /*------------------------------------------------------------------*/
  456. /**
  457. * write a comment to an XML file, enclosed in "<!--" and "-->"
  458. */
  459. int mxml_write_comment(MXML_WRITER *writer, const char *string)
  460. {
  461. int i;
  462. if (writer->element_is_open) {
  463. mxml_write_line(writer, ">\n");
  464. writer->element_is_open = FALSE;
  465. }
  466. std::string line = "";
  467. for (i=0 ; i<writer->level ; i++)
  468. line += XML_INDENT;
  469. line += "<!-- ";
  470. line += string;
  471. line += " -->\n";
  472. if (mxml_write_line(writer, line.c_str()) != (int)line.length())
  473. return FALSE;
  474. return TRUE;
  475. }
  476. /*------------------------------------------------------------------*/
  477. /**
  478. * shortcut to write an element with a value but without attribute
  479. */
  480. int mxml_write_element(MXML_WRITER *writer, const char *name, const char *value)
  481. {
  482. int i;
  483. i = mxml_start_element(writer, name);
  484. i += mxml_write_value(writer, value);
  485. i += mxml_end_element(writer);
  486. return i;
  487. }
  488. /*------------------------------------------------------------------*/
  489. /**
  490. * close a file opened with mxml_open_writer
  491. */
  492. char *mxml_close_buffer(MXML_WRITER *writer)
  493. {
  494. int i;
  495. char *p;
  496. if (writer->element_is_open) {
  497. writer->element_is_open = FALSE;
  498. if (mxml_write_line(writer, ">\n") != 2)
  499. return NULL;
  500. }
  501. /* close remaining open levels */
  502. for (i = 0 ; i<writer->level ; i++)
  503. mxml_end_element(writer);
  504. p = writer->buffer;
  505. mxml_free(writer);
  506. return p;
  507. }
  508. /*------------------------------------------------------------------*/
  509. /**
  510. * close a file opened with mxml_open_writer
  511. */
  512. int mxml_close_file(MXML_WRITER *writer)
  513. {
  514. int i;
  515. if (writer->element_is_open) {
  516. writer->element_is_open = FALSE;
  517. if (mxml_write_line(writer, ">\n") != 2)
  518. return 0;
  519. }
  520. /* close remaining open levels */
  521. for (i = 0 ; i<writer->level ; i++)
  522. mxml_end_element(writer);
  523. close(writer->fh);
  524. mxml_free(writer);
  525. return 1;
  526. }
  527. /*------------------------------------------------------------------*/
  528. /**
  529. * create root node of an XML tree
  530. */
  531. PMXML_NODE mxml_create_root_node(void)
  532. {
  533. PMXML_NODE root;
  534. root = (PMXML_NODE)calloc(sizeof(MXML_NODE), 1);
  535. strcpy(root->name, "root");
  536. root->node_type = DOCUMENT_NODE;
  537. return root;
  538. }
  539. /*------------------------------------------------------------------*/
  540. /**
  541. * add a subnode (child) to an existing parent node as a specific position
  542. */
  543. PMXML_NODE mxml_add_special_node_at(PMXML_NODE parent, int node_type, const char *node_name, const char *value, int idx)
  544. {
  545. PMXML_NODE pnode, pchild;
  546. int i, j;
  547. assert(parent);
  548. if (parent->n_children == 0)
  549. parent->child = (PMXML_NODE)mxml_malloc(sizeof(MXML_NODE));
  550. else
  551. parent->child = (PMXML_NODE)mxml_realloc(parent->child, sizeof(MXML_NODE)*(parent->n_children+1));
  552. assert(parent->child);
  553. /* move following nodes one down */
  554. if (idx < parent->n_children)
  555. for (i=parent->n_children ; i > idx ; i--)
  556. memcpy(&parent->child[i], &parent->child[i-1], sizeof(MXML_NODE));
  557. /* correct parent pointer for children */
  558. for (i=0 ; i<parent->n_children ; i++) {
  559. pchild = parent->child+i;
  560. for (j=0 ; j<pchild->n_children ; j++)
  561. pchild->child[j].parent = pchild;
  562. }
  563. /* initialize new node */
  564. pnode = &parent->child[idx];
  565. memset(pnode, 0, sizeof(MXML_NODE));
  566. mxml_strlcpy(pnode->name, node_name, sizeof(pnode->name));
  567. pnode->node_type = node_type;
  568. pnode->parent = parent;
  569. parent->n_children++;
  570. if (value && *value) {
  571. pnode->value = (char *)mxml_malloc(strlen(value)+1);
  572. assert(pnode->value);
  573. strcpy(pnode->value, value);
  574. }
  575. return pnode;
  576. }
  577. /*------------------------------------------------------------------*/
  578. /**
  579. * add a subnode (child) to an existing parent node at the end
  580. */
  581. PMXML_NODE mxml_add_special_node(PMXML_NODE parent, int node_type, const char *node_name, const char *value)
  582. {
  583. return mxml_add_special_node_at(parent, node_type, node_name, value, parent->n_children);
  584. }
  585. /*------------------------------------------------------------------*/
  586. /**
  587. * write value of an XML element, like <[name]>[value]</[name]>
  588. */
  589. PMXML_NODE mxml_add_node(PMXML_NODE parent, const char *node_name, const char *value)
  590. {
  591. return mxml_add_special_node_at(parent, ELEMENT_NODE, node_name, value, parent->n_children);
  592. }
  593. /*------------------------------------------------------------------*/
  594. /**
  595. * add a subnode (child) to an existing parent node at the end
  596. */
  597. PMXML_NODE mxml_add_node_at(PMXML_NODE parent, const char *node_name, const char *value, int idx)
  598. {
  599. return mxml_add_special_node_at(parent, ELEMENT_NODE, node_name, value, idx);
  600. }
  601. /*------------------------------------------------------------------*/
  602. /**
  603. * add a whole node tree to an existing parent node at a specific position
  604. */
  605. int mxml_add_tree_at(PMXML_NODE parent, PMXML_NODE tree, int idx)
  606. {
  607. PMXML_NODE pchild;
  608. int i, j, k;
  609. assert(parent);
  610. assert(tree);
  611. if (parent->n_children == 0)
  612. parent->child = (PMXML_NODE)mxml_malloc(sizeof(MXML_NODE));
  613. else {
  614. pchild = parent->child;
  615. parent->child = (PMXML_NODE)mxml_realloc(parent->child, sizeof(MXML_NODE)*(parent->n_children+1));
  616. if (parent->child != pchild) {
  617. /* correct parent pointer for children */
  618. for (i=0 ; i<parent->n_children ; i++) {
  619. pchild = parent->child+i;
  620. for (j=0 ; j<pchild->n_children ; j++)
  621. pchild->child[j].parent = pchild;
  622. }
  623. }
  624. }
  625. assert(parent->child);
  626. if (idx < parent->n_children)
  627. for (i=parent->n_children ; i > idx ; i--) {
  628. /* move following nodes one down */
  629. memcpy(&parent->child[i], &parent->child[i-1], sizeof(MXML_NODE));
  630. /* correct parent pointer for children */
  631. for (j=0 ; j<parent->n_children ; j++) {
  632. pchild = parent->child+j;
  633. for (k=0 ; k<pchild->n_children ; k++)
  634. pchild->child[k].parent = pchild;
  635. }
  636. }
  637. /* initialize new node */
  638. memcpy(parent->child+idx, tree, sizeof(MXML_NODE));
  639. parent->n_children++;
  640. parent->child[idx].parent = parent;
  641. /* correct parent pointer for children */
  642. for (i=0 ; i<parent->n_children ; i++) {
  643. pchild = parent->child+i;
  644. for (j=0 ; j<pchild->n_children ; j++)
  645. pchild->child[j].parent = pchild;
  646. }
  647. return TRUE;
  648. }
  649. /*------------------------------------------------------------------*/
  650. /**
  651. * add a whole node tree to an existing parent node at the end
  652. */
  653. int mxml_add_tree(PMXML_NODE parent, PMXML_NODE tree)
  654. {
  655. return mxml_add_tree_at(parent, tree, parent->n_children);
  656. }
  657. /*------------------------------------------------------------------*/
  658. /**
  659. * add an attribute to an existing node
  660. */
  661. int mxml_add_attribute(PMXML_NODE pnode, const char *attrib_name, const char *attrib_value)
  662. {
  663. if (pnode->n_attributes == 0) {
  664. pnode->attribute_name = (char*)mxml_malloc(MXML_NAME_LENGTH);
  665. pnode->attribute_value = (char**)mxml_malloc(sizeof(char *));
  666. } else {
  667. pnode->attribute_name = (char*)mxml_realloc(pnode->attribute_name, MXML_NAME_LENGTH*(pnode->n_attributes+1));
  668. pnode->attribute_value = (char**)mxml_realloc(pnode->attribute_value, sizeof(char *)*(pnode->n_attributes+1));
  669. }
  670. mxml_strlcpy(pnode->attribute_name+pnode->n_attributes*MXML_NAME_LENGTH, attrib_name, MXML_NAME_LENGTH);
  671. pnode->attribute_value[pnode->n_attributes] = (char *)mxml_malloc(strlen(attrib_value)+1);
  672. strcpy(pnode->attribute_value[pnode->n_attributes], attrib_value);
  673. pnode->n_attributes++;
  674. return TRUE;
  675. }
  676. /*------------------------------------------------------------------*/
  677. /**
  678. * return number of subnodes (children) of a node
  679. */
  680. int mxml_get_number_of_children(PMXML_NODE pnode)
  681. {
  682. assert(pnode);
  683. return pnode->n_children;
  684. }
  685. /*------------------------------------------------------------------*/
  686. /**
  687. * return number of subnodes (children) of a node
  688. */
  689. PMXML_NODE mxml_subnode(PMXML_NODE pnode, int idx)
  690. {
  691. assert(pnode);
  692. if (idx < pnode->n_children)
  693. return &pnode->child[idx];
  694. return NULL;
  695. }
  696. /*------------------------------------------------------------------*/
  697. int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found);
  698. int mxml_add_resultnode(PMXML_NODE node, const char *xml_path, PMXML_NODE **nodelist, int *found)
  699. {
  700. /* if at end of path, add this node */
  701. if (*xml_path == 0) {
  702. if (*found == 0)
  703. *nodelist = (PMXML_NODE *)mxml_malloc(sizeof(PMXML_NODE));
  704. else
  705. *nodelist = (PMXML_NODE *)mxml_realloc(*nodelist, sizeof(PMXML_NODE)*(*found + 1));
  706. (*nodelist)[*found] = node;
  707. (*found)++;
  708. } else {
  709. /* if not at end of path, branch into subtree */
  710. return mxml_find_nodes1(node, xml_path+1, nodelist, found);
  711. }
  712. return 1;
  713. }
  714. /*------------------------------------------------------------------*/
  715. /**
  716. Return list of XML nodes with a subset of XPATH specifications.
  717. Following elemets are possible
  718. /<node>/<node>/..../<node> Find a node in the tree hierarchy
  719. /<node>[idx] Find child #[idx] of node (index starts from 1)
  720. /<node>[idx]/<node> Find subnode of the above
  721. /<node>[<subnode>=<value>] Find a node which has a specific subnode
  722. /<node>[<subnode>=<value>]/<node> Find subnode of the above
  723. /<node>[@<attrib>=<value>]/<node> Find a node which has a specific attribute
  724. */
  725. int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found)
  726. {
  727. PMXML_NODE pnode;
  728. const char *p1,*p2;
  729. char *p3, node_name[256], condition[256];
  730. char cond_name[MXML_MAX_CONDITION][256], cond_value[MXML_MAX_CONDITION][256];
  731. int cond_type[MXML_MAX_CONDITION];
  732. int i, j, k, idx, num_cond;
  733. int cond_satisfied,cond_index;
  734. size_t len;
  735. p1 = xml_path;
  736. pnode = tree;
  737. /* skip leading '/' */
  738. if (*p1 && *p1 == '/')
  739. p1++;
  740. do {
  741. p2 = p1;
  742. while (*p2 && *p2 != '/' && *p2 != '[')
  743. p2++;
  744. len = (size_t)p2 - (size_t)p1;
  745. if (len >= sizeof(node_name))
  746. return 0;
  747. memcpy(node_name, p1, len);
  748. node_name[len] = 0;
  749. idx = 0;
  750. num_cond = 0;
  751. while (*p2 == '[') {
  752. cond_name[num_cond][0] = cond_value[num_cond][0] = cond_type[num_cond] = 0;
  753. p2++;
  754. if (isdigit(*p2)) {
  755. /* evaluate [idx] */
  756. idx = atoi(p2);
  757. p2 = strchr(p2, ']');
  758. if (p2 == NULL)
  759. return 0;
  760. p2++;
  761. } else {
  762. /* evaluate [<@attrib>/<subnode>=<value>] */
  763. while (*p2 && isspace((unsigned char)*p2))
  764. p2++;
  765. mxml_strlcpy(condition, p2, sizeof(condition));
  766. if (strchr(condition, ']'))
  767. *strchr(condition, ']') = 0;
  768. else
  769. return 0;
  770. p2 = strchr(p2, ']')+1;
  771. if ((p3 = strchr(condition, '=')) != NULL) {
  772. if (condition[0] == '@') {
  773. cond_type[num_cond] = 1;
  774. mxml_strlcpy(cond_name[num_cond], &condition[1], sizeof(cond_name[num_cond]));
  775. } else {
  776. mxml_strlcpy(cond_name[num_cond], condition, sizeof(cond_name[num_cond]));
  777. }
  778. *strchr(cond_name[num_cond], '=') = 0;
  779. while (cond_name[num_cond][0] && isspace(cond_name[num_cond][strlen(cond_name[num_cond])-1]))
  780. cond_name[num_cond][strlen(cond_name[num_cond])-1] = 0;
  781. p3++;
  782. while (*p3 && isspace(*p3))
  783. p3++;
  784. if (*p3 == '\"') {
  785. mxml_strlcpy(cond_value[num_cond], p3+1, sizeof(cond_value[num_cond]));
  786. while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1]))
  787. cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
  788. if (cond_value[num_cond][0] && cond_value[num_cond][strlen(cond_value[num_cond])-1] == '\"')
  789. cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
  790. } else if (*p3 == '\'') {
  791. mxml_strlcpy(cond_value[num_cond], p3+1, sizeof(cond_value[num_cond]));
  792. while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1]))
  793. cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
  794. if (cond_value[num_cond][0] && cond_value[num_cond][strlen(cond_value[num_cond])-1] == '\'')
  795. cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
  796. } else {
  797. mxml_strlcpy(cond_value[num_cond], p3, sizeof(cond_value[num_cond]));
  798. while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1]))
  799. cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
  800. }
  801. num_cond++;
  802. }
  803. }
  804. }
  805. cond_index = 0;
  806. for (i=j=0 ; i<pnode->n_children ; i++) {
  807. if (num_cond) {
  808. cond_satisfied = 0;
  809. for (k=0;k<num_cond;k++) {
  810. if (cond_type[k]) {
  811. /* search node with attribute */
  812. if (strcmp(pnode->child[i].name, node_name) == 0)
  813. if (mxml_get_attribute(pnode->child+i, cond_name[k]) &&
  814. strcmp(mxml_get_attribute(pnode->child+i, cond_name[k]), cond_value[k]) == 0)
  815. cond_satisfied++;
  816. }
  817. else {
  818. /* search subnode */
  819. for (j=0 ; j<pnode->child[i].n_children ; j++)
  820. if (strcmp(pnode->child[i].child[j].name, cond_name[k]) == 0)
  821. if (strcmp(pnode->child[i].child[j].value, cond_value[k]) == 0)
  822. cond_satisfied++;
  823. }
  824. }
  825. if (cond_satisfied==num_cond) {
  826. cond_index++;
  827. if (idx == 0 || cond_index == idx) {
  828. if (!mxml_add_resultnode(pnode->child+i, p2, nodelist, found))
  829. return 0;
  830. }
  831. }
  832. } else {
  833. if (strcmp(pnode->child[i].name, node_name) == 0)
  834. if (idx == 0 || ++j == idx)
  835. if (!mxml_add_resultnode(pnode->child+i, p2, nodelist, found))
  836. return 0;
  837. }
  838. }
  839. if (i == pnode->n_children)
  840. return 1;
  841. pnode = &pnode->child[i];
  842. p1 = p2;
  843. if (*p1 == '/')
  844. p1++;
  845. } while (*p2);
  846. return 1;
  847. }
  848. /*------------------------------------------------------------------*/
  849. int mxml_find_nodes(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist)
  850. {
  851. int status, found = 0;
  852. status = mxml_find_nodes1(tree, xml_path, nodelist, &found);
  853. if (status == 0)
  854. return -1;
  855. return found;
  856. }
  857. /*------------------------------------------------------------------*/
  858. /**
  859. * Search for a specific XML node with a subset of XPATH specifications.
  860. * Return first found node. For syntax see mxml_find_nodes()
  861. */
  862. PMXML_NODE mxml_find_node(PMXML_NODE tree, const char *xml_path)
  863. {
  864. PMXML_NODE *node, pnode;
  865. int n;
  866. n = mxml_find_nodes(tree, xml_path, &node);
  867. if (n > 0) {
  868. pnode = node[0];
  869. mxml_free(node);
  870. } else
  871. pnode = NULL;
  872. return pnode;
  873. }
  874. /*------------------------------------------------------------------*/
  875. PMXML_NODE mxml_get_parent(PMXML_NODE pnode)
  876. {
  877. assert(pnode);
  878. return pnode->parent;
  879. }
  880. /*------------------------------------------------------------------*/
  881. char *mxml_get_name(PMXML_NODE pnode)
  882. {
  883. assert(pnode);
  884. return pnode->name;
  885. }
  886. /*------------------------------------------------------------------*/
  887. char *mxml_get_value(PMXML_NODE pnode)
  888. {
  889. assert(pnode);
  890. return pnode->value;
  891. }
  892. /*------------------------------------------------------------------*/
  893. int mxml_get_line_number_start(PMXML_NODE pnode)
  894. {
  895. assert(pnode);
  896. return pnode->line_number_start;
  897. }
  898. /*------------------------------------------------------------------*/
  899. int mxml_get_line_number_end(PMXML_NODE pnode)
  900. {
  901. assert(pnode);
  902. return pnode->line_number_end;
  903. }
  904. /*------------------------------------------------------------------*/
  905. char *mxml_get_attribute(PMXML_NODE pnode, const char *name)
  906. {
  907. int i;
  908. assert(pnode);
  909. for (i=0 ; i<pnode->n_attributes ; i++)
  910. if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, name) == 0)
  911. return pnode->attribute_value[i];
  912. return NULL;
  913. }
  914. /*------------------------------------------------------------------*/
  915. int mxml_replace_node_name(PMXML_NODE pnode, const char *name)
  916. {
  917. mxml_strlcpy(pnode->name, name, sizeof(pnode->name));
  918. return TRUE;
  919. }
  920. /*------------------------------------------------------------------*/
  921. int mxml_replace_node_value(PMXML_NODE pnode, const char *value)
  922. {
  923. if (pnode->value)
  924. pnode->value = (char *)mxml_realloc(pnode->value, strlen(value)+1);
  925. else if (value)
  926. pnode->value = (char *)mxml_malloc(strlen(value)+1);
  927. else
  928. pnode->value = NULL;
  929. if (value)
  930. strcpy(pnode->value, value);
  931. return TRUE;
  932. }
  933. /*------------------------------------------------------------------*/
  934. /**
  935. replace value os a subnode, like
  936. <parent>
  937. <child>value</child>
  938. </parent>
  939. if pnode=parent, and "name"="child", then "value" gets replaced
  940. */
  941. int mxml_replace_subvalue(PMXML_NODE pnode, const char *name, const char *value)
  942. {
  943. int i;
  944. for (i=0 ; i<pnode->n_children ; i++)
  945. if (strcmp(pnode->child[i].name, name) == 0)
  946. break;
  947. if (i == pnode->n_children)
  948. return FALSE;
  949. return mxml_replace_node_value(&pnode->child[i], value);
  950. }
  951. /*------------------------------------------------------------------*/
  952. /**
  953. * change the name of an attribute, keep its value
  954. */
  955. int mxml_replace_attribute_name(PMXML_NODE pnode, const char *old_name, const char *new_name)
  956. {
  957. int i;
  958. for (i=0 ; i<pnode->n_attributes ; i++)
  959. if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, old_name) == 0)
  960. break;
  961. if (i == pnode->n_attributes)
  962. return FALSE;
  963. mxml_strlcpy(pnode->attribute_name+i*MXML_NAME_LENGTH, new_name, MXML_NAME_LENGTH);
  964. return TRUE;
  965. }
  966. /*------------------------------------------------------------------*/
  967. /**
  968. * change the value of an attribute
  969. */
  970. int mxml_replace_attribute_value(PMXML_NODE pnode, const char *attrib_name, const char *attrib_value)
  971. {
  972. int i;
  973. for (i=0 ; i<pnode->n_attributes ; i++)
  974. if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, attrib_name) == 0)
  975. break;
  976. if (i == pnode->n_attributes)
  977. return FALSE;
  978. pnode->attribute_value[i] = (char *)mxml_realloc(pnode->attribute_value[i], strlen(attrib_value)+1);
  979. strcpy(pnode->attribute_value[i], attrib_value);
  980. return TRUE;
  981. }
  982. /*------------------------------------------------------------------*/
  983. /**
  984. * free memory of a node and remove it from the parent's child list
  985. */
  986. int mxml_delete_node(PMXML_NODE pnode)
  987. {
  988. PMXML_NODE parent;
  989. int i, j;
  990. /* remove node from parent's list */
  991. parent = pnode->parent;
  992. if (parent) {
  993. for (i=0 ; i<parent->n_children ; i++)
  994. if (&parent->child[i] == pnode)
  995. break;
  996. /* free allocated node memory recursively */
  997. mxml_free_tree(pnode);
  998. if (i < parent->n_children) {
  999. for (j=i ; j<parent->n_children-1 ; j++)
  1000. memcpy(&parent->child[j], &parent->child[j+1], sizeof(MXML_NODE));
  1001. parent->n_children--;
  1002. if (parent->n_children)
  1003. parent->child = (PMXML_NODE)mxml_realloc(parent->child, sizeof(MXML_NODE)*(parent->n_children));
  1004. else
  1005. mxml_free(parent->child);
  1006. }
  1007. } else
  1008. mxml_free_tree(pnode);
  1009. return TRUE;
  1010. }
  1011. /*------------------------------------------------------------------*/
  1012. int mxml_delete_attribute(PMXML_NODE pnode, const char *attrib_name)
  1013. {
  1014. int i, j;
  1015. for (i=0 ; i<pnode->n_attributes ; i++)
  1016. if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, attrib_name) == 0)
  1017. break;
  1018. if (i == pnode->n_attributes)
  1019. return FALSE;
  1020. mxml_free(pnode->attribute_value[i]);
  1021. for (j=i ; j<pnode->n_attributes-1 ; j++) {
  1022. strcpy(pnode->attribute_name+j*MXML_NAME_LENGTH, pnode->attribute_name+(j+1)*MXML_NAME_LENGTH);
  1023. pnode->attribute_value[j] = pnode->attribute_value[j+1];
  1024. }
  1025. if (pnode->n_attributes > 0) {
  1026. pnode->attribute_name = (char *)mxml_realloc(pnode->attribute_name, MXML_NAME_LENGTH*(pnode->n_attributes-1));
  1027. pnode->attribute_value = (char **)mxml_realloc(pnode->attribute_value, sizeof(char *)*(pnode->n_attributes-1));
  1028. } else {
  1029. mxml_free(pnode->attribute_name);
  1030. mxml_free(pnode->attribute_value);
  1031. }
  1032. return TRUE;
  1033. }
  1034. /*------------------------------------------------------------------*/
  1035. #define HERE root, file_name, line_number, error, error_size, error_line
  1036. /**
  1037. * used inside mxml_parse_file for reporting errors
  1038. */
  1039. 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, ...)
  1040. {
  1041. char *msg, str[1000];
  1042. va_list argptr;
  1043. if (file_name && file_name[0])
  1044. sprintf(str, "XML read error in file \"%s\", line %d: ", file_name, line_number);
  1045. else
  1046. sprintf(str, "XML read error, line %d: ", line_number);
  1047. msg = (char *)mxml_malloc(error_size);
  1048. if (error) {
  1049. mxml_strlcpy(error, str, error_size);
  1050. }
  1051. va_start(argptr, format);
  1052. vsprintf(str, (char *) format, argptr);
  1053. va_end(argptr);
  1054. if (error) {
  1055. mxml_strlcpy(error, str, error_size);
  1056. }
  1057. if (error_line) {
  1058. *error_line = line_number;
  1059. }
  1060. mxml_free(msg);
  1061. mxml_free_tree(root);
  1062. return NULL;
  1063. }
  1064. /*------------------------------------------------------------------*/
  1065. /**
  1066. * Parse a XML buffer and convert it into a tree of MXML_NODE's.
  1067. * Return NULL in case of an error, return error description.
  1068. * Optional file_name is used for error reporting if called from mxml_parse_file()
  1069. */
  1070. PMXML_NODE mxml_parse_buffer(const char *buf, char *error, int error_size, int *error_line)
  1071. {
  1072. char node_name[256], attrib_name[256], attrib_value[1000], quote;
  1073. const char *p, *pv;
  1074. int i,j, line_number;
  1075. PMXML_NODE root, ptree, pnew;
  1076. int end_element;
  1077. size_t len;
  1078. char *file_name = NULL; /* dummy for 'HERE' */
  1079. p = buf;
  1080. line_number = 1;
  1081. root = mxml_create_root_node();
  1082. ptree = root;
  1083. /* parse file contents */
  1084. do {
  1085. if (*p == '<') {
  1086. end_element = FALSE;
  1087. /* found new element */
  1088. p++;
  1089. while (*p && isspace(*p)) {
  1090. if (*p == '\n')
  1091. line_number++;
  1092. p++;
  1093. }
  1094. if (!*p)
  1095. return read_error(HERE, "Unexpected end of file");
  1096. if (strncmp(p, "!--", 3) == 0) {
  1097. /* found comment */
  1098. pnew = mxml_add_special_node(ptree, COMMENT_NODE, "Comment", NULL);
  1099. pnew->line_number_start = line_number;
  1100. pv = p+3;
  1101. while (*pv == ' ')
  1102. pv++;
  1103. p += 3;
  1104. if (strstr(p, "-->") == NULL)
  1105. return read_error(HERE, "Unterminated comment");
  1106. while (strncmp(p, "-->", 3) != 0) {
  1107. if (*p == '\n')
  1108. line_number++;
  1109. p++;
  1110. }
  1111. len = (size_t)p - (size_t)pv;
  1112. pnew->value = (char *)mxml_malloc(len+1);
  1113. memcpy(pnew->value, pv, len);
  1114. pnew->value[len] = 0;
  1115. pnew->line_number_end = line_number;
  1116. mxml_decode(pnew->value);
  1117. p += 3;
  1118. } else if (*p == '?') {
  1119. /* found ?...? element */
  1120. pnew = mxml_add_special_node(ptree, PROCESSING_INSTRUCTION_NODE, "PI", NULL);
  1121. pnew->line_number_start = line_number;
  1122. pv = p+1;
  1123. p++;
  1124. if (strstr(p, "?>") == NULL)
  1125. return read_error(HERE, "Unterminated ?...? element");
  1126. while (strncmp(p, "?>", 2) != 0) {
  1127. if (*p == '\n')
  1128. line_number++;
  1129. p++;
  1130. }
  1131. len = (size_t)p - (size_t)pv;
  1132. pnew->value = (char *)mxml_malloc(len+1);
  1133. memcpy(pnew->value, pv, len);
  1134. pnew->value[len] = 0;
  1135. pnew->line_number_end = line_number;
  1136. mxml_decode(pnew->value);
  1137. p += 2;
  1138. } else if (strncmp(p, "!DOCTYPE", 8) == 0 ) {
  1139. /* found !DOCTYPE element , skip it */
  1140. p += 8;
  1141. if (strstr(p, ">") == NULL)
  1142. return read_error(HERE, "Unterminated !DOCTYPE element");
  1143. j = 0;
  1144. while (*p && (*p != '>' || j > 0)) {
  1145. if (*p == '\n')
  1146. line_number++;
  1147. else if (*p == '<')
  1148. j++;
  1149. else if (*p == '>')
  1150. j--;
  1151. p++;
  1152. }
  1153. if (!*p)
  1154. return read_error(HERE, "Unexpected end of file");
  1155. p++;
  1156. } else {
  1157. /* found normal element */
  1158. if (*p == '/') {
  1159. end_element = TRUE;
  1160. p++;
  1161. while (*p && isspace((unsigned char)*p)) {
  1162. if (*p == '\n')
  1163. line_number++;
  1164. p++;
  1165. }
  1166. if (!*p)
  1167. return read_error(HERE, "Unexpected end of file");
  1168. }
  1169. /* extract node name */
  1170. i = 0;
  1171. node_name[i] = 0;
  1172. while (*p && !isspace((unsigned char)*p) && *p != '/' && *p != '>' && *p != '<')
  1173. node_name[i++] = *p++;
  1174. node_name[i] = 0;
  1175. if (!*p)
  1176. return read_error(HERE, "Unexpected end of file");
  1177. if (*p == '<')
  1178. return read_error(HERE, "Unexpected \'<\' inside element \"%s\"", node_name);
  1179. mxml_decode(node_name);
  1180. if (end_element) {
  1181. if (!ptree)
  1182. return read_error(HERE, "Found unexpected </%s>", node_name);
  1183. /* close previously opened element */
  1184. if (strcmp(ptree->name, node_name) != 0)
  1185. return read_error(HERE, "Found </%s>, expected </%s>", node_name, ptree->name);
  1186. ptree->line_number_end = line_number;
  1187. /* go up one level on the tree */
  1188. ptree = ptree->parent;
  1189. } else {
  1190. if (ptree == NULL)
  1191. return read_error(HERE, "Unexpected second top level node");
  1192. /* allocate new element structure in parent tree */
  1193. pnew = mxml_add_node(ptree, node_name, NULL);
  1194. pnew->line_number_start = line_number;
  1195. pnew->line_number_end = line_number;
  1196. while (*p && isspace((unsigned char)*p)) {
  1197. if (*p == '\n')
  1198. line_number++;
  1199. p++;
  1200. }
  1201. if (!*p)
  1202. return read_error(HERE, "Unexpected end of file");
  1203. while (*p != '>' && *p != '/') {
  1204. /* found attribute */
  1205. pv = p;
  1206. while (*pv && !isspace((unsigned char)*pv) && *pv != '=' && *pv != '<' && *pv != '>')
  1207. pv++;
  1208. if (!*pv)
  1209. return read_error(HERE, "Unexpected end of file");
  1210. if (*pv == '<' || *pv == '>')
  1211. return read_error(HERE, "Unexpected \'%c\' inside element \"%s\"", *pv, node_name);
  1212. /* extract attribute name */
  1213. len = (size_t)pv - (size_t)p;
  1214. if (len > sizeof(attrib_name)-1)
  1215. len = sizeof(attrib_name)-1;
  1216. memcpy(attrib_name, p, len);
  1217. attrib_name[len] = 0;
  1218. mxml_decode(attrib_name);
  1219. p = pv;
  1220. while (*p && isspace((unsigned char)*p)) {
  1221. if (*p == '\n')
  1222. line_number++;
  1223. p++;
  1224. }
  1225. if (!*p)
  1226. return read_error(HERE, "Unexpected end of file");
  1227. if (*p != '=')
  1228. return read_error(HERE, "Expect \"=\" here");
  1229. p++;
  1230. while (*p && isspace((unsigned char)*p)) {
  1231. if (*p == '\n')
  1232. line_number++;
  1233. p++;
  1234. }
  1235. if (!*p)
  1236. return read_error(HERE, "Unexpected end of file");
  1237. if (*p != '\"' && *p != '\'')
  1238. return read_error(HERE, "Expect \" or \' here");
  1239. quote = *p;
  1240. p++;
  1241. /* extract attribute value */
  1242. pv = p;
  1243. while (*pv && *pv != quote)
  1244. pv++;
  1245. if (!*pv)
  1246. return read_error(HERE, "Unexpected end of file");
  1247. len = (size_t)pv - (size_t)p;
  1248. if (len > sizeof(attrib_value)-1)
  1249. len = sizeof(attrib_value)-1;
  1250. memcpy(attrib_value, p, len);
  1251. attrib_value[len] = 0;
  1252. mxml_decode(attrib_value);
  1253. /* add attribute to current node */
  1254. mxml_add_attribute(pnew, attrib_name, attrib_value);
  1255. p = pv+1;
  1256. while (*p && isspace((unsigned char)*p)) {
  1257. if (*p == '\n')
  1258. line_number++;
  1259. p++;
  1260. }
  1261. if (!*p)
  1262. return read_error(HERE, "Unexpected end of file");
  1263. }
  1264. if (*p == '/') {
  1265. /* found empty node, like <node/>, just skip closing bracket */
  1266. p++;
  1267. while (*p && isspace((unsigned char)*p)) {
  1268. if (*p == '\n')
  1269. line_number++;
  1270. p++;
  1271. }
  1272. if (!*p)
  1273. return read_error(HERE, "Unexpected end of file");
  1274. if (*p != '>')
  1275. return read_error(HERE, "Expected \">\" after \"/\"");
  1276. p++;
  1277. }
  1278. if (*p == '>') {
  1279. p++;
  1280. /* check if we have sub-element or value */
  1281. pv = p;
  1282. while (*pv && isspace((unsigned char)*pv)) {
  1283. if (*pv == '\n')
  1284. line_number++;
  1285. pv++;
  1286. }
  1287. if (!*pv)
  1288. return read_error(HERE, "Unexpected end of file");
  1289. if (*pv == '<' && *(pv+1) != '/') {
  1290. /* start new subtree */
  1291. ptree = pnew;
  1292. p = pv;
  1293. } else {
  1294. /* extract value */
  1295. while (*pv && *pv != '<') {
  1296. if (*pv == '\n')
  1297. line_number++;
  1298. pv++;
  1299. }
  1300. if (!*pv)
  1301. return read_error(HERE, "Unexpected end of file");
  1302. len = (size_t)pv - (size_t)p;
  1303. pnew->value = (char *)mxml_malloc(len+1);
  1304. memcpy(pnew->value, p, len);
  1305. pnew->value[len] = 0;
  1306. mxml_decode(pnew->value);
  1307. p = pv;
  1308. ptree = pnew;
  1309. }
  1310. }
  1311. }
  1312. }
  1313. }
  1314. /* go to next element */
  1315. while (*p && *p != '<') {
  1316. if (*p == '\n')
  1317. line_number++;
  1318. p++;
  1319. }
  1320. } while (*p);
  1321. return root;
  1322. }
  1323. /*------------------------------------------------------------------*/
  1324. /**
  1325. * parse !ENTYTY entries of XML files and replace with references.
  1326. * Return 0 in case of no errors, return error description.
  1327. * Optional file_name is used for error reporting if called from mxml_parse_file()
  1328. */
  1329. int mxml_parse_entity(char **buf, const char *file_name, char *error, int error_size, int *error_line)
  1330. {
  1331. char *p;
  1332. char *pv;
  1333. char delimiter;
  1334. int i, j, k, line_number, status;
  1335. char *replacement;
  1336. char entity_name[MXML_MAX_ENTITY][256];
  1337. char entity_reference_name[MXML_MAX_ENTITY][256];
  1338. char *entity_value[MXML_MAX_ENTITY];
  1339. int entity_type[MXML_MAX_ENTITY]; /* internal or external */
  1340. int entity_line_number[MXML_MAX_ENTITY];
  1341. int nentity;
  1342. int fh, length, len;
  1343. char *buffer;
  1344. int ip; /* counter for entity value */
  1345. char directoryname[FILENAME_MAX];
  1346. char filename[FILENAME_MAX];
  1347. int entity_value_length[MXML_MAX_ENTITY];
  1348. int entity_name_length[MXML_MAX_ENTITY];
  1349. PMXML_NODE root = mxml_create_root_node(); /* dummy for 'HERE' */
  1350. for (ip = 0; ip < MXML_MAX_ENTITY; ip++)
  1351. entity_value[ip] = NULL;
  1352. line_number = 1;
  1353. nentity = -1;
  1354. status = 0;
  1355. if (!buf || !(*buf) || !strlen(*buf))
  1356. return 0;
  1357. strcpy(directoryname, file_name);
  1358. mxml_dirname(directoryname);
  1359. /* copy string to temporary space */
  1360. buffer = (char *) mxml_malloc(strlen(*buf) + 1);
  1361. if (buffer == NULL) {
  1362. read_error(HERE, "Cannot allocate memory.");
  1363. status = 1;
  1364. goto error;
  1365. }
  1366. strcpy(buffer, *buf);
  1367. p = strstr(buffer, "!DOCTYPE");
  1368. if (p == NULL) { /* no entities */
  1369. status = 0;
  1370. goto error;
  1371. }
  1372. pv = strstr(p, "[");
  1373. if (pv == NULL) { /* no entities */
  1374. status = 1;
  1375. goto error;
  1376. }
  1377. p = pv + 1;
  1378. /* search !ENTITY */
  1379. do {
  1380. if (*p == ']')
  1381. break;
  1382. if (*p == '<') {
  1383. /* found new entity */
  1384. p++;
  1385. while (*p && isspace((unsigned char)*p)) {
  1386. if (*p == '\n')
  1387. line_number++;
  1388. p++;
  1389. }
  1390. if (!*p) {
  1391. read_error(HERE, "Unexpected end of file");
  1392. status = 1;
  1393. goto error;
  1394. }
  1395. if (strncmp(p, "!--", 3) == 0) {
  1396. /* found comment */
  1397. p += 3;
  1398. if (strstr(p, "-->") == NULL) {
  1399. read_error(HERE, "Unterminated comment");
  1400. status = 1;
  1401. goto error;
  1402. }
  1403. while (strncmp(p, "-->", 3) != 0) {
  1404. if (*p == '\n')
  1405. line_number++;
  1406. p++;
  1407. }
  1408. p += 3;
  1409. }
  1410. else if (strncmp(p, "!ENTITY", 7) == 0) {
  1411. /* found entity */
  1412. nentity++;
  1413. if (nentity >= MXML_MAX_ENTITY) {
  1414. read_error(HERE, "Too much entities");
  1415. status = 1;
  1416. goto err

Large files files are truncated, but you can click here to view the full file