1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 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;
39 XMLParser::XMLParser(const char * a_filename
)
40 : module(NULL
) // get value with 'connectWithModule()' method
41 , filename(a_filename
) // includes the path of the file
44 , parserCheckingXML(NULL
)
45 , contextCheckingXML(NULL
)
46 , contextCheckingXSD(NULL
)
48 , actualTagName(n_NOTSET
)
49 , actualTagAttributes(this)
52 xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader
);
54 parserCheckingXML
= (xmlSAXHandler
*)malloc(sizeof(xmlSAXHandler
));
55 memset(parserCheckingXML
, 0, sizeof(xmlSAXHandler
));
56 parserCheckingXML
->initialized
= XML_SAX2_MAGIC
;
57 parserCheckingXML
->warning
= warningHandler
;
58 parserCheckingXML
->error
= errorHandler
;
59 contextCheckingXML
= xmlCreateFileParserCtxt(a_filename
);
60 if (!contextCheckingXML
) {
63 "Creating XML syntax checker has failed.\n");
67 contextCheckingXML
->sax
= parserCheckingXML
;
71 contextCheckingXSD
= xmlSchemaNewParserCtxt(a_filename
);
72 if (!contextCheckingXSD
) {
75 "Creating XSD validator has failed.\n");
79 xmlSchemaSetParserErrors(contextCheckingXSD
, errorHandler
, warningHandler
, 0);
82 parser
= (xmlSAXHandler
*)malloc(sizeof(xmlSAXHandler
));
83 memset(parser
, 0, sizeof(xmlSAXHandler
));
84 parser
->initialized
= XML_SAX2_MAGIC
;
85 parser
->startElementNs
= (startElementNsSAX2Func
)wrapper_to_call_startelement_h
;
86 parser
->endElementNs
= (endElementNsSAX2Func
)wrapper_to_call_endelement_h
;
87 parser
->characters
= (charactersSAXFunc
)wrapper_to_call_characterdata_h
;
88 parser
->comment
= (commentSAXFunc
)wrapper_to_call_comment_h
;
90 context
= xmlCreateFileParserCtxt(filename
.c_str());
94 "Creating parser for file '%s' has failed.\n", filename
.c_str());
98 context
->sax
= parser
;
99 context
->userData
= this;
102 XMLParser::~XMLParser()
105 contextCheckingXML
->sax
= NULL
;
107 free(parserCheckingXML
);
108 if (context
) xmlFreeParserCtxt(context
);
109 if (contextCheckingXML
) xmlFreeParserCtxt(contextCheckingXML
);
110 if (contextCheckingXSD
) xmlSchemaFreeParserCtxt(contextCheckingXSD
);
113 void XMLParser::checkSyntax()
115 xmlParseDocument(contextCheckingXML
);
118 void XMLParser::validate()
121 xmlSchemaPtr schema
= xmlSchemaParse(contextCheckingXSD
);
123 xmlSchemaValidCtxtPtr validator
= xmlSchemaNewValidCtxt(schema
);
125 // do not use this->context!
126 xmlParserCtxtPtr newcontext
= xmlNewParserCtxt();
127 xmlDocPtr doc
= xmlCtxtReadFile(newcontext
, filename
.c_str(), NULL
, 0);
129 // Don't try this, it always fails
130 //int result = xmlSchemaValidateDoc(validator, doc);
131 //(void)result; // 0=ok, errorcode > 0, intrnal error == -1
134 xmlSchemaFreeValidCtxt(validator
);
136 xmlSchemaFree(schema
);
141 void XMLParser::startConversion(TTCN3Module
* a_module
)
144 xmlParseDocument(context
);
147 void XMLParser::wrapper_to_call_startelement_h(XMLParser
*self
, const xmlChar
* localname
, const xmlChar
*, const xmlChar
*,
148 int nb_namespaces
, const xmlChar
** namespaces
, 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
*)
155 self
->endelementHandler(localname
);
158 void XMLParser::wrapper_to_call_comment_h(XMLParser
*self
, const xmlChar
* value
)
160 self
->commentHandler(value
);
163 void XMLParser::wrapper_to_call_characterdata_h(XMLParser
*self
, const xmlChar
* ch
, int len
)
165 self
->characterdataHandler(ch
, len
);
168 void XMLParser::warningHandler(void *, const char *, ...)
170 if (w_flag_used
) return;
172 xmlErrorPtr error
= xmlGetLastError();
174 if (error
->file
== NULL
)
190 void XMLParser::errorHandler(void *, const char *, ...)
192 xmlErrorPtr error
= xmlGetLastError();
194 if (error
->code
== XML_SCHEMAP_SRC_RESOLVE
) return;
195 if (error
->code
== XML_SCHEMAP_COS_ALL_LIMITED
) return;
197 switch (error
->level
) {
199 fputs("ERROR:\n", stderr
);
202 fputs("FATAL ERROR:\n", stderr
);
204 default: // warning or no error, can't happen (famous last words)
208 if (error
->file
!= NULL
) {
209 fprintf(stderr
, "%s (in line %d): ", error
->file
, error
->line
);
212 fputs(error
->message
, stderr
); // libxml2 supplies a trailing \n
216 void XMLParser::startelementHandler(const xmlChar
* localname
,
217 int nb_namespaces
, const xmlChar
** namespaces
, int nb_attributes
, const xmlChar
** attributes
)
219 fillUpActualTagName((const char *)localname
, startElement
);
220 fillUpActualTagAttributes((const char **)attributes
, nb_attributes
);
222 switch (module
->getActualXsdConstruct())
225 switch (actualTagName
)
228 module
->setActualXsdConstruct(c_schema
);
230 module
->loadValuesFromXMLDeclaration((const char *)context
->version
,
231 (const char *)context
->encoding
, context
->standalone
);
233 List
<NamespaceType
> declaredNamespaces
;
234 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
];
240 // else leave it as empty string
242 if (namespaces
[i
+1] != NULL
)
243 tmp_ns_pair
.uri
= (const char*)namespaces
[i
+1];
244 // else leave it as empty string
246 declaredNamespaces
.push_back(tmp_ns_pair
);
249 module
->loadValuesFromSchemaTag(actualTagAttributes
.targetNamespace
, declaredNamespaces
,
250 actualTagAttributes
.elementFormDefault
, actualTagAttributes
.attributeFormDefault
);
258 switch (actualTagName
)
261 module
->addMainType(c_simpleType
);
264 module
->addMainType(c_element
);
267 module
->addMainType(c_attribute
);
270 module
->addMainType(c_complexType
);
273 module
->addMainType(c_group
);
275 case n_attributeGroup
:
276 module
->addMainType(c_attributeGroup
);
279 module
->addMainType(c_include
);
282 module
->addMainType(c_import
);
285 module
->addMainType(c_annotation
);
293 if (module
->hasDefinedMainType()) module
->getLastMainType().loadWithValues();
298 parentTagNames
.push_back(actualTagName
);
301 void XMLParser::endelementHandler(const xmlChar
* localname
)
303 fillUpActualTagName((const char *)localname
, endElement
);
305 parentTagNames
.pop_back();
308 if (actualDepth
== 0) module
->setActualXsdConstruct(c_schema
);
309 if (actualDepth
== 1) module
->setActualXsdConstruct(c_schema
);
311 if (module
->hasDefinedMainType()) module
->getLastMainType().modifyValues();
315 void XMLParser::commentHandler(const xmlChar
* text
)
317 Mstring
comment((const char *)text
);
318 comment
.removeWSfromBegin();
319 comment
.removeWSfromEnd();
320 if (comment
.empty()) return;
322 if (module
->getActualXsdConstruct() == c_schema
) {
323 module
->addMainType(c_annotation
);
324 module
->setActualXsdConstruct(c_schema
); // actualXsdConstruct was set to c_annotation
327 if (module
->hasDefinedMainType()) module
->getLastMainType().addComment(comment
);
330 void XMLParser::characterdataHandler(const xmlChar
* text
, int length
)
332 if (suspended
) return;
334 char * temp
= (char *)Malloc(length
+ 1);
335 memcpy(temp
, text
, length
);
337 Mstring
comment(temp
);
340 comment
.removeWSfromBegin();
341 comment
.removeWSfromEnd();
342 if (comment
.empty()) return;
344 if (module
->getActualXsdConstruct() == c_schema
) {
345 module
->addMainType(c_annotation
);
347 if (module
->hasDefinedMainType()) module
->getLastMainType().addComment(comment
);
350 void XMLParser::fillUpActualTagName(const char * localname
, tagMode mode
)
352 Mstring
name_s(localname
);
355 actualTagName
= n_all
;
356 else if (name_s
== "annotation")
357 actualTagName
= n_annotation
;
358 else if (name_s
== "any")
359 actualTagName
= n_any
;
360 else if (name_s
== "anyAttribute")
361 actualTagName
= n_anyAttribute
;
362 else if (name_s
== "appinfo") {
363 actualTagName
= n_appinfo
;
374 else if (name_s
== "attribute")
375 actualTagName
= n_attribute
;
376 else if (name_s
== "attributeGroup")
377 actualTagName
= n_attributeGroup
;
378 else if (name_s
== "choice")
379 actualTagName
= n_choice
;
380 else if (name_s
== "complexContent")
381 actualTagName
= n_complexContent
;
382 else if (name_s
== "complexType")
383 actualTagName
= n_complexType
;
384 else if (name_s
== "definition")
385 actualTagName
= n_definition
;
386 else if (name_s
== "documentation")
387 actualTagName
= n_documentation
;
388 else if (name_s
== "element")
389 actualTagName
= n_element
;
390 else if (name_s
== "enumeration")
391 actualTagName
= n_enumeration
;
392 else if (name_s
== "extension")
393 actualTagName
= n_extension
;
394 else if (name_s
== "field") {
395 actualTagName
= n_field
;
396 if (mode
== startElement
) {
397 printWarning(filename
, xmlSAX2GetLineNumber(context
),
398 Mstring("The 'field' tag is ignored by the standard."));
402 else if (name_s
== "fractionDigits") {
403 actualTagName
= n_fractionDigits
;
406 else if (name_s
== "group")
407 actualTagName
= n_group
;
408 else if (name_s
== "import")
409 actualTagName
= n_import
;
410 else if (name_s
== "include")
411 actualTagName
= n_include
;
412 else if (name_s
== "key") {
413 actualTagName
= n_key
;
414 if (mode
== startElement
) {
415 printWarning(filename
, xmlSAX2GetLineNumber(context
),
416 Mstring("The 'key' tag is ignored by the standard."));
420 else if (name_s
== "keyref") {
421 actualTagName
= n_keyref
;
422 if (mode
== startElement
) {
423 printWarning(filename
, xmlSAX2GetLineNumber(context
),
424 Mstring("The 'keyref' tag ignored by the standard."));
428 else if (name_s
== "length")
429 actualTagName
= n_length
;
430 else if (name_s
== "label")
431 actualTagName
= n_label
;
432 else if (name_s
== "list")
433 actualTagName
= n_list
;
434 else if (name_s
== "maxExclusive")
435 actualTagName
= n_maxExclusive
;
436 else if (name_s
== "maxInclusive")
437 actualTagName
= n_maxInclusive
;
438 else if (name_s
== "maxLength")
439 actualTagName
= n_maxLength
;
440 else if (name_s
== "minExclusive")
441 actualTagName
= n_minExclusive
;
442 else if (name_s
== "minInclusive")
443 actualTagName
= n_minInclusive
;
444 else if (name_s
== "minLength")
445 actualTagName
= n_minLength
;
446 else if (name_s
== "notation")
448 else if (name_s
== "pattern")
449 actualTagName
= n_pattern
;
450 else if (name_s
== "redefine")
451 actualTagName
= n_redefine
;
452 else if (name_s
== "restriction")
453 actualTagName
= n_restriction
;
454 else if (name_s
== "schema")
455 actualTagName
= n_schema
;
456 else if (name_s
== "selector") {
457 actualTagName
= n_selector
;
458 if (mode
== startElement
) {
459 printWarning(filename
, xmlSAX2GetLineNumber(context
),
460 Mstring("The 'selector' tag ignored by the standard."));
464 else if (name_s
== "sequence")
465 actualTagName
= n_sequence
;
466 else if (name_s
== "simpleContent")
467 actualTagName
= n_simpleContent
;
468 else if (name_s
== "simpleType")
469 actualTagName
= n_simpleType
;
470 else if (name_s
== "totalDigits")
471 actualTagName
= n_totalDigits
;
472 else if (name_s
== "union")
473 actualTagName
= n_union
;
474 else if (name_s
== "unique") {
475 actualTagName
= n_unique
;
476 if (mode
== startElement
) {
477 printWarning(filename
, xmlSAX2GetLineNumber(context
),
478 Mstring("The 'unique' tag ignored by the standard."));
482 else if (name_s
== "whiteSpace")
483 actualTagName
= n_whiteSpace
;
486 void XMLParser::fillUpActualTagAttributes(const char ** attributes
, int att_count
)
488 struct attribute_data
{
492 const char * value_start
;
493 const char * value_end
;
495 attribute_data
* ad
= (attribute_data
*)attributes
;
497 Mstring
* att_name_s
= new Mstring
[att_count
];
498 Mstring
* att_value_s
= new Mstring
[att_count
];
499 TagAttributeName
* att_name_e
= new TagAttributeName
[att_count
];
501 for (int i
= 0; i
!= att_count
; ++i
) {
502 att_name_s
[i
] = ad
[i
].name
;
503 att_value_s
[i
] = Mstring(ad
[i
].value_end
- ad
[i
].value_start
, ad
[i
].value_start
);
505 att_name_e
[i
] = a_NOTSET
;
506 if (att_name_s
[i
] == "abstract") {
507 att_name_e
[i
] = a_abstract
;
508 printWarning(filename
, xmlSAX2GetLineNumber(context
),
509 Mstring("The 'abstract' attribute is currently not supported."));
512 else if (att_name_s
[i
] == "attributeFormDefault")
513 att_name_e
[i
] = a_attributeFormDefault
;
514 else if (att_name_s
[i
] == "base")
515 att_name_e
[i
] = a_base
;
516 else if (att_name_s
[i
] == "block") {
517 att_name_e
[i
] = a_block
;
518 printWarning(filename
, xmlSAX2GetLineNumber(context
),
519 Mstring("The 'block' attribute is currently not supported."));
522 else if (att_name_s
[i
] == "blockDefault")
524 else if (att_name_s
[i
] == "default")
525 att_name_e
[i
] = a_default
;
526 else if (att_name_s
[i
] == "elementFormDefault")
527 att_name_e
[i
] = a_elementFormDefault
;
528 else if (att_name_s
[i
] == "final") {
529 att_name_e
[i
] = a_final
; // no effect on the output
531 else if (att_name_s
[i
] == "finalDefault")
533 else if (att_name_s
[i
] == "fixed")
534 att_name_e
[i
] = a_fixed
;
535 else if (att_name_s
[i
] == "form")
536 att_name_e
[i
] = a_form
;
537 else if (att_name_s
[i
] == "id")
538 att_name_e
[i
] = a_id
;
539 else if (att_name_s
[i
] == "itemType")
540 att_name_e
[i
] = a_itemType
;
541 else if (att_name_s
[i
] == "lang")
543 else if (att_name_s
[i
] == "maxOccurs")
544 att_name_e
[i
] = a_maxOccurs
;
545 else if (att_name_s
[i
] == "memberTypes")
546 att_name_e
[i
] = a_memberTypes
;
547 else if (att_name_s
[i
] == "minOccurs")
548 att_name_e
[i
] = a_minOccurs
;
549 else if (att_name_s
[i
] == "mixed")
550 att_name_e
[i
] = a_mixed
;
551 else if (att_name_s
[i
] == "name")
552 att_name_e
[i
] = a_name
;
553 else if (att_name_s
[i
] == "namespace")
554 att_name_e
[i
] = a_namespace
;
555 else if (att_name_s
[i
] == "nillable")
556 att_name_e
[i
] = a_nillable
;
557 else if (att_name_s
[i
] == "processContents") {
558 att_name_e
[i
] = a_processContents
;
561 else if (att_name_s
[i
] == "ref")
562 att_name_e
[i
] = a_ref
;
563 else if (att_name_s
[i
] == "schemaLocation")
564 att_name_e
[i
] = a_schemaLocation
;
565 else if (att_name_s
[i
] == "substitutionGroup") {
566 att_name_e
[i
] = a_substitutionGroup
;
567 printWarning(filename
, xmlSAX2GetLineNumber(context
),
568 Mstring("The 'substitutionGroup' attribute is currently not supported."));
571 else if (att_name_s
[i
] == "targetNamespace")
572 att_name_e
[i
] = a_targetNamespace
;
573 else if (att_name_s
[i
] == "type")
574 att_name_e
[i
] = a_type
;
575 else if (att_name_s
[i
] == "use")
576 att_name_e
[i
] = a_use
;
577 else if (att_name_s
[i
] == "value")
578 att_name_e
[i
] = a_value
;
579 else if (att_name_s
[i
] == "version")
582 actualTagAttributes
.fillUp(att_name_e
, att_value_s
, att_count
);
583 delete [] att_name_s
;
584 delete [] att_value_s
;
585 delete [] att_name_e
;
588 XMLParser::TagAttributes::TagAttributes(XMLParser
* withThisParser
)
589 : parser(withThisParser
)
590 , attributeFormDefault(notset
)
593 , elementFormDefault(notset
)
614 void XMLParser::TagAttributes::fillUp(TagAttributeName
* att_name_e
, Mstring
* att_value_s
, int att_count
)
619 attributeFormDefault
= notset
;
622 elementFormDefault
= notset
;
635 schemaLocation
.clear();
637 targetNamespace
.clear();
644 for (int i
= 0; i
!= att_count
; ++i
) {
645 switch (att_name_e
[i
])
647 case a_abstract
: // Not supported by now
649 case a_attributeFormDefault
: // qualified | unqualified
650 if (att_value_s
[i
] == "qualified")
651 attributeFormDefault
= qualified
;
652 else if (att_value_s
[i
] == "unqualified")
653 attributeFormDefault
= unqualified
;
655 case a_base
: // QName = anyURI + NCName
656 base
= att_value_s
[i
];
658 case a_block
: // Not supported by now
660 case a_blockDefault
: // Not supported by now
662 case a_default
: // string
663 default_
= att_value_s
[i
];
665 case a_elementFormDefault
:
666 if (att_value_s
[i
] == "qualified")
667 elementFormDefault
= qualified
;
668 else if (att_value_s
[i
] == "unqualified")
669 elementFormDefault
= unqualified
;
671 case a_final
: // Not supported by now
673 case a_finalDefault
: // Not supported by now
675 case a_fixed
: // string
676 fixed
= att_value_s
[i
];
678 case a_form
: // qualified | unqualified
679 if (att_value_s
[i
] == "qualified")
681 else if (att_value_s
[i
] == "unqualified")
686 case a_id
: // ID = NCName
689 case a_itemType
: // QName = anyURI + NCName /- used in 'list' tag only
690 itemType
= att_value_s
[i
];
692 case a_maxOccurs
: // nonNegativeinteger or 'unbounded'
693 if (att_value_s
[i
] == "unbounded")
694 maxOccurs
= ULLONG_MAX
;
696 maxOccurs
= strtoull(att_value_s
[i
].c_str(), NULL
, 0);
698 case a_memberTypes
: // list of QNames - used in 'union' tag only
699 memberTypes
= att_value_s
[i
];
701 case a_minOccurs
: // nonNegativeInteger
702 minOccurs
= strtoull(att_value_s
[i
].c_str(), NULL
, 0);
704 case a_mixed
: // true | false
705 if (att_value_s
[i
] == "true")
707 else if (att_value_s
[i
] == "false")
710 case a_name
: // NCName
711 name
= att_value_s
[i
];
713 case a_namespace
: // anyURI
714 namespace_
= att_value_s
[i
];
716 case a_nillable
: // true | false
717 if (att_value_s
[i
] == "true")
719 else if (att_value_s
[i
] == "false")
722 case a_processContents
: // Not supported by now
724 case a_ref
: // QName = anyURI + NCName
725 ref
= att_value_s
[i
];
727 case a_schemaLocation
: // anyURI
728 schemaLocation
= att_value_s
[i
];
730 case a_substitutionGroup
: // Not supported by now
732 case a_targetNamespace
: // anyURI
733 targetNamespace
= att_value_s
[i
];
735 case a_type
: // QName = anyURI + NCName
736 type
= att_value_s
[i
];
738 case a_use
: // optional | prohibited | required - used in 'use' tag only
739 if (att_value_s
[i
] == "optional")
741 else if (att_value_s
[i
] == "prohibited")
743 else if (att_value_s
[i
] == "required")
746 case a_value
: // value of FACETS
747 value
= att_value_s
[i
];
751 case a_version
: // Not supported by now
756 fprintf(stderr
, "Unknown TagAttributeName %d\n", att_name_e
[i
]);