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();
358 if(module
->hasDefinedMainType()) {
359 SimpleType
& st
= (SimpleType
&)(module
->getLastMainType());
360 if(st
.getXsdtype() == n_NOTSET
){
361 st
.setMode(SimpleType::restrictionAfterListMode
);
367 if (actualDepth
== 0 || actualDepth
== 1) {
368 module
->setActualXsdConstruct(c_schema
);
371 if (module
->hasDefinedMainType() && modify
) {
372 module
->getLastMainType().modifyValues();
374 parentTagNames
.pop_back();
377 void XMLParser::commentHandler(const xmlChar
* text
) {
378 Mstring
comment((const char *) text
);
379 comment
.removeWSfromBegin();
380 comment
.removeWSfromEnd();
381 if (comment
.empty()) {
385 if (module
->getActualXsdConstruct() == c_schema
) {
386 module
->addMainType(c_annotation
);
387 module
->setActualXsdConstruct(c_schema
); // actualXsdConstruct was set to c_annotation
390 if (module
->hasDefinedMainType()) {
391 module
->getLastMainType().addComment(comment
);
395 void XMLParser::characterdataHandler(const xmlChar
* text
, const int length
) {
400 char * temp
= (char *) Malloc(length
+ 1);
401 memcpy(temp
, text
, length
);
403 Mstring
comment(temp
);
406 comment
.removeWSfromBegin();
407 comment
.removeWSfromEnd();
408 if (comment
.empty()) {
412 if (module
->getActualXsdConstruct() == c_schema
) {
413 module
->addMainType(c_annotation
);
415 if (module
->hasDefinedMainType()) {
416 module
->getLastMainType().addComment(comment
);
420 void XMLParser::fillUpActualTagName(const char * localname
, const tagMode mode
) {
421 Mstring
name_s(localname
);
424 actualTagName
= n_all
;
425 else if (name_s
== "annotation")
426 actualTagName
= n_annotation
;
427 else if (name_s
== "any")
428 actualTagName
= n_any
;
429 else if (name_s
== "anyAttribute")
430 actualTagName
= n_anyAttribute
;
431 else if (name_s
== "appinfo") {
432 actualTagName
= n_appinfo
;
443 } else if (name_s
== "attribute")
444 actualTagName
= n_attribute
;
445 else if (name_s
== "attributeGroup")
446 actualTagName
= n_attributeGroup
;
447 else if (name_s
== "choice")
448 actualTagName
= n_choice
;
449 else if (name_s
== "complexContent")
450 actualTagName
= n_complexContent
;
451 else if (name_s
== "complexType")
452 actualTagName
= n_complexType
;
453 else if (name_s
== "definition")
454 actualTagName
= n_definition
;
455 else if (name_s
== "documentation")
456 actualTagName
= n_documentation
;
457 else if (name_s
== "element")
458 actualTagName
= n_element
;
459 else if (name_s
== "enumeration")
460 actualTagName
= n_enumeration
;
461 else if (name_s
== "extension")
462 actualTagName
= n_extension
;
463 else if (name_s
== "field") {
464 actualTagName
= n_field
;
465 if (mode
== startElement
) {
466 printWarning(filename
, xmlSAX2GetLineNumber(context
),
467 Mstring("The 'field' tag is ignored by the standard."));
470 } else if (name_s
== "fractionDigits") {
471 actualTagName
= n_fractionDigits
;
472 if (mode
== startElement
) {
473 printWarning(filename
, xmlSAX2GetLineNumber(context
),
474 Mstring("The 'fractionDigits' tag is currently not supported."));
477 } else if (name_s
== "group")
478 actualTagName
= n_group
;
479 else if (name_s
== "import")
480 actualTagName
= n_import
;
481 else if (name_s
== "include")
482 actualTagName
= n_include
;
483 else if (name_s
== "key") {
484 actualTagName
= n_key
;
485 if (mode
== startElement
) {
486 printWarning(filename
, xmlSAX2GetLineNumber(context
),
487 Mstring("The 'key' tag is ignored by the standard."));
490 } else if (name_s
== "keyref") {
491 actualTagName
= n_keyref
;
492 if (mode
== startElement
) {
493 printWarning(filename
, xmlSAX2GetLineNumber(context
),
494 Mstring("The 'keyref' tag ignored by the standard."));
497 } else if (name_s
== "length")
498 actualTagName
= n_length
;
499 else if (name_s
== "label")
500 actualTagName
= n_label
;
501 else if (name_s
== "list")
502 actualTagName
= n_list
;
503 else if (name_s
== "maxExclusive")
504 actualTagName
= n_maxExclusive
;
505 else if (name_s
== "maxInclusive")
506 actualTagName
= n_maxInclusive
;
507 else if (name_s
== "maxLength")
508 actualTagName
= n_maxLength
;
509 else if (name_s
== "minExclusive")
510 actualTagName
= n_minExclusive
;
511 else if (name_s
== "minInclusive")
512 actualTagName
= n_minInclusive
;
513 else if (name_s
== "minLength")
514 actualTagName
= n_minLength
;
515 else if (name_s
== "notation")
517 else if (name_s
== "pattern")
518 actualTagName
= n_pattern
;
519 else if (name_s
== "redefine")
520 actualTagName
= n_redefine
;
521 else if (name_s
== "restriction")
522 actualTagName
= n_restriction
;
523 else if (name_s
== "schema")
524 actualTagName
= n_schema
;
525 else if (name_s
== "selector") {
526 actualTagName
= n_selector
;
527 if (mode
== startElement
) {
528 printWarning(filename
, xmlSAX2GetLineNumber(context
),
529 Mstring("The 'selector' tag ignored by the standard."));
532 } else if (name_s
== "sequence")
533 actualTagName
= n_sequence
;
534 else if (name_s
== "simpleContent")
535 actualTagName
= n_simpleContent
;
536 else if (name_s
== "simpleType")
537 actualTagName
= n_simpleType
;
538 else if (name_s
== "totalDigits")
539 actualTagName
= n_totalDigits
;
540 else if (name_s
== "union")
541 actualTagName
= n_union
;
542 else if (name_s
== "unique") {
543 actualTagName
= n_unique
;
544 if (mode
== startElement
) {
545 printWarning(filename
, xmlSAX2GetLineNumber(context
),
546 Mstring("The 'unique' tag ignored by the standard."));
549 } else if (name_s
== "whiteSpace")
550 actualTagName
= n_whiteSpace
;
553 void XMLParser::fillUpActualTagAttributes(const char ** attributes
, const int att_count
) {
555 struct attribute_data
{
559 const char * value_start
;
560 const char * value_end
;
562 attribute_data
* ad
= (attribute_data
*) attributes
;
564 Mstring
* att_name_s
= new Mstring
[att_count
];
565 Mstring
* att_value_s
= new Mstring
[att_count
];
566 TagAttributeName
* att_name_e
= new TagAttributeName
[att_count
];
568 for (int i
= 0; i
!= att_count
; ++i
) {
569 att_name_s
[i
] = ad
[i
].name
;
570 att_value_s
[i
] = Mstring(ad
[i
].value_end
- ad
[i
].value_start
, ad
[i
].value_start
);
572 att_name_e
[i
] = a_NOTSET
;
573 if (att_name_s
[i
] == "abstract") {
574 att_name_e
[i
] = a_abstract
;
575 } else if (att_name_s
[i
] == "attributeFormDefault")
576 att_name_e
[i
] = a_attributeFormDefault
;
577 else if (att_name_s
[i
] == "base")
578 att_name_e
[i
] = a_base
;
579 else if (att_name_s
[i
] == "block") {
580 att_name_e
[i
] = a_block
;
581 } else if (att_name_s
[i
] == "blockDefault"){
582 att_name_e
[i
] = a_blockDefault
;
583 } else if (att_name_s
[i
] == "default")
584 att_name_e
[i
] = a_default
;
585 else if (att_name_s
[i
] == "elementFormDefault")
586 att_name_e
[i
] = a_elementFormDefault
;
587 else if (att_name_s
[i
] == "final") {
588 att_name_e
[i
] = a_final
; // no effect on the output
589 } else if (att_name_s
[i
] == "finalDefault")
591 else if (att_name_s
[i
] == "fixed")
592 att_name_e
[i
] = a_fixed
;
593 else if (att_name_s
[i
] == "form")
594 att_name_e
[i
] = a_form
;
595 else if (att_name_s
[i
] == "id")
596 att_name_e
[i
] = a_id
;
597 else if (att_name_s
[i
] == "itemType")
598 att_name_e
[i
] = a_itemType
;
599 else if (att_name_s
[i
] == "lang")
601 else if (att_name_s
[i
] == "maxOccurs")
602 att_name_e
[i
] = a_maxOccurs
;
603 else if (att_name_s
[i
] == "memberTypes")
604 att_name_e
[i
] = a_memberTypes
;
605 else if (att_name_s
[i
] == "minOccurs")
606 att_name_e
[i
] = a_minOccurs
;
607 else if (att_name_s
[i
] == "mixed")
608 att_name_e
[i
] = a_mixed
;
609 else if (att_name_s
[i
] == "name")
610 att_name_e
[i
] = a_name
;
611 else if (att_name_s
[i
] == "namespace")
612 att_name_e
[i
] = a_namespace
;
613 else if (att_name_s
[i
] == "nillable")
614 att_name_e
[i
] = a_nillable
;
615 else if (att_name_s
[i
] == "processContents") {
616 att_name_e
[i
] = a_processContents
;
618 } else if (att_name_s
[i
] == "ref")
619 att_name_e
[i
] = a_ref
;
620 else if (att_name_s
[i
] == "schemaLocation")
621 att_name_e
[i
] = a_schemaLocation
;
622 else if (att_name_s
[i
] == "substitutionGroup") {
623 att_name_e
[i
] = a_substitutionGroup
;
624 } else if (att_name_s
[i
] == "targetNamespace")
625 att_name_e
[i
] = a_targetNamespace
;
626 else if (att_name_s
[i
] == "type")
627 att_name_e
[i
] = a_type
;
628 else if (att_name_s
[i
] == "use")
629 att_name_e
[i
] = a_use
;
630 else if (att_name_s
[i
] == "value")
631 att_name_e
[i
] = a_value
;
632 else if (att_name_s
[i
] == "version") {
635 actualTagAttributes
.fillUp(att_name_e
, att_value_s
, att_count
);
636 delete [] att_name_s
;
637 delete [] att_value_s
;
638 delete [] att_name_e
;
641 XMLParser::TagAttributes::TagAttributes(XMLParser
* withThisParser
)
642 : parser(withThisParser
)
643 , attributeFormDefault(notset
)
646 , elementFormDefault(notset
)
667 void XMLParser::TagAttributes::fillUp(TagAttributeName
* att_name_e
, Mstring
* att_value_s
, const int att_count
) {
672 attributeFormDefault
= notset
;
675 blockDefault
= not_set
,
677 elementFormDefault
= notset
;
690 schemaLocation
.clear();
692 substitionGroup
= empty_string
;
693 targetNamespace
.clear();
700 for (int i
= 0; i
!= att_count
; ++i
) {
701 switch (att_name_e
[i
]) {
702 case a_abstract
: // Not supported by now
703 if (att_value_s
[i
] == "true") {
705 } else if (att_value_s
[i
] == "false") {
708 case a_attributeFormDefault
: // qualified | unqualified
709 if (att_value_s
[i
] == "qualified") {
710 attributeFormDefault
= qualified
;
711 } else if (att_value_s
[i
] == "unqualified") {
712 attributeFormDefault
= unqualified
;
715 case a_base
: // QName = anyURI + NCName
716 base
= att_value_s
[i
];
718 case a_block
: // Not supported by now
719 if(att_value_s
[i
] == "#all"){
721 }else if(att_value_s
[i
] == "substitution"){
722 block
= substitution
;
723 }else if(att_value_s
[i
] == "restriction"){
725 }else if(att_value_s
[i
] == "extension"){
729 case a_blockDefault
: // Not supported by now
730 if(att_value_s
[i
] == "#all"){
732 }else if(att_value_s
[i
] == "substitution"){
733 blockDefault
= substitution
;
734 }else if(att_value_s
[i
] == "restriction"){
735 blockDefault
= restriction
;
736 }else if(att_value_s
[i
] == "extension"){
737 blockDefault
= extension
;
740 case a_default
: // string
741 default_
= att_value_s
[i
];
743 case a_elementFormDefault
:
744 if (att_value_s
[i
] == "qualified") {
745 elementFormDefault
= qualified
;
746 } else if (att_value_s
[i
] == "unqualified") {
747 elementFormDefault
= unqualified
;
750 case a_final
: // Not supported by now
752 case a_finalDefault
: // Not supported by now
754 case a_fixed
: // string
755 fixed
= att_value_s
[i
];
757 case a_form
: // qualified | unqualified
758 if (att_value_s
[i
] == "qualified") {
760 } else if (att_value_s
[i
] == "unqualified") {
766 case a_id
: // ID = NCName
769 case a_itemType
: // QName = anyURI + NCName /- used in 'list' tag only
770 itemType
= att_value_s
[i
];
772 case a_maxOccurs
: // nonNegativeinteger or 'unbounded'
773 if (att_value_s
[i
] == "unbounded") {
774 maxOccurs
= ULLONG_MAX
;
776 maxOccurs
= strtoull(att_value_s
[i
].c_str(), NULL
, 0);
779 case a_memberTypes
: // list of QNames - used in 'union' tag only
780 memberTypes
= att_value_s
[i
];
782 case a_minOccurs
: // nonNegativeInteger
783 minOccurs
= strtoull(att_value_s
[i
].c_str(), NULL
, 0);
785 case a_mixed
: // true | false
786 if (att_value_s
[i
] == "true") {
788 } else if (att_value_s
[i
] == "false") {
792 case a_name
: // NCName
793 name
= att_value_s
[i
];
795 case a_namespace
: // anyURI
796 namespace_
= att_value_s
[i
];
798 case a_nillable
: // true | false
799 if (att_value_s
[i
] == "true") {
801 } else if (att_value_s
[i
] == "false") {
805 case a_processContents
: // Not supported by now
807 case a_ref
: // QName = anyURI + NCName
808 ref
= att_value_s
[i
];
810 case a_schemaLocation
: // anyURI
811 schemaLocation
= att_value_s
[i
];
813 case a_substitutionGroup
:
814 substitionGroup
= att_value_s
[i
];
816 case a_targetNamespace
: // anyURI
817 targetNamespace
= att_value_s
[i
];
819 case a_type
: // QName = anyURI + NCName
820 type
= att_value_s
[i
];
822 case a_use
: // optional | prohibited | required - used in 'use' tag only
823 if (att_value_s
[i
] == "optional") {
825 } else if (att_value_s
[i
] == "prohibited") {
827 } else if (att_value_s
[i
] == "required") {
831 case a_value
: // value of FACETS
832 value
= att_value_s
[i
];
836 case a_version
: // Not supported by now
841 fprintf(stderr
, "Unknown TagAttributeName %d\n", att_name_e
[i
]);