1 /******************************************************************************
2 * Copyright (c) 2000-2016 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
15 ******************************************************************************/
16 #include "XMLParser.hh"
17 #include "TTCN3Module.hh"
18 #include "SimpleType.hh"
19 #include "ComplexType.hh"
21 #include "GeneralFunctions.hh"
23 #include <cstring> // for using "memset" function
28 #define ULLONG_MAX 18446744073709551615ULL
31 #define LLONG_MIN -9223372036854775808LL
34 #define LLONG_MAX 9223372036854775807LL
37 extern bool V_flag_used
;
38 extern bool w_flag_used
;
39 extern bool x_flag_used
;
41 bool XMLParser::suspended
= false;
42 unsigned int XMLParser::num_errors
= 0;
43 unsigned int XMLParser::num_warnings
= 0;
45 XMLParser::XMLParser(const char * a_filename
)
46 : module(NULL
) // get value with 'connectWithModule()' method
47 , filename(a_filename
) // includes the path of the file
50 , parserCheckingXML(NULL
)
51 , contextCheckingXML(NULL
)
52 , contextCheckingXSD(NULL
)
54 , actualTagName(n_NOTSET
)
55 , actualTagAttributes(this)
57 , inside_annotation(){
58 xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader
);
60 parserCheckingXML
= (xmlSAXHandler
*) malloc(sizeof (xmlSAXHandler
));
61 memset(parserCheckingXML
, 0, sizeof (xmlSAXHandler
));
62 parserCheckingXML
->initialized
= XML_SAX2_MAGIC
;
63 parserCheckingXML
->warning
= warningHandler
;
64 parserCheckingXML
->error
= errorHandler
;
65 contextCheckingXML
= xmlCreateFileParserCtxt(a_filename
);
66 if (!contextCheckingXML
) {
69 "Creating XML syntax checker has failed.\n");
73 contextCheckingXML
->sax
= parserCheckingXML
;
76 contextCheckingXSD
= xmlSchemaNewParserCtxt(a_filename
);
77 if (!contextCheckingXSD
) {
80 "Creating XSD validator has failed.\n");
84 xmlSchemaSetParserErrors(contextCheckingXSD
, errorHandler
, warningHandler
, 0);
87 parser
= (xmlSAXHandler
*) malloc(sizeof (xmlSAXHandler
));
88 memset(parser
, 0, sizeof (xmlSAXHandler
));
89 parser
->initialized
= XML_SAX2_MAGIC
;
90 parser
->startElementNs
= (startElementNsSAX2Func
) wrapper_to_call_startelement_h
;
91 parser
->endElementNs
= (endElementNsSAX2Func
) wrapper_to_call_endelement_h
;
92 parser
->characters
= (charactersSAXFunc
) wrapper_to_call_characterdata_h
;
93 parser
->comment
= (commentSAXFunc
) wrapper_to_call_comment_h
;
95 context
= xmlCreateFileParserCtxt(filename
.c_str());
99 "Creating parser for file '%s' has failed.\n", filename
.c_str());
103 context
->sax
= parser
;
104 context
->userData
= this;
107 XMLParser::~XMLParser() {
109 xmlFreeDoc(context
->myDoc
);
110 contextCheckingXML
->sax
= NULL
;
112 free(parserCheckingXML
);
114 xmlFreeParserCtxt(context
);
116 if (contextCheckingXML
) {
117 xmlFreeParserCtxt(contextCheckingXML
);
119 if (contextCheckingXSD
) {
120 xmlSchemaFreeParserCtxt(contextCheckingXSD
);
124 void XMLParser::checkSyntax() {
125 xmlParseDocument(contextCheckingXML
);
128 void XMLParser::validate() {
130 xmlSchemaPtr schema
= xmlSchemaParse(contextCheckingXSD
);
132 xmlSchemaValidCtxtPtr validator
= xmlSchemaNewValidCtxt(schema
);
134 // do not use this->context!
135 xmlParserCtxtPtr newcontext
= xmlNewParserCtxt();
136 xmlDocPtr doc
= xmlCtxtReadFile(newcontext
, filename
.c_str(), NULL
, 0);
138 // Don't try this, it always fails
139 //int result = xmlSchemaValidateDoc(validator, doc);
140 //(void)result; // 0=ok, errorcode > 0, intrnal error == -1
143 xmlSchemaFreeValidCtxt(validator
);
144 xmlFreeParserCtxt(newcontext
);
146 xmlSchemaFree(schema
);
151 void XMLParser::startConversion(TTCN3Module
* a_module
) {
153 xmlParseDocument(context
);
156 void XMLParser::wrapper_to_call_startelement_h(XMLParser
*self
, const xmlChar
* localname
, const xmlChar
*, const xmlChar
*,
157 int nb_namespaces
, const xmlChar
** namespaces
, const int nb_attributes
, int, const xmlChar
** attributes
) {
158 self
->startelementHandler(localname
, nb_namespaces
, namespaces
, nb_attributes
, attributes
);
161 void XMLParser::wrapper_to_call_endelement_h(XMLParser
*self
, const xmlChar
* localname
, const xmlChar
*, const xmlChar
*) {
162 self
->endelementHandler(localname
);
165 void XMLParser::wrapper_to_call_comment_h(XMLParser
*self
, const xmlChar
* value
) {
166 self
->commentHandler(value
);
169 void XMLParser::wrapper_to_call_characterdata_h(XMLParser
*self
, const xmlChar
* ch
, int len
) {
170 self
->characterdataHandler(ch
, len
);
173 void XMLParser::warningHandler(void *, const char *, ...) {
178 xmlErrorPtr error
= xmlGetLastError();
180 if (error
->file
== NULL
) {
197 void XMLParser::errorHandler(void *, const char *, ...) {
198 xmlErrorPtr error
= xmlGetLastError();
200 if (error
->code
== XML_SCHEMAP_SRC_RESOLVE
) {
203 if (error
->code
== XML_SCHEMAP_COS_ALL_LIMITED
) {
207 switch (error
->level
) {
209 fputs("ERROR:\n", stderr
);
212 fputs("FATAL ERROR:\n", stderr
);
214 default: // warning or no error, can't happen (famous last words)
218 if (error
->file
!= NULL
) {
219 fprintf(stderr
, "%s (in line %d): ", error
->file
, error
->line
);
222 fputs(error
->message
, stderr
); // libxml2 supplies a trailing \n
226 void XMLParser::startelementHandler(const xmlChar
* localname
,
227 int nb_namespaces
, const xmlChar
** namespaces
, int nb_attributes
, const xmlChar
** attributes
) {
228 fillUpActualTagName((const char *) localname
, startElement
);
229 fillUpActualTagAttributes((const char **) attributes
, nb_attributes
);
231 switch (module
->getActualXsdConstruct()) {
234 switch (actualTagName
) {
237 module
->setActualXsdConstruct(c_schema
);
239 module
->loadValuesFromXMLDeclaration((const char *) context
->version
,
240 (const char *) context
->encoding
, context
->standalone
);
242 List
<NamespaceType
> declaredNamespaces
;
243 for (int i
= 0; i
< nb_namespaces
* 2; i
= i
+ 2) {
244 NamespaceType tmp_ns_pair
;
246 if (namespaces
[i
] != NULL
) {
247 tmp_ns_pair
.prefix
= (const char*) namespaces
[i
];
249 // else leave it as empty string
251 if (namespaces
[i
+ 1] != NULL
) {
252 tmp_ns_pair
.uri
= (const char*) namespaces
[i
+ 1];
254 // else leave it as empty string
256 declaredNamespaces
.push_back(tmp_ns_pair
);
259 module
->loadValuesFromSchemaTag(actualTagAttributes
.targetNamespace
, declaredNamespaces
,
260 actualTagAttributes
.elementFormDefault
, actualTagAttributes
.attributeFormDefault
,
261 actualTagAttributes
.blockDefault
);
272 switch (actualTagName
) {
274 module
->addMainType(c_simpleType
);
277 module
->addMainType(c_element
);
280 module
->addMainType(c_attribute
);
283 module
->addMainType(c_complexType
);
286 module
->addMainType(c_group
);
288 case n_attributeGroup
:
289 module
->addMainType(c_attributeGroup
);
292 module
->addMainType(c_include
);
295 module
->addMainType(c_import
);
304 if (module
->hasDefinedMainType()) {
305 if(actualTagName
== n_annotation
||
306 actualTagName
== n_appinfo
||
307 actualTagName
== n_documentation
){
308 inside_annotation
.push_back(actualTagName
);
309 module
->getLastMainType().loadWithValues();
310 }else if(inside_annotation
.empty()){
311 module
->getLastMainType().loadWithValues();
317 //Standard section 7.1.1
318 if (!actualTagAttributes
.id
.empty()) {
319 ConstructType type
= module
->getActualXsdConstruct();
320 module
->addMainType(c_idattrib
);
321 module
->setActualXsdConstruct(type
);
325 parentTagNames
.push_back(actualTagName
);
328 void XMLParser::endelementHandler(const xmlChar
* localname
) {
329 fillUpActualTagName((const char *) localname
, endElement
);
332 TagName tag
= parentTagNames
.back();
333 //After some tags there is no need to call modifyValues
334 if (tag
== n_element
||
338 tag
== n_attributeGroup
||
339 tag
== n_extension
||
340 tag
== n_simpleType
||
341 tag
== n_simpleContent
||
343 tag
== n_complexType
||
344 tag
== n_complexContent
||
345 tag
== n_attribute
||
346 tag
== n_anyAttribute
351 if(tag
== n_annotation
||
353 tag
== n_documentation
){
354 inside_annotation
.pop_back();
359 if (actualDepth
== 0 || actualDepth
== 1) {
360 module
->setActualXsdConstruct(c_schema
);
363 if (module
->hasDefinedMainType() && modify
) {
364 module
->getLastMainType().modifyValues();
366 parentTagNames
.pop_back();
369 void XMLParser::commentHandler(const xmlChar
* text
) {
370 Mstring
comment((const char *) text
);
371 comment
.removeWSfromBegin();
372 comment
.removeWSfromEnd();
373 if (comment
.empty()) {
377 if (module
->getActualXsdConstruct() == c_schema
) {
378 module
->addMainType(c_annotation
);
379 module
->setActualXsdConstruct(c_schema
); // actualXsdConstruct was set to c_annotation
382 if (module
->hasDefinedMainType()) {
383 module
->getLastMainType().addComment(comment
);
387 void XMLParser::characterdataHandler(const xmlChar
* text
, const int length
) {
392 char * temp
= (char *) Malloc(length
+ 1);
393 memcpy(temp
, text
, length
);
395 Mstring
comment(temp
);
398 comment
.removeWSfromBegin();
399 comment
.removeWSfromEnd();
400 if (comment
.empty()) {
404 if (module
->getActualXsdConstruct() == c_schema
) {
405 module
->addMainType(c_annotation
);
407 if (module
->hasDefinedMainType()) {
408 module
->getLastMainType().addComment(comment
);
412 void XMLParser::fillUpActualTagName(const char * localname
, const tagMode mode
) {
413 Mstring
name_s(localname
);
416 actualTagName
= n_all
;
417 else if (name_s
== "annotation")
418 actualTagName
= n_annotation
;
419 else if (name_s
== "any")
420 actualTagName
= n_any
;
421 else if (name_s
== "anyAttribute")
422 actualTagName
= n_anyAttribute
;
423 else if (name_s
== "appinfo") {
424 actualTagName
= n_appinfo
;
435 } else if (name_s
== "attribute")
436 actualTagName
= n_attribute
;
437 else if (name_s
== "attributeGroup")
438 actualTagName
= n_attributeGroup
;
439 else if (name_s
== "choice")
440 actualTagName
= n_choice
;
441 else if (name_s
== "complexContent")
442 actualTagName
= n_complexContent
;
443 else if (name_s
== "complexType")
444 actualTagName
= n_complexType
;
445 else if (name_s
== "definition")
446 actualTagName
= n_definition
;
447 else if (name_s
== "documentation")
448 actualTagName
= n_documentation
;
449 else if (name_s
== "element")
450 actualTagName
= n_element
;
451 else if (name_s
== "enumeration")
452 actualTagName
= n_enumeration
;
453 else if (name_s
== "extension")
454 actualTagName
= n_extension
;
455 else if (name_s
== "field") {
456 actualTagName
= n_field
;
457 if (mode
== startElement
) {
458 printWarning(filename
, xmlSAX2GetLineNumber(context
),
459 Mstring("The 'field' tag is ignored by the standard."));
462 } else if (name_s
== "fractionDigits") {
463 actualTagName
= n_fractionDigits
;
464 if (mode
== startElement
) {
465 printWarning(filename
, xmlSAX2GetLineNumber(context
),
466 Mstring("The 'fractionDigits' tag is currently not supported."));
469 } else if (name_s
== "group")
470 actualTagName
= n_group
;
471 else if (name_s
== "import")
472 actualTagName
= n_import
;
473 else if (name_s
== "include")
474 actualTagName
= n_include
;
475 else if (name_s
== "key") {
476 actualTagName
= n_key
;
477 if (mode
== startElement
) {
478 printWarning(filename
, xmlSAX2GetLineNumber(context
),
479 Mstring("The 'key' tag is ignored by the standard."));
482 } else if (name_s
== "keyref") {
483 actualTagName
= n_keyref
;
484 if (mode
== startElement
) {
485 printWarning(filename
, xmlSAX2GetLineNumber(context
),
486 Mstring("The 'keyref' tag ignored by the standard."));
489 } else if (name_s
== "length")
490 actualTagName
= n_length
;
491 else if (name_s
== "label")
492 actualTagName
= n_label
;
493 else if (name_s
== "list")
494 actualTagName
= n_list
;
495 else if (name_s
== "maxExclusive")
496 actualTagName
= n_maxExclusive
;
497 else if (name_s
== "maxInclusive")
498 actualTagName
= n_maxInclusive
;
499 else if (name_s
== "maxLength")
500 actualTagName
= n_maxLength
;
501 else if (name_s
== "minExclusive")
502 actualTagName
= n_minExclusive
;
503 else if (name_s
== "minInclusive")
504 actualTagName
= n_minInclusive
;
505 else if (name_s
== "minLength")
506 actualTagName
= n_minLength
;
507 else if (name_s
== "notation")
509 else if (name_s
== "pattern")
510 actualTagName
= n_pattern
;
511 else if (name_s
== "redefine")
512 actualTagName
= n_redefine
;
513 else if (name_s
== "restriction")
514 actualTagName
= n_restriction
;
515 else if (name_s
== "schema")
516 actualTagName
= n_schema
;
517 else if (name_s
== "selector") {
518 actualTagName
= n_selector
;
519 if (mode
== startElement
) {
520 printWarning(filename
, xmlSAX2GetLineNumber(context
),
521 Mstring("The 'selector' tag ignored by the standard."));
524 } else if (name_s
== "sequence")
525 actualTagName
= n_sequence
;
526 else if (name_s
== "simpleContent")
527 actualTagName
= n_simpleContent
;
528 else if (name_s
== "simpleType")
529 actualTagName
= n_simpleType
;
530 else if (name_s
== "totalDigits")
531 actualTagName
= n_totalDigits
;
532 else if (name_s
== "union")
533 actualTagName
= n_union
;
534 else if (name_s
== "unique") {
535 actualTagName
= n_unique
;
536 if (mode
== startElement
) {
537 printWarning(filename
, xmlSAX2GetLineNumber(context
),
538 Mstring("The 'unique' tag ignored by the standard."));
541 } else if (name_s
== "whiteSpace")
542 actualTagName
= n_whiteSpace
;
545 void XMLParser::fillUpActualTagAttributes(const char ** attributes
, const int att_count
) {
547 struct attribute_data
{
551 const char * value_start
;
552 const char * value_end
;
554 attribute_data
* ad
= (attribute_data
*) attributes
;
556 Mstring
* att_name_s
= new Mstring
[att_count
];
557 Mstring
* att_value_s
= new Mstring
[att_count
];
558 TagAttributeName
* att_name_e
= new TagAttributeName
[att_count
];
560 for (int i
= 0; i
!= att_count
; ++i
) {
561 att_name_s
[i
] = ad
[i
].name
;
562 att_value_s
[i
] = Mstring(ad
[i
].value_end
- ad
[i
].value_start
, ad
[i
].value_start
);
564 att_name_e
[i
] = a_NOTSET
;
565 if (att_name_s
[i
] == "abstract") {
566 att_name_e
[i
] = a_abstract
;
567 } else if (att_name_s
[i
] == "attributeFormDefault")
568 att_name_e
[i
] = a_attributeFormDefault
;
569 else if (att_name_s
[i
] == "base")
570 att_name_e
[i
] = a_base
;
571 else if (att_name_s
[i
] == "block") {
572 att_name_e
[i
] = a_block
;
573 } else if (att_name_s
[i
] == "blockDefault"){
574 att_name_e
[i
] = a_blockDefault
;
575 } else if (att_name_s
[i
] == "default")
576 att_name_e
[i
] = a_default
;
577 else if (att_name_s
[i
] == "elementFormDefault")
578 att_name_e
[i
] = a_elementFormDefault
;
579 else if (att_name_s
[i
] == "final") {
580 att_name_e
[i
] = a_final
; // no effect on the output
581 } else if (att_name_s
[i
] == "finalDefault")
583 else if (att_name_s
[i
] == "fixed")
584 att_name_e
[i
] = a_fixed
;
585 else if (att_name_s
[i
] == "form")
586 att_name_e
[i
] = a_form
;
587 else if (att_name_s
[i
] == "id")
588 att_name_e
[i
] = a_id
;
589 else if (att_name_s
[i
] == "itemType")
590 att_name_e
[i
] = a_itemType
;
591 else if (att_name_s
[i
] == "lang")
593 else if (att_name_s
[i
] == "maxOccurs")
594 att_name_e
[i
] = a_maxOccurs
;
595 else if (att_name_s
[i
] == "memberTypes")
596 att_name_e
[i
] = a_memberTypes
;
597 else if (att_name_s
[i
] == "minOccurs")
598 att_name_e
[i
] = a_minOccurs
;
599 else if (att_name_s
[i
] == "mixed")
600 att_name_e
[i
] = a_mixed
;
601 else if (att_name_s
[i
] == "name")
602 att_name_e
[i
] = a_name
;
603 else if (att_name_s
[i
] == "namespace")
604 att_name_e
[i
] = a_namespace
;
605 else if (att_name_s
[i
] == "nillable")
606 att_name_e
[i
] = a_nillable
;
607 else if (att_name_s
[i
] == "processContents") {
608 att_name_e
[i
] = a_processContents
;
610 } else if (att_name_s
[i
] == "ref")
611 att_name_e
[i
] = a_ref
;
612 else if (att_name_s
[i
] == "schemaLocation")
613 att_name_e
[i
] = a_schemaLocation
;
614 else if (att_name_s
[i
] == "substitutionGroup") {
615 att_name_e
[i
] = a_substitutionGroup
;
616 } else if (att_name_s
[i
] == "targetNamespace")
617 att_name_e
[i
] = a_targetNamespace
;
618 else if (att_name_s
[i
] == "type")
619 att_name_e
[i
] = a_type
;
620 else if (att_name_s
[i
] == "use")
621 att_name_e
[i
] = a_use
;
622 else if (att_name_s
[i
] == "value")
623 att_name_e
[i
] = a_value
;
624 else if (att_name_s
[i
] == "version") {
627 actualTagAttributes
.fillUp(att_name_e
, att_value_s
, att_count
);
628 delete [] att_name_s
;
629 delete [] att_value_s
;
630 delete [] att_name_e
;
633 XMLParser::TagAttributes::TagAttributes(XMLParser
* withThisParser
)
634 : parser(withThisParser
)
635 , attributeFormDefault(notset
)
638 , elementFormDefault(notset
)
659 void XMLParser::TagAttributes::fillUp(TagAttributeName
* att_name_e
, Mstring
* att_value_s
, const int att_count
) {
664 attributeFormDefault
= notset
;
667 blockDefault
= not_set
,
669 elementFormDefault
= notset
;
682 schemaLocation
.clear();
684 substitionGroup
= empty_string
;
685 targetNamespace
.clear();
692 for (int i
= 0; i
!= att_count
; ++i
) {
693 switch (att_name_e
[i
]) {
694 case a_abstract
: // Not supported by now
695 if (att_value_s
[i
] == "true") {
697 } else if (att_value_s
[i
] == "false") {
700 case a_attributeFormDefault
: // qualified | unqualified
701 if (att_value_s
[i
] == "qualified") {
702 attributeFormDefault
= qualified
;
703 } else if (att_value_s
[i
] == "unqualified") {
704 attributeFormDefault
= unqualified
;
707 case a_base
: // QName = anyURI + NCName
708 base
= att_value_s
[i
];
710 case a_block
: // Not supported by now
711 if(att_value_s
[i
] == "#all"){
713 }else if(att_value_s
[i
] == "substitution"){
714 block
= substitution
;
715 }else if(att_value_s
[i
] == "restriction"){
717 }else if(att_value_s
[i
] == "extension"){
721 case a_blockDefault
: // Not supported by now
722 if(att_value_s
[i
] == "#all"){
724 }else if(att_value_s
[i
] == "substitution"){
725 blockDefault
= substitution
;
726 }else if(att_value_s
[i
] == "restriction"){
727 blockDefault
= restriction
;
728 }else if(att_value_s
[i
] == "extension"){
729 blockDefault
= extension
;
732 case a_default
: // string
733 default_
= att_value_s
[i
];
735 case a_elementFormDefault
:
736 if (att_value_s
[i
] == "qualified") {
737 elementFormDefault
= qualified
;
738 } else if (att_value_s
[i
] == "unqualified") {
739 elementFormDefault
= unqualified
;
742 case a_final
: // Not supported by now
744 case a_finalDefault
: // Not supported by now
746 case a_fixed
: // string
747 fixed
= att_value_s
[i
];
749 case a_form
: // qualified | unqualified
750 if (att_value_s
[i
] == "qualified") {
752 } else if (att_value_s
[i
] == "unqualified") {
758 case a_id
: // ID = NCName
761 case a_itemType
: // QName = anyURI + NCName /- used in 'list' tag only
762 itemType
= att_value_s
[i
];
764 case a_maxOccurs
: // nonNegativeinteger or 'unbounded'
765 if (att_value_s
[i
] == "unbounded") {
766 maxOccurs
= ULLONG_MAX
;
768 maxOccurs
= strtoull(att_value_s
[i
].c_str(), NULL
, 0);
771 case a_memberTypes
: // list of QNames - used in 'union' tag only
772 memberTypes
= att_value_s
[i
];
774 case a_minOccurs
: // nonNegativeInteger
775 minOccurs
= strtoull(att_value_s
[i
].c_str(), NULL
, 0);
777 case a_mixed
: // true | false
778 if (att_value_s
[i
] == "true") {
780 } else if (att_value_s
[i
] == "false") {
784 case a_name
: // NCName
785 name
= att_value_s
[i
];
787 case a_namespace
: // anyURI
788 namespace_
= att_value_s
[i
];
790 case a_nillable
: // true | false
791 if (att_value_s
[i
] == "true") {
793 } else if (att_value_s
[i
] == "false") {
797 case a_processContents
: // Not supported by now
799 case a_ref
: // QName = anyURI + NCName
800 ref
= att_value_s
[i
];
802 case a_schemaLocation
: // anyURI
803 schemaLocation
= att_value_s
[i
];
805 case a_substitutionGroup
:
806 substitionGroup
= att_value_s
[i
];
808 case a_targetNamespace
: // anyURI
809 targetNamespace
= att_value_s
[i
];
811 case a_type
: // QName = anyURI + NCName
812 type
= att_value_s
[i
];
814 case a_use
: // optional | prohibited | required - used in 'use' tag only
815 if (att_value_s
[i
] == "optional") {
817 } else if (att_value_s
[i
] == "prohibited") {
819 } else if (att_value_s
[i
] == "required") {
823 case a_value
: // value of FACETS
824 value
= att_value_s
[i
];
828 case a_version
: // Not supported by now
833 fprintf(stderr
, "Unknown TagAttributeName %d\n", att_name_e
[i
]);