CUBRID Engine  latest
xml_parser.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * xml_parser.c : XML Parser for CUBRID
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <assert.h>
30 #include <string.h>
31 
32 #include "xml_parser.h"
33 #include "utility.h"
34 
35 #if defined(WINDOWS)
36 #define strtok_r strtok_s
37 #endif
38 
39 
40 /* size of XML parsing input buffer */
41 #define XML_READ_BUFFSIZE 8192
42 
43 /* XML parse tree data */
44 #define XML_ROOT_DEPTH 0
45 
46 #define IS_XML_ROOT(el) (el->def->depth == XML_ROOT_DEPTH)
47 
48 typedef enum
49 {
53 } XML_INS_POS;
54 
55 static XML_ELEMENT *xml_init_schema_tree (XML_ELEMENT_DEF ** element_array, const int count);
56 static void xml_destroy_schema_tree (XML_ELEMENT * pt);
57 static XML_ELEMENT *xml_clone_node (XML_ELEMENT * schema_src, XML_ELEMENT * parent, XML_ELEMENT * prev,
58  bool * has_error);
59 static bool xml_copy_schema_tree (XML_ELEMENT * src, XML_ELEMENT ** dest);
60 
61 static XML_ELEMENT *create_xml_node (XML_ELEMENT_DEF * new_elem);
62 static int add_xml_element (XML_ELEMENT * xml_node, XML_ELEMENT_DEF * new_elem_def);
63 
64 static XML_ELEMENT *select_xml_branch_node (XML_ELEMENT * xml_node, const char *sel_name);
65 static XML_ELEMENT *select_xml_node_for_ins (XML_ELEMENT * xml_node, const char *sel_name, XML_INS_POS * insert_pos);
66 static char *get_elem_path_token_at (const XML_ELEMENT_DEF * el_def, const int level, char *short_name);
67 static const char *get_short_elem_name (const XML_ELEMENT_DEF * el_def);
68 
69 static int check_xml_elem_name (XML_ELEMENT * el, const char *check_el_name);
70 
71 static void XMLCALL xml_header_validation_utf8 (void *userData, const XML_Char * version, const XML_Char * encoding,
72  int standalone);
73 static void XMLCALL xml_elem_start (void *data, const char *parsed_el_name, const char **attr);
74 static void XMLCALL xml_elem_end (void *data, const char *parsed_el_name);
75 static void XMLCALL xml_data_handler (void *data, const XML_Char * s, int len);
76 static XML_Parser xml_init_parser_common (void *data, const char *xml_file, const char *encoding);
77 static int xml_parse (void *data, FILE * fp, bool * is_finished);
78 static bool xml_check_include_loop (XML_PARSER_DATA * pd, char *new_file);
79 
80 /* XML root element */
82 
83 
84 /*
85  * xml_init_schema_tree() - initializes the XML parsing schema
86  * return: tree parse schema (root node)
87  * element_array(in): array of definition nodes (XML elements)
88  * count(in): count of nodes in the array
89  *
90  */
91 static XML_ELEMENT *
92 xml_init_schema_tree (XML_ELEMENT_DEF ** element_array, const int count)
93 {
94  int i;
95  XML_ELEMENT *xml_parse_tree = NULL;
96 
97  xml_parse_tree = (XML_ELEMENT *) malloc (sizeof (XML_ELEMENT));
98  if (xml_parse_tree == NULL)
99  {
100  return NULL;
101  }
102 
103  xml_parse_tree->def = &xml_elem_XML;
104  xml_parse_tree->child = NULL;
105  xml_parse_tree->next = NULL;
106  xml_parse_tree->prev = NULL;
107  xml_parse_tree->parent = NULL;
108  xml_parse_tree->short_name = xml_elem_XML.full_name;
109 
110  for (i = 0; i < count; i++)
111  {
112  if (add_xml_element (xml_parse_tree, element_array[i]) != XML_CUB_NO_ERROR)
113  {
114  return NULL;
115  }
116  }
117 
118  return xml_parse_tree;
119 }
120 
121 /*
122  * xml_destroy_schema_tree() - frees the XML parsing schema
123  * return:
124  * pt(in): tree parse schema (root node)
125  */
126 static void
128 {
129  if (pt->next != NULL)
130  {
132  pt->next = NULL;
133  }
134 
135  if (pt->child != NULL)
136  {
138  pt->child = NULL;
139  }
140 
141  pt->def = NULL;
142  pt->parent = NULL;
143  pt->prev = NULL;
144  assert (pt->short_name != NULL);
145  free (pt);
146 }
147 
148 /*
149  * xml_clone_node() - clone an XML parsing node
150  * return: tree parse schema (root node)
151  * schema_src(in): parse tree schema node to copy
152  * parent (in): parent node of the node being created
153  * prev(in): previous node of the node being created
154  * has_error(out): true if errors were found, false otherwise
155  *
156  */
157 static XML_ELEMENT *
158 xml_clone_node (XML_ELEMENT * schema_src, XML_ELEMENT * parent, XML_ELEMENT * prev, bool * has_error)
159 {
160  XML_ELEMENT *xml_parse_tree = NULL;
161 
162  *has_error = false;
163 
164  if (schema_src == NULL)
165  {
166  return NULL;
167  }
168 
169  xml_parse_tree = (XML_ELEMENT *) malloc (sizeof (XML_ELEMENT));
170  if (xml_parse_tree == NULL)
171  {
172  *has_error = true;
173  goto exit;
174  }
175 
176  xml_parse_tree->def = schema_src->def;
177  xml_parse_tree->match = false;
178  xml_parse_tree->short_name = schema_src->short_name;
179 
180  xml_parse_tree->prev = prev;
181  xml_parse_tree->parent = parent;
182 
183  xml_parse_tree->child = xml_clone_node (schema_src->child, xml_parse_tree, NULL, has_error);
184 
185  if (*has_error)
186  {
187  goto exit;
188  }
189  xml_parse_tree->next = xml_clone_node (schema_src->next, xml_parse_tree->parent, xml_parse_tree, has_error);
190  if (*has_error)
191  {
192  goto exit;
193  }
194 
195 exit:
196  return xml_parse_tree;
197 }
198 
199 /*
200  * xml_copy_schema_def() - clone an XML parsing node
201  *
202  * return: true if success, false otherwise
203  * src(in): XML_ELEMENT tree to copy
204  * dest(in/out): address where to create the XML_ELEMENT tree clone
205  *
206  * NOTE: only the linked structure and definitions are copyied. The "match"
207  * field is set to false, so the schema can be entirely reused.
208  */
209 static bool
211 {
212  bool has_error = false;
213  *dest = xml_clone_node (src, NULL, NULL, &has_error);
214 
215  return !has_error;
216 }
217 
218 /*
219  * create_xml_node() - creates a new XML schema element based on definition
220  *
221  * return: new element node
222  * el_def(in): element node definition
223  */
224 static XML_ELEMENT *
226 {
227  XML_ELEMENT *xml_node = (XML_ELEMENT *) malloc (sizeof (XML_ELEMENT));
228 
229  if (xml_node == NULL)
230  {
231  return NULL;
232  }
233 
234  xml_node->def = new_elem;
235  xml_node->child = NULL;
236  xml_node->next = NULL;
237  xml_node->prev = NULL;
238  xml_node->parent = NULL;
239  xml_node->match = false;
240  xml_node->short_name = NULL;
241 
242  return xml_node;
243 }
244 
245 /*
246  * add_xml_element() - creates and element node based on its definition and
247  * inserts it into the XML schema parser
248  *
249  * return: XML error code
250  * xml_node(in): tree parse schema (root node)
251  * new_elem_def(in): element definition
252  */
253 static int
254 add_xml_element (XML_ELEMENT * xml_node, XML_ELEMENT_DEF * new_elem_def)
255 {
256  const char *new_elem_short_name;
257  char new_elem_branch_name[MAX_ELEMENT_NAME];
258 
259  assert (xml_node != NULL);
260  assert (new_elem_def != NULL);
261 
262  assert (xml_node->def != NULL);
263  assert (new_elem_def->depth >= xml_node->def->depth);
264 
265  new_elem_short_name = get_short_elem_name (new_elem_def);
266 
267  if (new_elem_short_name == NULL || strlen (new_elem_short_name) == 0)
268  {
269  return XML_CUB_SCHEMA_BROKEN;
270  }
271 
272  if (new_elem_def->depth == xml_node->def->depth)
273  {
274  /* same level */
275  XML_ELEMENT *xml_new_node = NULL;
276  XML_INS_POS insert_pos = XML_INS_POS_UNDEF;
277 
278  xml_node = select_xml_node_for_ins (xml_node, new_elem_short_name, &insert_pos);
279 
280  assert (xml_node != NULL);
281 
282  /* insert new node here */
283  xml_new_node = create_xml_node (new_elem_def);
284  if (xml_new_node == NULL)
285  {
286  return XML_CUB_OUT_OF_MEMORY;
287  }
288 
289  assert (insert_pos == XML_INS_POS_AFTER || insert_pos == XML_INS_POS_BEFORE);
290 
291  xml_new_node->short_name = new_elem_short_name;
292  xml_new_node->parent = xml_node->parent;
293 
294  if (insert_pos == XML_INS_POS_AFTER)
295  {
296  xml_new_node->next = xml_node->next;
297  if (xml_node->next != NULL)
298  {
299  xml_node->next->prev = xml_new_node;
300  }
301  xml_node->next = xml_new_node;
302  xml_new_node->prev = xml_node;
303  }
304  else
305  {
306  if (xml_node->prev == NULL)
307  {
308  /* becomes new first child */
309  assert (xml_node->parent != NULL);
310  xml_node->parent->child = xml_new_node;
311  xml_new_node->next = xml_node;
312  xml_node->prev = xml_new_node;
313  }
314  else
315  {
316  /* insert before */
317  xml_new_node->prev = xml_node->prev;
318  xml_node->prev->next = xml_new_node;
319  xml_new_node->next = xml_node;
320  xml_node->prev = xml_new_node;
321  }
322  }
323 
324  return XML_CUB_NO_ERROR;
325  }
326 
327  assert (new_elem_def->depth > xml_node->def->depth);
328 
329  if (xml_node->child == NULL)
330  {
331  XML_ELEMENT *xml_new_node = NULL;
332 
333  /* cannot create children without parents */
334  assert (new_elem_def->depth == xml_node->def->depth + 1);
335 
336  /* first child of this node, insert new node here */
337  xml_new_node = create_xml_node (new_elem_def);
338 
339  if (xml_new_node == NULL)
340  {
341  return XML_CUB_OUT_OF_MEMORY;
342  }
343 
344  xml_new_node->parent = xml_node;
345  xml_node->child = xml_new_node;
346  xml_new_node->short_name = new_elem_short_name;
347 
348  return XML_CUB_NO_ERROR;
349  }
350 
351  assert (xml_node->child != NULL);
352 
353  /* check that select branch is ok up to this point before next selection */
354  if (!IS_XML_ROOT (xml_node))
355  {
356  int el_order = 0;
357 
358  if (get_elem_path_token_at (new_elem_def, xml_node->def->depth, new_elem_branch_name) == NULL)
359  {
360  return XML_CUB_SCHEMA_BROKEN;
361  }
362 
363  el_order = check_xml_elem_name (xml_node, new_elem_branch_name);
364 
365  assert (el_order == 0);
366 
367  if (el_order != 0)
368  {
369  return XML_CUB_SCHEMA_BROKEN;
370  }
371  }
372 
373  /* move to child */
374  xml_node = xml_node->child;
375 
376  if (xml_node->def->depth == new_elem_def->depth)
377  {
378  /* add on same level as child */
379  return add_xml_element (xml_node, new_elem_def);
380  }
381 
382  /* go down the branches */
383  while (xml_node->def->depth < new_elem_def->depth)
384  {
385  /* select branch at this level */
386  if (get_elem_path_token_at (new_elem_def, xml_node->def->depth, new_elem_branch_name) == NULL)
387  {
388  return XML_CUB_SCHEMA_BROKEN;
389  }
390 
391  xml_node = select_xml_branch_node (xml_node, new_elem_branch_name);
392 
393  if (xml_node->child == NULL)
394  {
395  break;
396  }
397 
398  xml_node = xml_node->child;
399  }
400  assert (xml_node != NULL);
401 
402  return add_xml_element (xml_node, new_elem_def);
403 
404 }
405 
406 /*
407  * select_xml_branch_node() - selects the node branch coresponding to the name
408  * within the same level
409  *
410  * return: XML node or NULL if branch not found
411  * xml_node(in): first node of level to start from
412  * sel_name(in): branch name
413  */
414 static XML_ELEMENT *
415 select_xml_branch_node (XML_ELEMENT * xml_node, const char *sel_name)
416 {
417  assert (xml_node != NULL);
418 
419  for (;;)
420  {
421  int el_order = check_xml_elem_name (xml_node, sel_name);
422 
423  if (el_order < 0)
424  {
425  if (xml_node->next != NULL)
426  {
427  /* position after : continue search */
428  xml_node = xml_node->next;
429  continue;
430  }
431  else
432  {
433  /* no more branches */
434  assert (false);
435  return NULL;
436  }
437  }
438  else if (el_order > 0)
439  {
440  /* branch non existent */
441  assert (false);
442  return NULL;
443  }
444  else
445  {
446  /* found */
447  assert (el_order == 0);
448  return xml_node;
449  }
450  }
451 
452  assert (false);
453  return NULL;
454 }
455 
456 /*
457  * select_xml_node_for_ins() - selects the node from which to insert a new
458  * element node
459  *
460  * return: XML node or NULL if a node with the required name already exists
461  * xml_node(in): first node of level to start from
462  * sel_name(in): short name of new node
463  * insert_pos(out): where to insert
464  */
465 static XML_ELEMENT *
466 select_xml_node_for_ins (XML_ELEMENT * xml_node, const char *sel_name, XML_INS_POS * insert_pos)
467 {
468  assert (xml_node != NULL);
469 
470  for (;;)
471  {
472  int el_order = check_xml_elem_name (xml_node, sel_name);
473 
474  if (el_order < 0)
475  {
476  if (xml_node->next != NULL)
477  {
478  /* position after : continue search */
479  xml_node = xml_node->next;
480  continue;
481  }
482  else
483  {
484  *insert_pos = XML_INS_POS_AFTER;
485  return xml_node;
486  }
487  }
488  else if (el_order > 0)
489  {
490  *insert_pos = XML_INS_POS_BEFORE;
491  return xml_node;
492  }
493  else
494  {
495  assert (el_order == 0);
496  /* node alreay existing */
497  return NULL;
498  }
499  }
500 
501  assert (false);
502  return NULL;
503 }
504 
505 /*
506  * get_elem_path_token_at() - returns the short name of an XML node located
507  * inside an element definition long name (or path)
508  * element definition, at the specified depth/level
509  *
510  * return: short name or NULL if required level exceeds the node depth
511  * el_def(in): element node definition
512  * level(in): level for which the short name is requested
513  * short_name(out): short name
514  */
515 static char *
516 get_elem_path_token_at (const XML_ELEMENT_DEF * el_def, const int level, char *short_name)
517 {
518  int l = 1;
519  const char *tok_start = NULL;
520  const char *tok_end = NULL;
521 
522  assert (short_name != NULL);
523  assert (el_def != NULL);
524  assert (el_def->full_name != NULL);
525 
526  tok_start = el_def->full_name;
527  tok_end = strchr (tok_start, ' ');
528  if (tok_end == NULL)
529  {
530  tok_end = tok_start + strlen (tok_start);
531  }
532 
533  while (l < level)
534  {
535  tok_start = tok_end + 1;
536  tok_end = strchr (tok_start, ' ');
537  if (tok_end == NULL)
538  {
539  tok_end = tok_start + strlen (tok_start);
540  if (l < level - 1)
541  {
542  /* end of string reached, and level requested is too big */
543  return NULL;
544  }
545  }
546  l++;
547  }
548 
549  memcpy (short_name, tok_start, tok_end - tok_start);
550  short_name[tok_end - tok_start] = '\0';
551 
552  return short_name;
553 }
554 
555 /*
556  * get_short_elem_name() - returns the short name of an element definition
557  *
558  * return: short name
559  * el_def(in): element node definition
560  */
561 static const char *
563 {
564  const char *result = NULL;
565 
566  assert (el_def != NULL);
567  assert (el_def->full_name != NULL && *(el_def->full_name) != '\0');
568 
569  result = strrchr (el_def->full_name, ' ');
570  if (result == NULL)
571  {
572  /* root element, its path is the actual short element name */
573  return el_def->full_name;
574  }
575 
576  /* skip the space */
577  result++;
578  assert (*result != '\0');
579 
580  return result;
581 }
582 
583 /*
584  * check_xml_elem_name() - checks the order between an XML element node name
585  * and a a string
586  *
587  * return: 0 if same name, < 0 if requested name is after element name,
588  * > 0 if requested name is before element name
589  * el(in): element node
590  * check_el_name(in): name to be checked
591  */
592 static int
593 check_xml_elem_name (XML_ELEMENT * el, const char *check_el_name)
594 {
595  assert (el != NULL);
596  assert (check_el_name != NULL);
597 
598  assert (el->short_name != NULL);
599 
600  return strcmp (el->short_name, check_el_name);
601 }
602 
603 /*
604  * xml_header_validation_utf8() - XML header validation function;
605  * expat callback function
606  *
607  * return:
608  * userData(in): user data
609  * version(in):
610  * encoding(in):
611  * standalone(in):
612  */
613 static void XMLCALL
614 xml_header_validation_utf8 (void *userData, const XML_Char * version, const XML_Char * encoding, int standalone)
615 {
616  if (encoding == NULL || strcmp ((char *) encoding, "UTF-8"))
617  {
618  XML_PARSER_DATA *pd;
619 
620  assert (userData != NULL);
621 
622  pd = (XML_PARSER_DATA *) userData;
623 
625  pd->xml_error_line = XML_GetCurrentLineNumber (pd->xml_parser);
626  pd->xml_error_column = XML_GetCurrentColumnNumber (pd->xml_parser);
627 
628  XML_StopParser (pd->xml_parser, XML_FALSE);
629  }
630 }
631 
632 /*
633  * xml_elem_start() - XML element start function;
634  * expat callback function
635  *
636  * return:
637  * data(in): user data
638  * parsed_el_name(in): element name
639  * attr(in): array of pairs for XML attribute and value (strings) of current
640  * element
641  */
642 static void XMLCALL
643 xml_elem_start (void *data, const char *parsed_el_name, const char **attr)
644 {
645  int el_order;
646  XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
647  XML_ELEMENT *el = NULL;
648  bool found = false;
649 
650  assert (pd != NULL);
651  el = pd->ce;
652 
653  if (IS_XML_ROOT (el))
654  {
655  el = el->child;
656  }
657 
658  assert (el != NULL);
659  assert (el->def != NULL);
660 
661  pd->depth++;
662  assert (pd->depth >= el->def->depth);
663 
664  if (pd->depth - el->def->depth > 1)
665  {
666  /* parser is too deep for our schema, ignore element */
667  return;
668  }
669  else if (pd->depth - el->def->depth == 1)
670  {
671  /* search elements of next level */
672  el = el->child;
673  }
674  else
675  {
676  /* same level */
677  assert (pd->depth == el->def->depth);
678  }
679 
680  for (; el != NULL; el = el->next)
681  {
682  el_order = check_xml_elem_name (el, parsed_el_name);
683 
684  if (el_order == 0)
685  {
686  /* found element name */
687  found = true;
688  break;
689  }
690 
691  if (el_order > 0)
692  {
693  /* currently parsed element sorts after last schema element */
694  break;
695  }
696  }
697 
698  if (found)
699  {
700  int elem_start_res = 0;
701  ELEM_START_FUNC start_func = START_FUNC (el);
702  ELEM_DATA_FUNC data_func = DATA_FUNC (el);
703  XML_ELEMENT *saved_el = NULL;
704 
705  assert (el != NULL);
706  assert (el->def != NULL);
707 
708  /* set current element (required for verbose option) */
709  saved_el = pd->ce;
710  pd->ce = el;
711 
712  /* found element */
713  if (start_func != NULL)
714  {
715  elem_start_res = (*start_func) (pd, attr);
716  }
717 
718  if (elem_start_res > 0)
719  {
720  /* ignore element */
721  assert (el->match == false);
722  /* restore initial current element */
723  pd->ce = saved_el;
724  return;
725  }
726  else if (elem_start_res < 0)
727  {
728  if (pd->xml_error == XML_CUB_NO_ERROR)
729  {
731  }
732  pd->xml_error_line = XML_GetCurrentLineNumber (pd->xml_parser);
733  pd->xml_error_column = XML_GetCurrentColumnNumber (pd->xml_parser);
734 
735  XML_StopParser (pd->xml_parser, XML_FALSE);
736  /* restore initial current element */
737  pd->ce = saved_el;
738  return;
739  }
740 
741  assert (elem_start_res == 0);
742 
743  /* new schema element is checked */
744  assert (pd->ce == el);
745  el->match = true;
746 
747  /* enable data handler */
748  if (data_func != NULL)
749  {
750  XML_SetCharacterDataHandler (pd->xml_parser, xml_data_handler);
751  }
752  }
753  else
754  {
755  /* only first level unknown elements are ignored */
756  if (!IS_XML_ROOT (pd->ce))
757  {
758  assert (pd->ce->match == true);
759  }
760  }
761 }
762 
763 /*
764  * xml_elem_end() - XML element end function; expat callback function
765  *
766  * return:
767  * data(in): user data
768  * parsed_el_name(in): element name
769  */
770 static void XMLCALL
771 xml_elem_end (void *data, const char *parsed_el_name)
772 {
773  XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
774  ELEM_END_FUNC end_func;
775  int end_res = 0;
776 
777  assert (pd != NULL);
778 
779  /* disable data handler */
780  XML_SetCharacterDataHandler (pd->xml_parser, NULL);
781 
782  if (pd->depth > pd->ce->def->depth || !pd->ce->match)
783  {
784  pd->depth--;
785  return;
786  }
787 
788  pd->depth--;
789 
790  end_func = END_FUNC (pd->ce);
791 
792  if (end_func != NULL)
793  {
794  assert (parsed_el_name != NULL);
795  end_res = (*end_func) (data, parsed_el_name);
796  }
797 
798  if (end_res != 0)
799  {
800  if (pd->xml_error == XML_CUB_NO_ERROR)
801  {
803  }
804  pd->xml_error_line = XML_GetCurrentLineNumber (pd->xml_parser);
805  pd->xml_error_column = XML_GetCurrentColumnNumber (pd->xml_parser);
806 
807  XML_StopParser (pd->xml_parser, XML_FALSE);
808  }
809 
810  assert (pd->ce->match == true);
811  /* move level up in schema */
812  pd->ce->match = false;
813  pd->ce = pd->ce->parent;
814 }
815 
816 /*
817  * xml_data_handler() - XML element element content handling function;
818  * expat callback function
819  *
820  * return:
821  * data(in): user data
822  * s(in): content buffer
823  * len(in): length (in XML_Char) of content buffer
824  *
825  * Note : if encoding is UTF-8, the unit XML_Char is byte
826  */
827 static void XMLCALL
828 xml_data_handler (void *data, const XML_Char * s, int len)
829 {
830  XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
831  ELEM_DATA_FUNC data_func;
832  int data_res = -1;
833 
834  assert (pd != NULL);
835 
836  assert (pd->ce != NULL);
837  assert (pd->ce->def != NULL);
838  assert (pd->ce->match == true);
839 
840  data_func = DATA_FUNC (pd->ce);
841 
842  assert (data_func != NULL);
843 
844  /* handle data */
845  if (data_func != NULL)
846  {
847  data_res = (*data_func) (data, (const char *) s, len);
848  }
849 
850  if (data_res != 0)
851  {
852  if (pd->xml_error == XML_CUB_NO_ERROR)
853  {
855  }
856  pd->xml_error_line = XML_GetCurrentLineNumber (pd->xml_parser);
857  pd->xml_error_column = XML_GetCurrentColumnNumber (pd->xml_parser);
858 
859  XML_StopParser (pd->xml_parser, XML_FALSE);
860  }
861 }
862 
863 /* XML interface functions */
864 /*
865  * xml_init_parser_common() - common initialization for XML parser/subparsers
866  *
867  * return: pointer to expat XML parser
868  * data(in): XML parser data
869  * xml_file(in): path to the XML file to be parsed
870  * encoding(in): encoding charset
871  */
872 static XML_Parser
873 xml_init_parser_common (void *data, const char *xml_file, const char *encoding)
874 {
875  XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
876  XML_Parser p = NULL;
877 
878  assert (pd != NULL);
879  assert (XML_USER_DATA (pd) != NULL);
880 
882 
883  p = XML_ParserCreate (encoding);
884  if (p == NULL)
885  {
887  return NULL;
888  }
889 
890  size_t encoding_len = strnlen (encoding, MAX_ENCODE_LEN);
891  memcpy (pd->encoding, encoding, encoding_len);
892  pd->encoding[encoding_len] = '\0';
893 
894  pd->xml_parser = p;
896  pd->xml_error_line = -1;
897  pd->xml_error_column = -1;
898 
899  strcpy (pd->filepath, xml_file);
900 
901  XML_SetUserData (p, pd);
902  /* XML parser : callbacks */
903  XML_SetElementHandler (p, xml_elem_start, xml_elem_end);
904 
905  /* use built-in header validation */
906  if (strcmp (encoding, "UTF-8") == 0)
907  {
908  XML_SetXmlDeclHandler (p, xml_header_validation_utf8);
909  }
910 
911  /* input buffer */
912  pd->buf = (char *) malloc (XML_READ_BUFFSIZE);
913  if (pd->buf == NULL)
914  {
916  }
917 
918  pd->sc = NULL;
919  pd->ce = NULL;
920  pd->depth = 0;
921 
922  pd->prev = NULL;
923  pd->next = NULL;
924 
925  return p;
926 }
927 
928 /*
929  * xml_init_parser() - XML parser initializer
930  *
931  * return: pointer to expat XML parser
932  * data(in): XML parser data
933  * xml_file(in): path to the XML file to be parsed
934  * encoding(in): encoding charset
935  * element_array(in): array of element definition nodes (schema definition)
936  * count(in): number of elements in schema definition
937  */
938 XML_Parser
939 xml_init_parser (void *data, const char *xml_file, const char *encoding, XML_ELEMENT_DEF ** element_array,
940  const int count)
941 {
942  XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
943  XML_Parser p = NULL;
944 
945  assert (pd != NULL);
946  assert (XML_USER_DATA (pd) != NULL);
947 
948  p = xml_init_parser_common (data, xml_file, encoding);
949  if (pd->xml_error != XML_CUB_NO_ERROR)
950  {
951  return p;
952  }
953 
954  pd = (XML_PARSER_DATA *) data;
955 
956  pd->sc = xml_init_schema_tree (element_array, count);
957 
958  if (pd->sc == NULL)
959  {
961  }
962 
963  pd->ce = pd->sc;
964  pd->ce->match = false;
965  pd->depth = 0;
966 
967  return p;
968 }
969 
970 /*
971  * xml_destroy_parser() - frees XML parser
972  *
973  * return:
974  * data(in): XML parser data
975  */
976 void
977 xml_destroy_parser (void *data)
978 {
979  XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
980  XML_PARSER_DATA *cpd = NULL;
981 
982  cpd = pd->next;
983  while (cpd != NULL)
984  {
985  pd->next = cpd->next;
987  free (cpd);
988  cpd = pd->next;
989  }
991 }
992 
993 /*
994  * xml_create_subparser() - initialize a parser for an included XML file
995  *
996  * return: initialized XML parser data (containing the expat XML parser) for
997  * the file path supplied as input (new_file)
998  * data(in): XML parser data
999  * new_file(in): path to the XML file to be parsed
1000  */
1003 {
1004  XML_Parser p = NULL;
1005  XML_PARSER_DATA *new_pd = NULL;
1006  bool is_success = true;
1007 
1008  assert (pd != NULL);
1009 
1010  if (xml_check_include_loop (pd, new_file))
1011  {
1013  return NULL;
1014  }
1015 
1016  new_pd = (XML_PARSER_DATA *) malloc (sizeof (XML_PARSER_DATA));
1017  if (new_pd == NULL)
1018  {
1020  return NULL;
1021  }
1022  memset (new_pd, 0, sizeof (XML_PARSER_DATA));
1023  new_pd->ud = pd->ud;
1024 
1025  p = xml_init_parser_common (new_pd, new_file, pd->encoding);
1026  if (new_pd->xml_error != XML_CUB_NO_ERROR)
1027  {
1028  pd->xml_error = new_pd->xml_error;
1029  goto error;
1030  }
1031 
1032  is_success = xml_copy_schema_tree (pd->sc, &(new_pd->sc));
1033  if (!is_success && new_pd->sc != NULL)
1034  {
1035  xml_destroy_schema_tree (new_pd->sc);
1036  new_pd->sc = NULL;
1037  }
1038  if (new_pd->sc == NULL)
1039  {
1041  goto error;
1042  }
1043 
1044  new_pd->ce = new_pd->sc;
1045  new_pd->ce->match = false;
1046  new_pd->depth = 0;
1047 
1048  pd->next = new_pd;
1049  new_pd->prev = pd;
1050 
1051  return new_pd;
1052 
1053 error:
1054  xml_destroy_parser_data (new_pd);
1055  free (new_pd);
1056 
1057  return NULL;
1058 }
1059 
1060 /*
1061  * xml_destroy_parser_data() - destroy the data inside a CUB_PARSER structure.
1062  *
1063  * return:
1064  * data(in): XML parser data
1065  */
1066 void
1068 {
1069  XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
1070 
1071  if (pd == NULL)
1072  {
1073  return;
1074  }
1075 
1076  if (pd->sc != NULL)
1077  {
1079  }
1080 
1081  if (pd->xml_parser != NULL)
1082  {
1083  XML_ParserFree (pd->xml_parser);
1084  }
1085 
1086  if (pd->buf != NULL)
1087  {
1088  free (pd->buf);
1089  }
1090 
1091  memset (pd, 0, sizeof (XML_PARSER_DATA));
1092 }
1093 
1094 /*
1095  * xml_parse() - parses the selected file using the current XML_Parser
1096  * inside the XML_PARSER_DATA variable
1097  *
1098  * return: error code
1099  * data(in): XML parser data
1100  * fp(in): file to read from
1101  * is_finished(out): true if parser has finished
1102  */
1103 static int
1104 xml_parse (void *data, FILE * fp, bool * is_finished)
1105 {
1106  XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
1107  int len;
1108  int isFinal;
1109  XML_ParsingStatus xml_status;
1110 
1111  assert (pd != NULL);
1112  assert (pd->xml_parser != NULL);
1113 
1114  assert (fp != NULL);
1115  assert (is_finished != NULL);
1116 
1117  len = (int) fread (pd->buf, 1, XML_READ_BUFFSIZE, fp);
1118  if (ferror (fp))
1119  {
1120  return XML_CUB_ERR_FILE_READ;
1121  }
1122 
1123  isFinal = (feof (fp) != 0) ? 1 : 0;
1124 
1125  XML_GetParsingStatus (pd->xml_parser, &xml_status);
1126  if (xml_status.parsing == XML_FINISHED)
1127  {
1128  *is_finished = true;
1129  return XML_CUB_NO_ERROR;
1130  }
1131 
1132  if (XML_Parse (pd->xml_parser, pd->buf, len, isFinal) == XML_STATUS_ERROR)
1133  {
1135  pd->xml_error_line = XML_GetCurrentLineNumber (pd->xml_parser);
1136  pd->xml_error_column = XML_GetCurrentColumnNumber (pd->xml_parser);
1137  return XML_CUB_ERR_PARSER;
1138  }
1139 
1140  return XML_CUB_NO_ERROR;
1141 }
1142 
1143 /*
1144  * xml_check_att_value() - checks the attribute value
1145  *
1146  * return: 0 if attribute value matches, 1 otherwise (or attribute not found)
1147  * attrs(in): the array of attribute name/value pairs of current XML element
1148  * att_name(in):
1149  * att_value(in):
1150  */
1151 int
1152 xml_check_att_value (const char **attrs, const char *att_name, const char *att_value)
1153 {
1154  const char **curr_att = attrs;
1155 
1156  assert (attrs != NULL);
1157  assert (att_name != NULL);
1158  assert (att_value != NULL);
1159 
1160  for (; *curr_att != NULL; curr_att++, curr_att++)
1161  {
1162  if (strcmp (curr_att[0], att_name) == 0 && strcmp (curr_att[1], att_value) == 0)
1163  {
1164  return 0;
1165  }
1166  }
1167 
1168  return 1;
1169 }
1170 
1171 /*
1172  * xml_get_att_value() - returns the attribute value
1173  *
1174  * return: 0 if attribute was found, 1 otherwise
1175  * attrs(in): the array of attribute name/value pairs of current XML element
1176  * att_name(in):
1177  * p_att_value(in/out): (returned attribute value)
1178  */
1179 int
1180 xml_get_att_value (const char **attrs, const char *att_name, char **p_att_value)
1181 {
1182  const char **curr_att = attrs;
1183 
1184  assert (attrs != NULL);
1185  assert (att_name != NULL);
1186  assert (p_att_value != NULL);
1187  assert (*p_att_value == NULL);
1188 
1189  for (; *curr_att != NULL; curr_att++, curr_att++)
1190  {
1191  if (strcmp (curr_att[0], att_name) == 0)
1192  {
1193  *p_att_value = (char *) curr_att[1];
1194  return 0;
1195  }
1196  }
1197 
1198  return 1;
1199 }
1200 
1201 /*
1202  * xml_check_include_loop() - checks if a parser is already created for
1203  * new_file.
1204  *
1205  * return: true if loop is detected, false otherwise
1206  * pd(in): pointer to the current parser data
1207  * new_file(in): file path to check
1208  *
1209  * NOTE: If a parser is already created and opened for new_file, it should
1210  * not be possible to create another parser for the same file until
1211  * the existing parser will be closed, because this will lead to an
1212  * inclusion loop in the input parser list.
1213  */
1214 static bool
1216 {
1217  XML_PARSER_DATA *cpd;
1218 
1219  cpd = pd;
1220  while (cpd != NULL)
1221  {
1222  if (strcmp (cpd->filepath, new_file) == 0)
1223  {
1224  return true;
1225  }
1226  cpd = cpd->prev;
1227  }
1228 
1229  return false;
1230 }
1231 
1232 /*
1233  * xml_parser_exec() - calls the parser using the information
1234  * inside the XML_PARSER_DATA variable
1235  *
1236  * return: error code
1237  * data(in): XML parser data
1238  */
1239 void
1241 {
1242  bool is_finished = false;
1243  FILE *fp = NULL;
1244 
1245  fp = fopen_ex (pd->filepath, "rb");
1246  if (fp == NULL)
1247  {
1249  goto exit;
1250  }
1251 
1252  for (; pd->xml_error == XML_CUB_NO_ERROR && !is_finished;)
1253  {
1254  if (xml_parse (pd, fp, &is_finished) != XML_CUB_NO_ERROR)
1255  {
1256  goto exit;
1257  }
1258  }
1259 
1260 exit:
1261  if (fp != NULL)
1262  {
1263  fclose (fp);
1264  }
1265 }
static int xml_parse(void *data, FILE *fp, bool *is_finished)
Definition: xml_parser.c:1104
const int depth
Definition: xml_parser.h:87
XML_ELEMENT_DEF xml_elem_XML
Definition: xml_parser.c:81
const char * full_name
Definition: xml_parser.h:86
#define XML_CUB_ERR_FILE_MISSING
Definition: xml_parser.h:43
XML_ELEMENT * child
Definition: xml_parser.h:99
static XML_ELEMENT * xml_clone_node(XML_ELEMENT *schema_src, XML_ELEMENT *parent, XML_ELEMENT *prev, bool *has_error)
Definition: xml_parser.c:158
static void xml_destroy_schema_tree(XML_ELEMENT *pt)
Definition: xml_parser.c:127
#define MAX_ENCODE_LEN
Definition: xml_parser.h:50
char filepath[PATH_MAX]
Definition: xml_parser.h:124
XML_PARSER_DATA * xml_create_subparser(XML_PARSER_DATA *pd, char *new_file)
Definition: xml_parser.c:1002
#define XML_READ_BUFFSIZE
Definition: xml_parser.c:41
static int check_xml_elem_name(XML_ELEMENT *el, const char *check_el_name)
Definition: xml_parser.c:593
static void XMLCALL xml_header_validation_utf8(void *userData, const XML_Char *version, const XML_Char *encoding, int standalone)
Definition: xml_parser.c:614
static XML_ELEMENT * xml_init_schema_tree(XML_ELEMENT_DEF **element_array, const int count)
Definition: xml_parser.c:92
int(* ELEM_START_FUNC)(void *, const char **)
Definition: xml_parser.h:60
XML_Parser xml_init_parser(void *data, const char *xml_file, const char *encoding, XML_ELEMENT_DEF **element_array, const int count)
Definition: xml_parser.c:939
#define XML_CUB_OUT_OF_MEMORY
Definition: xml_parser.h:39
static const char * get_short_elem_name(const XML_ELEMENT_DEF *el_def)
Definition: xml_parser.c:562
XML_ELEMENT * parent
Definition: xml_parser.h:98
#define XML_CUB_ERR_PARSER
Definition: xml_parser.h:42
#define XML_CUB_SCHEMA_BROKEN
Definition: xml_parser.h:38
#define IS_XML_ROOT(el)
Definition: xml_parser.c:46
#define XML_USER_DATA(xml)
Definition: xml_parser.h:109
#define XML_CUB_ERR_HEADER_ENCODING
Definition: xml_parser.h:40
XML_ELEMENT_DEF * def
Definition: xml_parser.h:96
#define DATA_FUNC(el)
Definition: xml_parser.h:107
XML_Parser xml_parser
Definition: xml_parser.h:114
#define XML_CUB_NO_ERROR
Definition: xml_parser.h:36
static XML_Parser xml_init_parser_common(void *data, const char *xml_file, const char *encoding)
Definition: xml_parser.c:873
static int add_xml_element(XML_ELEMENT *xml_node, XML_ELEMENT_DEF *new_elem_def)
Definition: xml_parser.c:254
static void XMLCALL xml_elem_start(void *data, const char *parsed_el_name, const char **attr)
Definition: xml_parser.c:643
#define assert(x)
#define XML_CUB_ERR_FILE_READ
Definition: xml_parser.h:41
static bool xml_copy_schema_tree(XML_ELEMENT *src, XML_ELEMENT **dest)
Definition: xml_parser.c:210
#define XML_ROOT_DEPTH
Definition: xml_parser.c:44
void xml_parser_exec(XML_PARSER_DATA *pd)
Definition: xml_parser.c:1240
#define END_FUNC(el)
Definition: xml_parser.h:106
static bool xml_check_include_loop(XML_PARSER_DATA *pd, char *new_file)
Definition: xml_parser.c:1215
static XML_ELEMENT * select_xml_branch_node(XML_ELEMENT *xml_node, const char *sel_name)
Definition: xml_parser.c:415
#define NULL
Definition: freelistheap.h:34
XML_ELEMENT * sc
Definition: xml_parser.h:116
char encoding[MAX_ENCODE_LEN]
Definition: xml_parser.h:125
#define START_FUNC(el)
Definition: xml_parser.h:105
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
FILE * fopen_ex(const char *filename, const char *type)
Definition: util_common.c:322
XML_ELEMENT * prev
Definition: xml_parser.h:101
static void error(const char *msg)
Definition: gencat.c:331
XML_INS_POS
Definition: xml_parser.c:48
static XML_ELEMENT * create_xml_node(XML_ELEMENT_DEF *new_elem)
Definition: xml_parser.c:225
int(* ELEM_DATA_FUNC)(void *, const char *, int)
Definition: xml_parser.h:81
#define strlen(s1)
Definition: intl_support.c:43
int(* ELEM_END_FUNC)(void *, const char *)
Definition: xml_parser.h:70
void xml_destroy_parser_data(void *data)
Definition: xml_parser.c:1067
void xml_destroy_parser(void *data)
Definition: xml_parser.c:977
XML_PARSER_DATA * next
Definition: xml_parser.h:127
int xml_check_att_value(const char **attrs, const char *att_name, const char *att_value)
Definition: xml_parser.c:1152
int i
Definition: dynamic_load.c:954
static char * get_elem_path_token_at(const XML_ELEMENT_DEF *el_def, const int level, char *short_name)
Definition: xml_parser.c:516
#define XML_CUB_ERR_PARSER_INIT_FAIL
Definition: xml_parser.h:45
static XML_ELEMENT * select_xml_node_for_ins(XML_ELEMENT *xml_node, const char *sel_name, XML_INS_POS *insert_pos)
Definition: xml_parser.c:466
XML_ELEMENT * next
Definition: xml_parser.h:100
#define MAX_ELEMENT_NAME
Definition: xml_parser.h:48
const char * short_name
Definition: xml_parser.h:97
int xml_get_att_value(const char **attrs, const char *att_name, char **p_att_value)
Definition: xml_parser.c:1180
#define XML_CUB_ERR_INCLUDE_LOOP
Definition: xml_parser.h:44
static void XMLCALL xml_elem_end(void *data, const char *parsed_el_name)
Definition: xml_parser.c:771
XML_PARSER_DATA * prev
Definition: xml_parser.h:126
const char ** p
Definition: dynamic_load.c:945
static void XMLCALL xml_data_handler(void *data, const XML_Char *s, int len)
Definition: xml_parser.c:828
XML_ELEMENT * ce
Definition: xml_parser.h:117