1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 #include "XMLParser.hh"
9 #include "TTCN3Module.hh"
10 #include "SimpleType.hh"
11 #include "ComplexType.hh"
13 #include "GeneralFunctions.hh"
15 #include <cstring> // for using "memset" function
20 #define ULLONG_MAX 18446744073709551615ULL
23 #define LLONG_MIN -9223372036854775808LL
26 #define LLONG_MAX 9223372036854775807LL
29 extern bool V_flag_used
;
30 extern bool w_flag_used
;
31 extern bool x_flag_used
;
33 bool XMLParser::suspended
= false;
34 unsigned int XMLParser::num_errors
= 0;
35 unsigned int XMLParser::num_warnings
= 0;
37 XMLParser::XMLParser(const char * a_filename
)
38 : module(NULL
) // get value with 'connectWithModule()' method
39 , filename(a_filename
) // includes the path of the file
42 , parserCheckingXML(NULL
)
43 , contextCheckingXML(NULL
)
44 , contextCheckingXSD(NULL
)
46 , actualTagName(n_NOTSET
)
47 , actualTagAttributes(this)
49 , inside_annotation(){
50 xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader
);
52 parserCheckingXML
= (xmlSAXHandler
*) malloc(sizeof (xmlSAXHandler
));
53 memset(parserCheckingXML
, 0, sizeof (xmlSAXHandler
));
54 parserCheckingXML
->initialized
= XML_SAX2_MAGIC
;
55 parserCheckingXML
->warning
= warningHandler
;
56 parserCheckingXML
->error
= errorHandler
;
57 contextCheckingXML
= xmlCreateFileParserCtxt(a_filename
);
58 if (!contextCheckingXML
) {
61 "Creating XML syntax checker has failed.\n");
65 contextCheckingXML
->sax
= parserCheckingXML
;
68 contextCheckingXSD
= xmlSchemaNewParserCtxt(a_filename
);
69 if (!contextCheckingXSD
) {
72 "Creating XSD validator has failed.\n");
76 xmlSchemaSetParserErrors(contextCheckingXSD
, errorHandler
, warningHandler
, 0);
79 parser
= (xmlSAXHandler
*) malloc(sizeof (xmlSAXHandler
));
80 memset(parser
, 0, sizeof (xmlSAXHandler
));
81 parser
->initialized
= XML_SAX2_MAGIC
;
82 parser
->startElementNs
= (startElementNsSAX2Func
) wrapper_to_call_startelement_h
;
83 parser
->endElementNs
= (endElementNsSAX2Func
) wrapper_to_call_endelement_h
;
84 parser
->characters
= (charactersSAXFunc
) wrapper_to_call_characterdata_h
;
85 parser
->comment
= (commentSAXFunc
) wrapper_to_call_comment_h
;
87 context
= xmlCreateFileParserCtxt(filename
.c_str());
91 "Creating parser for file '%s' has failed.\n", filename
.c_str());
95 context
->sax
= parser
;
96 context
->userData
= this;
99 XMLParser::~XMLParser() {
101 xmlFreeDoc(context
->myDoc
);
102 contextCheckingXML
->sax
= NULL
;
104 free(parserCheckingXML
);
106 xmlFreeParserCtxt(context
);
108 if (contextCheckingXML
) {
109 xmlFreeParserCtxt(contextCheckingXML
);
111 if (contextCheckingXSD
) {
112 xmlSchemaFreeParserCtxt(contextCheckingXSD
);
116 void XMLParser::checkSyntax() {
117 xmlParseDocument(contextCheckingXML
);
120 void XMLParser::validate() {
122 xmlSchemaPtr schema
= xmlSchemaParse(contextCheckingXSD
);
124 xmlSchemaValidCtxtPtr validator
= xmlSchemaNewValidCtxt(schema
);
126 // do not use this->context!
127 xmlParserCtxtPtr newcontext
= xmlNewParserCtxt();
128 xmlDocPtr doc
= xmlCtxtReadFile(newcontext
, filename
.c_str(), NULL
, 0);
130 // Don't try this, it always fails
131 //int result = xmlSchemaValidateDoc(validator, doc);
132 //(void)result; // 0=ok, errorcode > 0, intrnal error == -1
135 xmlSchemaFreeValidCtxt(validator
);
136 xmlFreeParserCtxt(newcontext
);
138 xmlSchemaFree(schema
);
143 void XMLParser::startConversion(TTCN3Module
* a_module
) {
145 xmlParseDocument(context
);
148 void XMLParser::wrapper_to_call_startelement_h(XMLParser
*self
, const xmlChar
* localname
, const xmlChar
*, const xmlChar
*,
149 int nb_namespaces
, const xmlChar
** namespaces
, const int nb_attributes
, int, const xmlChar
** attributes
) {
150 self
->startelementHandler(localname
, nb_namespaces
, namespaces
, nb_attributes
, attributes
);
153 void XMLParser::wrapper_to_call_endelement_h(XMLParser
*self
, const xmlChar
* localname
, const xmlChar
*, const xmlChar
*) {
154 self
->endelementHandler(localname
);
157 void XMLParser::wrapper_to_call_comment_h(XMLParser
*self
, const xmlChar
* value
) {
158 self
->commentHandler(value
);
161 void XMLParser::wrapper_to_call_characterdata_h(XMLParser
*self
, const xmlChar
* ch
, int len
) {
162 self
->characterdataHandler(ch
, len
);
165 void XMLParser::warningHandler(void *, const char *, ...) {
170 xmlErrorPtr error
= xmlGetLastError();
172 if (error
->file
== NULL
) {
189 void XMLParser::errorHandler(void *, const char *, ...) {
190 xmlErrorPtr error
= xmlGetLastError();
192 if (error
->code
== XML_SCHEMAP_SRC_RESOLVE
) {
195 if (error
->code
== XML_SCHEMAP_COS_ALL_LIMITED
) {
199 switch (error
->level
) {
201 fputs("ERROR:\n", stderr
);
204 fputs("FATAL ERROR:\n", stderr
);
206 default: // warning or no error, can't happen (famous last words)
210 if (error
->file
!= NULL
) {
211 fprintf(stderr
, "%s (in line %d): ", error
->file
, error
->line
);
214 fputs(error
->message
, stderr
); // libxml2 supplies a trailing \n
218 void XMLParser::startelementHandler(const xmlChar
* localname
,
219 int nb_namespaces
, const xmlChar
** namespaces
, int nb_attributes
, const xmlChar
** attributes
) {
220 fillUpActualTagName((const char *) localname
, startElement
);
221 fillUpActualTagAttributes((const char **) attributes
, nb_attributes
);
223 switch (module
->getActualXsdConstruct()) {
226 switch (actualTagName
) {
229 module
->setActualXsdConstruct(c_schema
);
231 module
->loadValuesFromXMLDeclaration((const char *) context
->version
,
232 (const char *) context
->encoding
, context
->standalone
);
234 List
<NamespaceType
> declaredNamespaces
;
235 for (int i
= 0; i
< nb_namespaces
* 2; i
= i
+ 2) {
236 NamespaceType tmp_ns_pair
;
238 if (namespaces
[i
] != NULL
) {
239 tmp_ns_pair
.prefix
= (const char*) namespaces
[i
];
241 // else leave it as empty string
243 if (namespaces
[i
+ 1] != NULL
) {
244 tmp_ns_pair
.uri
= (const char*) namespaces
[i
+ 1];
246 // else leave it as empty string
248 declaredNamespaces
.push_back(tmp_ns_pair
);
251 module
->loadValuesFromSchemaTag(actualTagAttributes
.targetNamespace
, declaredNamespaces
,
252 actualTagAttributes
.elementFormDefault
, actualTagAttributes
.attributeFormDefault
,
253 actualTagAttributes
.blockDefault
);
264 switch (actualTagName
) {
266 module
->addMainType(c_simpleType
);
269 module
->addMainType(c_element
);
272 module
->addMainType(c_attribute
);
275 module
->addMainType(c_complexType
);
278 module
->addMainType(c_group
);
280 case n_attributeGroup
:
281 module
->addMainType(c_attributeGroup
);
284 module
->addMainType(c_include
);
287 module
->addMainType(c_import
);
296 if (module
->hasDefinedMainType()) {
297 if(actualTagName
== n_annotation
||
298 actualTagName
== n_appinfo
||
299 actualTagName
== n_documentation
){
300 inside_annotation
.push_back(actualTagName
);
301 module
->getLastMainType().loadWithValues();
302 }else if(inside_annotation
.empty()){
303 module
->getLastMainType().loadWithValues();
309 //Standard section 7.1.1
310 if (!actualTagAttributes
.id
.empty()) {
311 ConstructType type
= module
->getActualXsdConstruct();
312 module
->addMainType(c_idattrib
);
313 module
->setActualXsdConstruct(type
);
317 parentTagNames
.push_back(actualTagName
);
320 void XMLParser::endelementHandler(const xmlChar
* localname
) {
321 fillUpActualTagName((const char *) localname
, endElement
);
324 TagName tag
= parentTagNames
.back();
325 //After some tags there is no need to call modifyValues
326 if (tag
== n_element
||
330 tag
== n_attributeGroup
||
331 tag
== n_extension
||
332 tag
== n_simpleType
||
333 tag
== n_simpleContent
||
335 tag
== n_complexType
||
336 tag
== n_complexContent
||
337 tag
== n_attribute
||
338 tag
== n_anyAttribute
343 if(tag
== n_annotation
||
345 tag
== n_documentation
){
346 inside_annotation
.pop_back();
351 if (actualDepth
== 0 || actualDepth
== 1) {
352 module
->setActualXsdConstruct(c_schema
);
355 if (module
->hasDefinedMainType() && modify
) {
356 module
->getLastMainType().modifyValues();
358 parentTagNames
.pop_back();
361 void XMLParser::commentHandler(const xmlChar
* text
) {
362 Mstring
comment((const char *) text
);
363 comment
.removeWSfromBegin();
364 comment
.removeWSfromEnd();
365 if (comment
.empty()) {
369 if (module
->getActualXsdConstruct() == c_schema
) {
370 module
->addMainType(c_annotation
);
371 module
->setActualXsdConstruct(c_schema
); // actualXsdConstruct was set to c_annotation
374 if (module
->hasDefinedMainType()) {
375 module
->getLastMainType().addComment(comment
);
379 void XMLParser::characterdataHandler(const xmlChar
* text
, const int length
) {
384 char * temp
= (char *) Malloc(length
+ 1);
385 memcpy(temp
, text
, length
);
387 Mstring
comment(temp
);
390 comment
.removeWSfromBegin();
391 comment
.removeWSfromEnd();
392 if (comment
.empty()) {
396 if (module
->getActualXsdConstruct() == c_schema
) {
397 module
->addMainType(c_annotation
);
399 if (module
->hasDefinedMainType()) {
400 module
->getLastMainType().addComment(comment
);
404 void XMLParser::fillUpActualTagName(const char * localname
, const tagMode mode
) {
405 Mstring
name_s(localname
);
408 actualTagName
= n_all
;
409 else if (name_s
== "annotation")
410 actualTagName
= n_annotation
;
411 else if (name_s
== "any")
412 actualTagName
= n_any
;
413 else if (name_s
== "anyAttribute")
414 actualTagName
= n_anyAttribute
;
415 else if (name_s
== "appinfo") {
416 actualTagName
= n_appinfo
;
427 } else if (name_s
== "attribute")
428 actualTagName
= n_attribute
;
429 else if (name_s
== "attributeGroup")
430 actualTagName
= n_attributeGroup
;
431 else if (name_s
== "choice")
432 actualTagName
= n_choice
;
433 else if (name_s
== "complexContent")
434 actualTagName
= n_complexContent
;
435 else if (name_s
== "complexType")
436 actualTagName
= n_complexType
;
437 else if (name_s
== "definition")
438 actualTagName
= n_definition
;
439 else if (name_s
== "documentation")
440 actualTagName
= n_documentation
;
441 else if (name_s
== "element")
442 actualTagName
= n_element
;
443 else if (name_s
== "enumeration")
444 actualTagName
= n_enumeration
;
445 else if (name_s
== "extension")
446 actualTagName
= n_extension
;
447 else if (name_s
== "field") {
448 actualTagName
= n_field
;
449 if (mode
== startElement
) {
450 printWarning(filename
, xmlSAX2GetLineNumber(context
),
451 Mstring("The 'field' tag is ignored by the standard."));
454 } else if (name_s
== "fractionDigits") {
455 actualTagName
= n_fractionDigits
;
456 if (mode
== startElement
) {
457 printWarning(filename
, xmlSAX2GetLineNumber(context
),
458 Mstring("The 'fractionDigits' tag is currently not supported."));
461 } else if (name_s
== "group")
462 actualTagName
= n_group
;
463 else if (name_s
== "import")
464 actualTagName
= n_import
;
465 else if (name_s
== "include")
466 actualTagName
= n_include
;
467 else if (name_s
== "key") {
468 actualTagName
= n_key
;
469 if (mode
== startElement
) {
470 printWarning(filename
, xmlSAX2GetLineNumber(context
),
471 Mstring("The 'key' tag is ignored by the standard."));
474 } else if (name_s
== "keyref") {
475 actualTagName
= n_keyref
;
476 if (mode
== startElement
) {
477 printWarning(filename
, xmlSAX2GetLineNumber(context
),
478 Mstring("The 'keyref' tag ignored by the standard."));
481 } else if (name_s
== "length")
482 actualTagName
= n_length
;
483 else if (name_s
== "label")
484 actualTagName
= n_label
;
485 else if (name_s
== "list")
486 actualTagName
= n_list
;
487 else if (name_s
== "maxExclusive")
488 actualTagName
= n_maxExclusive
;
489 else if (name_s
== "maxInclusive")
490 actualTagName
= n_maxInclusive
;
491 else if (name_s
== "maxLength")
492 actualTagName
= n_maxLength
;
493 else if (name_s
== "minExclusive")
494 actualTagName
= n_minExclusive
;
495 else if (name_s
== "minInclusive")
496 actualTagName
= n_minInclusive
;
497 else if (name_s
== "minLength")
498 actualTagName
= n_minLength
;
499 else if (name_s
== "notation")
501 else if (name_s
== "pattern")
502 actualTagName
= n_pattern
;
503 else if (name_s
== "redefine")
504 actualTagName
= n_redefine
;
505 else if (name_s
== "restriction")
506 actualTagName
= n_restriction
;
507 else if (name_s
== "schema")
508 actualTagName
= n_schema
;
509 else if (name_s
== "selector") {
510 actualTagName
= n_selector
;
511 if (mode
== startElement
) {
512 printWarning(filename
, xmlSAX2GetLineNumber(context
),
513 Mstring("The 'selector' tag ignored by the standard."));
516 } else if (name_s
== "sequence")
517 actualTagName
= n_sequence
;
518 else if (name_s
== "simpleContent")
519 actualTagName
= n_simpleContent
;
520 else if (name_s
== "simpleType")
521 actualTagName
= n_simpleType
;
522 else if (name_s
== "totalDigits")
523 actualTagName
= n_totalDigits
;
524 else if (name_s
== "union")
525 actualTagName
= n_union
;
526 else if (name_s
== "unique") {
527 actualTagName
= n_unique
;
528 if (mode
== startElement
) {
529 printWarning(filename
, xmlSAX2GetLineNumber(context
),
530 Mstring("The 'unique' tag ignored by the standard."));
533 } else if (name_s
== "whiteSpace")
534 actualTagName
= n_whiteSpace
;
537 void XMLParser::fillUpActualTagAttributes(const char ** attributes
, const int att_count
) {
539 struct attribute_data
{
543 const char * value_start
;
544 const char * value_end
;
546 attribute_data
* ad
= (attribute_data
*) attributes
;
548 Mstring
* att_name_s
= new Mstring
[att_count
];
549 Mstring
* att_value_s
= new Mstring
[att_count
];
550 TagAttributeName
* att_name_e
= new TagAttributeName
[att_count
];
552 for (int i
= 0; i
!= att_count
; ++i
) {
553 att_name_s
[i
] = ad
[i
].name
;
554 att_value_s
[i
] = Mstring(ad
[i
].value_end
- ad
[i
].value_start
, ad
[i
].value_start
);
556 att_name_e
[i
] = a_NOTSET
;
557 if (att_name_s
[i
] == "abstract") {
558 att_name_e
[i
] = a_abstract
;
559 } else if (att_name_s
[i
] == "attributeFormDefault")
560 att_name_e
[i
] = a_attributeFormDefault
;
561 else if (att_name_s
[i
] == "base")
562 att_name_e
[i
] = a_base
;
563 else if (att_name_s
[i
] == "block") {
564 att_name_e
[i
] = a_block
;
565 } else if (att_name_s
[i
] == "blockDefault"){
566 att_name_e
[i
] = a_blockDefault
;
567 } else if (att_name_s
[i
] == "default")
568 att_name_e
[i
] = a_default
;
569 else if (att_name_s
[i
] == "elementFormDefault")
570 att_name_e
[i
] = a_elementFormDefault
;
571 else if (att_name_s
[i
] == "final") {
572 att_name_e
[i
] = a_final
; // no effect on the output
573 } else if (att_name_s
[i
] == "finalDefault")
575 else if (att_name_s
[i
] == "fixed")
576 att_name_e
[i
] = a_fixed
;
577 else if (att_name_s
[i
] == "form")
578 att_name_e
[i
] = a_form
;
579 else if (att_name_s
[i
] == "id")
580 att_name_e
[i
] = a_id
;
581 else if (att_name_s
[i
] == "itemType")
582 att_name_e
[i
] = a_itemType
;
583 else if (att_name_s
[i
] == "lang")
585 else if (att_name_s
[i
] == "maxOccurs")
586 att_name_e
[i
] = a_maxOccurs
;
587 else if (att_name_s
[i
] == "memberTypes")
588 att_name_e
[i
] = a_memberTypes
;
589 else if (att_name_s
[i
] == "minOccurs")
590 att_name_e
[i
] = a_minOccurs
;
591 else if (att_name_s
[i
] == "mixed")
592 att_name_e
[i
] = a_mixed
;
593 else if (att_name_s
[i
] == "name")
594 att_name_e
[i
] = a_name
;
595 else if (att_name_s
[i
] == "namespace")
596 att_name_e
[i
] = a_namespace
;
597 else if (att_name_s
[i
] == "nillable")
598 att_name_e
[i
] = a_nillable
;
599 else if (att_name_s
[i
] == "processContents") {
600 att_name_e
[i
] = a_processContents
;
602 } else if (att_name_s
[i
] == "ref")
603 att_name_e
[i
] = a_ref
;
604 else if (att_name_s
[i
] == "schemaLocation")
605 att_name_e
[i
] = a_schemaLocation
;
606 else if (att_name_s
[i
] == "substitutionGroup") {
607 att_name_e
[i
] = a_substitutionGroup
;
608 } else if (att_name_s
[i
] == "targetNamespace")
609 att_name_e
[i
] = a_targetNamespace
;
610 else if (att_name_s
[i
] == "type")
611 att_name_e
[i
] = a_type
;
612 else if (att_name_s
[i
] == "use")
613 att_name_e
[i
] = a_use
;
614 else if (att_name_s
[i
] == "value")
615 att_name_e
[i
] = a_value
;
616 else if (att_name_s
[i
] == "version") {
619 actualTagAttributes
.fillUp(att_name_e
, att_value_s
, att_count
);
620 delete [] att_name_s
;
621 delete [] att_value_s
;
622 delete [] att_name_e
;
625 XMLParser::TagAttributes::TagAttributes(XMLParser
* withThisParser
)
626 : parser(withThisParser
)
627 , attributeFormDefault(notset
)
630 , elementFormDefault(notset
)
651 void XMLParser::TagAttributes::fillUp(TagAttributeName
* att_name_e
, Mstring
* att_value_s
, const int att_count
) {
656 attributeFormDefault
= notset
;
659 blockDefault
= not_set
,
661 elementFormDefault
= notset
;
674 schemaLocation
.clear();
676 substitionGroup
= empty_string
;
677 targetNamespace
.clear();
684 for (int i
= 0; i
!= att_count
; ++i
) {
685 switch (att_name_e
[i
]) {
686 case a_abstract
: // Not supported by now
687 if (att_value_s
[i
] == "true") {
689 } else if (att_value_s
[i
] == "false") {
692 case a_attributeFormDefault
: // qualified | unqualified
693 if (att_value_s
[i
] == "qualified") {
694 attributeFormDefault
= qualified
;
695 } else if (att_value_s
[i
] == "unqualified") {
696 attributeFormDefault
= unqualified
;
699 case a_base
: // QName = anyURI + NCName
700 base
= att_value_s
[i
];
702 case a_block
: // Not supported by now
703 if(att_value_s
[i
] == "#all"){
705 }else if(att_value_s
[i
] == "substitution"){
706 block
= substitution
;
707 }else if(att_value_s
[i
] == "restriction"){
709 }else if(att_value_s
[i
] == "extension"){
713 case a_blockDefault
: // Not supported by now
714 if(att_value_s
[i
] == "#all"){
716 }else if(att_value_s
[i
] == "substitution"){
717 blockDefault
= substitution
;
718 }else if(att_value_s
[i
] == "restriction"){
719 blockDefault
= restriction
;
720 }else if(att_value_s
[i
] == "extension"){
721 blockDefault
= extension
;
724 case a_default
: // string
725 default_
= att_value_s
[i
];
727 case a_elementFormDefault
:
728 if (att_value_s
[i
] == "qualified") {
729 elementFormDefault
= qualified
;
730 } else if (att_value_s
[i
] == "unqualified") {
731 elementFormDefault
= unqualified
;
734 case a_final
: // Not supported by now
736 case a_finalDefault
: // Not supported by now
738 case a_fixed
: // string
739 fixed
= att_value_s
[i
];
741 case a_form
: // qualified | unqualified
742 if (att_value_s
[i
] == "qualified") {
744 } else if (att_value_s
[i
] == "unqualified") {
750 case a_id
: // ID = NCName
753 case a_itemType
: // QName = anyURI + NCName /- used in 'list' tag only
754 itemType
= att_value_s
[i
];
756 case a_maxOccurs
: // nonNegativeinteger or 'unbounded'
757 if (att_value_s
[i
] == "unbounded") {
758 maxOccurs
= ULLONG_MAX
;
760 maxOccurs
= strtoull(att_value_s
[i
].c_str(), NULL
, 0);
763 case a_memberTypes
: // list of QNames - used in 'union' tag only
764 memberTypes
= att_value_s
[i
];
766 case a_minOccurs
: // nonNegativeInteger
767 minOccurs
= strtoull(att_value_s
[i
].c_str(), NULL
, 0);
769 case a_mixed
: // true | false
770 if (att_value_s
[i
] == "true") {
772 } else if (att_value_s
[i
] == "false") {
776 case a_name
: // NCName
777 name
= att_value_s
[i
];
779 case a_namespace
: // anyURI
780 namespace_
= att_value_s
[i
];
782 case a_nillable
: // true | false
783 if (att_value_s
[i
] == "true") {
785 } else if (att_value_s
[i
] == "false") {
789 case a_processContents
: // Not supported by now
791 case a_ref
: // QName = anyURI + NCName
792 ref
= att_value_s
[i
];
794 case a_schemaLocation
: // anyURI
795 schemaLocation
= att_value_s
[i
];
797 case a_substitutionGroup
:
798 substitionGroup
= att_value_s
[i
];
800 case a_targetNamespace
: // anyURI
801 targetNamespace
= att_value_s
[i
];
803 case a_type
: // QName = anyURI + NCName
804 type
= att_value_s
[i
];
806 case a_use
: // optional | prohibited | required - used in 'use' tag only
807 if (att_value_s
[i
] == "optional") {
809 } else if (att_value_s
[i
] == "prohibited") {
811 } else if (att_value_s
[i
] == "required") {
815 case a_value
: // value of FACETS
816 value
= att_value_s
[i
];
820 case a_version
: // Not supported by now
825 fprintf(stderr
, "Unknown TagAttributeName %d\n", att_name_e
[i
]);