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 "SimpleType.hh"
10 #include "GeneralFunctions.hh"
12 #include "TTCN3ModuleInventory.hh"
13 #include "TTCN3Module.hh"
14 #include "ComplexType.hh"
16 extern bool g_flag_used
;
18 SimpleType::SimpleType(XMLParser
* a_parser
, TTCN3Module
* a_module
, ConstructType a_construct
)
19 : RootType(a_parser
, a_module
, a_construct
)
26 , element_form_as(notset
)
27 , attribute_form_as(notset
)
34 , substitionGroup(empty_string
)
40 SimpleType::SimpleType(const SimpleType
& other
)
42 , builtInBase(other
.builtInBase
)
43 , length(other
.length
)
44 , pattern(other
.pattern
)
45 , enumeration(other
.enumeration
)
46 , whitespace(other
.whitespace
)
48 , element_form_as(other
.element_form_as
)
49 , attribute_form_as(other
.attribute_form_as
)
51 , outside_reference(other
.outside_reference
)
52 , in_name_only(other
.in_name_only
)
53 , fromRef(other
.fromRef
)
54 , xsdtype(other
.xsdtype
)
55 , isOptional(other
.isOptional
)
56 , substitionGroup(other
.substitionGroup
)
57 , subsGroup(other
.subsGroup
)
61 pattern
.parent
= this;
62 enumeration
.parent
= this;
63 whitespace
.p_parent
= this;
67 void SimpleType::loadWithValues() {
68 const XMLParser::TagAttributes
& atts
= parser
->getActualTagAttributes();
69 switch (parser
->getActualTagName()) {
71 type
.upload(atts
.base
);
72 setReference(atts
.base
);
73 mode
= restrictionMode
;
76 type
.upload(atts
.itemType
);
77 setReference(atts
.itemType
);
79 maxOccurs
= ULLONG_MAX
;
84 { // generating complextype from simpletype
85 ComplexType
* new_complextype
= new ComplexType(*this, ComplexType::fromTagUnion
);
86 new_complextype
->loadWithValues();
90 name
.upload(atts
.name
);
91 type
.upload(atts
.type
);
92 setReference(atts
.type
, true);
94 applyDefaultAttribute(atts
.default_
);
95 applyFixedAttribute(atts
.fixed
);
97 applyAbstractAttribute(atts
.abstract
);
98 applySubstitionGroupAttribute(atts
.substitionGroup
);
99 applyBlockAttribute(atts
.block
);
100 //This shall be the last instruction always
101 applyNillableAttribute(atts
.nillable
);
104 name
.upload(atts
.name
);
105 type
.upload(atts
.type
);
106 xsdtype
= n_attribute
;
107 setReference(atts
.type
, true);
108 applyDefaultAttribute(atts
.default_
);
109 applyFixedAttribute(atts
.fixed
);
112 name
.upload(atts
.name
);
115 { // generating complextype from simpletype
116 ComplexType
* new_complextype
= new ComplexType(*this, ComplexType::fromTagComplexType
);
117 new_complextype
->loadWithValues();
121 if (mode
== listMode
) {
122 minOccurs
= strtoull(atts
.value
.c_str(), NULL
, 0);
123 maxOccurs
= strtoull(atts
.value
.c_str(), NULL
, 0);
126 length
.facet_minLength
= strtoull(atts
.value
.c_str(), NULL
, 0);
127 length
.facet_maxLength
= strtoull(atts
.value
.c_str(), NULL
, 0);
128 length
.modified
= true;
131 if (mode
== listMode
) {
132 minOccurs
= strtoull(atts
.value
.c_str(), NULL
, 0);
135 length
.facet_minLength
= strtoull(atts
.value
.c_str(), NULL
, 0);
136 length
.modified
= true;
139 if (mode
== listMode
) {
140 maxOccurs
= strtoull(atts
.value
.c_str(), NULL
, 0);
143 length
.facet_maxLength
= strtoull(atts
.value
.c_str(), NULL
, 0);
144 length
.modified
= true;
147 pattern
.facet
= atts
.value
;
148 pattern
.modified
= true;
151 enumeration
.facets
.push_back(atts
.value
);
152 enumeration
.modified
= true;
155 whitespace
.facet
= atts
.value
;
156 whitespace
.modified
= true;
159 if (atts
.value
== "NaN") {
160 value
.not_a_number
= true;
161 } else if (atts
.value
== "-INF") {
162 value
.facet_minInclusive
= -DBL_MAX
;
163 } else if (atts
.value
== "INF") {
164 value
.facet_minInclusive
= DBL_MAX
;
166 value
.facet_minInclusive
= stringToLongDouble(atts
.value
.c_str());
168 value
.modified
= true;
171 if (atts
.value
== "NaN") {
172 value
.not_a_number
= true;
173 } else if (atts
.value
== "-INF") {
174 value
.facet_maxInclusive
= -DBL_MAX
;
175 } else if (atts
.value
== "INF") {
176 value
.facet_maxInclusive
= DBL_MAX
;
178 value
.facet_maxInclusive
= stringToLongDouble(atts
.value
.c_str());
180 value
.modified
= true;
183 if (atts
.value
== "NaN") {
185 } else if (atts
.value
== "-INF") {
186 value
.facet_minExclusive
= -DBL_MAX
;
187 } else if (atts
.value
== "INF") {
190 value
.facet_minExclusive
= stringToLongDouble(atts
.value
.c_str());
192 value
.modified
= true;
193 value
.lowerExclusive
= true;
196 if (atts
.value
== "NaN") {
198 } else if (atts
.value
== "-INF") {
200 } else if (atts
.value
== "INF") {
201 value
.facet_maxExclusive
= DBL_MAX
;
203 value
.facet_maxExclusive
= stringToLongDouble(atts
.value
.c_str());
205 value
.modified
= true;
206 value
.upperExclusive
= true;
209 value
.facet_totalDigits
= strtoul(atts
.value
.c_str(), NULL
, 0);
210 value
.modified
= true;
212 case n_fractionDigits
:
213 //addVariant(V_fractionDigits, atts.value);
216 addComment(Mstring("LABEL:"));
219 addComment(Mstring("DEFINITION:"));
226 void SimpleType::applyDefaultAttribute(const Mstring
& default_value
) {
227 if (!default_value
.empty()) {
228 value
.default_value
= default_value
;
229 const Mstring nameT
= type
.originalValueWoPrefix
.getValueWithoutPrefix(':');
230 //Not supported for hexBinary and base64Binary
231 if (nameT
!= "hexBinary" && nameT
!= "base64Binary") {
232 addVariant(V_defaultForEmpty
, default_value
);
237 void SimpleType::applyFixedAttribute(const Mstring
& fixed_value
) {
238 if (!fixed_value
.empty()) {
239 value
.fixed_value
= fixed_value
;
240 value
.modified
= true;
241 const Mstring nameT
= type
.originalValueWoPrefix
.getValueWithoutPrefix(':');
242 //Not supported for hexBinary and base64Binary
243 if (nameT
!= "hexBinary" && nameT
!= "base64Binary") {
244 addVariant(V_defaultForEmpty
, fixed_value
);
249 void SimpleType::applyNillableAttribute(const bool nillable
) {
251 ComplexType
* new_complextype
= new ComplexType(*this, ComplexType::fromTagNillable
); // generating complextype from simpletype
252 new_complextype
->loadWithValues();
256 void SimpleType::applyAbstractAttribute(const bool abstract_value
) {
257 if (abstract_value
) {
258 addVariant(V_onlyValueHidden
, Mstring("\"abstract\""));
262 void SimpleType::applySubstitionGroupAttribute(const Mstring
& substition_group
){
263 if(!substition_group
.empty()){
264 substitionGroup
= substition_group
;
268 void SimpleType::applyBlockAttribute(const BlockValue block_
){
269 if(block_
== not_set
){
270 block
= getModule()->getBlockDefault();
276 void SimpleType::addToSubstitutions(){
280 SimpleType
* st_
= (SimpleType
*) TTCN3ModuleInventory::getInstance().lookup(this, substitionGroup
, want_BOTH
);
282 printError(module
->getSchemaname(), name
.convertedValue
,
283 "Reference for a non-defined type: " + substitionGroup
);
284 TTCN3ModuleInventory::getInstance().incrNumErrors();
288 SimpleType
* st
= (SimpleType
*)st_
;
289 if(st
->getSubstitution() != NULL
){
290 st
= st
->getSubstitution();
293 st
->referenceResolving();
294 substitionGroup
= empty_string
;
296 if(st
->subsGroup
== NULL
){
297 ComplexType
* head_element
= new ComplexType(*st
, ComplexType::fromTagSubstition
);
298 for(List
<SimpleType
*>::iterator simpletype
= st
->nameDepList
.begin(); simpletype
; simpletype
= simpletype
->Next
){
299 head_element
->nameDepList
.push_back(simpletype
->Data
);
301 st
->nameDepList
.clear();
302 st
->getModule()->addMainType(head_element
);
303 head_element
->addVariant(V_untagged
);
304 head_element
->addSubstitution(st
);
305 head_element
->addSubstitution(this);
306 //if st->subsGroup == this, then it is a generated subs group
307 st
->subsGroup
= head_element
;
310 st
->subsGroup
->addSubstitution(this);
314 void SimpleType::setReference(const Mstring
& ref
, bool only_name_dependency
) {
318 if (isBuiltInType(ref
)) {
319 builtInBase
= ref
.getValueWithoutPrefix(':');
320 if (name
.convertedValue
.empty()) {
323 if (type
.convertedValue
.empty() || type
.convertedValue
== "anySimpleType") {
324 type
.upload(ref
.getValueWithoutPrefix(':'));
330 Mstring refPrefix
= ref
.getPrefix(':');
331 Mstring refValue
= ref
.getValueWithoutPrefix(':');
333 // Find the URI amongst the known namespace URIs
334 List
<NamespaceType
>::iterator declNS
;
335 for (declNS
= module
->getDeclaredNamespaces().begin(); declNS
; declNS
= declNS
->Next
) {
336 if (refPrefix
== declNS
->Data
.prefix
) {
337 refUri
= declNS
->Data
.uri
;
342 // FIXME: can this part be moved above the search ?
343 if (refUri
.empty()) { // not found
344 if (refPrefix
== "xml") {
345 refUri
= "http://www.w3.org/XML/1998/namespace";
346 } else if (refPrefix
== "xmlns") {
347 refUri
= "http://www.w3.org/2000/xmlns";
348 } else if (refPrefix
.empty() && module
->getTargetNamespace() == "NoTargetNamespace") {
349 refUri
= "NoTargetNamespace";
353 if (refUri
.empty()) { // something is incorrect - unable to find the uri to the given prefix
354 if (refPrefix
.empty()) {
355 printError(module
->getSchemaname(), parser
->getActualLineNumber(),
356 Mstring("The absent namespace must be imported because "
357 "it is not the same as the target namespace of the current schema."));
358 parser
->incrNumErrors();
361 printError(module
->getSchemaname(), parser
->getActualLineNumber(),
362 "The value \'" + ref
+ "\' is incorrect: "
363 "A namespace prefix does not denote any URI.");
364 parser
->incrNumErrors();
369 if (only_name_dependency
) {
373 outside_reference
.load(refUri
, refValue
, &declNS
->Data
);
376 void SimpleType::referenceResolving() {
377 if (outside_reference
.empty() && substitionGroup
.empty()) return;
378 if (outside_reference
.is_resolved()) return;
380 if(!outside_reference
.empty()){
381 SimpleType
* found_ST
= static_cast<SimpleType
*> (
382 TTCN3ModuleInventory::getInstance().lookup(this, want_ST
));
383 ComplexType
* found_CT
= static_cast<ComplexType
*> (
384 TTCN3ModuleInventory::getInstance().lookup(this, want_CT
));
385 // It _is_ possible to find both
387 if (found_ST
!= NULL
) {
388 if (!found_ST
->outside_reference
.empty() && !found_ST
->outside_reference
.is_resolved() && found_ST
!= this) {
389 found_ST
->outside_reference
.set_resolved(NULL
);
390 found_ST
->referenceResolving();
392 referenceForST(found_ST
);
393 if (!isBuiltInType(type
.convertedValue
)) {
394 found_ST
->addToNameDepList(this);
396 } else if (found_CT
!= NULL
) {
397 referenceForCT(found_CT
);
398 if (!isBuiltInType(type
.convertedValue
)) {
399 found_CT
->addToNameDepList(this);
402 printError(module
->getSchemaname(), name
.convertedValue
,
403 "Reference for a non-defined type: " + outside_reference
.repr());
404 TTCN3ModuleInventory::getInstance().incrNumErrors();
405 outside_reference
.set_resolved(NULL
);
407 if(!substitionGroup
.empty()){
408 addToSubstitutions();
410 }else if(!substitionGroup
.empty()){
411 addToSubstitutions();
415 void SimpleType::referenceForST(SimpleType
* found_ST
) {
416 outside_reference
.set_resolved(found_ST
);
421 if (construct
== c_element
)
424 if (mode
== listMode
)
427 if (!found_ST
->builtInBase
.empty()) {
428 builtInBase
= found_ST
->builtInBase
;
431 length
.applyReference(found_ST
->length
);
432 pattern
.applyReference(found_ST
->pattern
);
433 enumeration
.applyReference(found_ST
->enumeration
);
434 whitespace
.applyReference(found_ST
->whitespace
);
435 value
.applyReference(found_ST
->value
);
437 mode
= found_ST
->mode
;
438 if (found_ST
->mode
!= listMode
) {
439 type
.upload(found_ST
->getType().convertedValue
);
443 void SimpleType::referenceForCT(ComplexType
* found_CT
) {
444 outside_reference
.set_resolved(found_CT
);
449 // Section 7.5.3 Example5
450 if (found_CT
->getType().convertedValue
== Mstring("union") && mode
== restrictionMode
) {
451 for (List
<Mstring
>::iterator facet
= enumeration
.facets
.begin(); facet
; facet
= facet
->Next
) {
452 enumeration
.items_misc
.push_back(facet
->Data
);
455 size_t value_size
= value
.items_with_value
.size(); //Used to check changes
456 enumeration
.modified
= false;
457 for (List
<Mstring
>::iterator itemMisc
= enumeration
.items_misc
.begin(); itemMisc
; itemMisc
= itemMisc
->Next
) {
458 size_t act_size
= value
.items_with_value
.size(); //Used to detect if field did not match any field
459 for (List
<ComplexType
*>::iterator field
= found_CT
->complexfields
.begin(); field
; field
= field
->Next
) {
460 if (isIntegerType(field
->Data
->getType().convertedValue
)) {
463 sscanf(itemMisc
->Data
.c_str(), "%d%n", &val
, &read_chars
);
464 if ((size_t) read_chars
== itemMisc
->Data
.size()) {
465 expstring_t tmp_string
= mprintf("{%s:=%d}",
466 field
->Data
->getName().convertedValue
.c_str(), val
);
467 value
.items_with_value
.push_back(Mstring(tmp_string
));
472 if (isFloatType(field
->Data
->getType().convertedValue
)) {
475 sscanf(itemMisc
->Data
.c_str(), "%f%n", &val
, &read_chars
);
476 if ((size_t) read_chars
== itemMisc
->Data
.size()) {
477 expstring_t tmp_string
= mprintf("{%s:=%f}",
478 field
->Data
->getName().convertedValue
.c_str(), val
);
479 value
.items_with_value
.push_back(Mstring(tmp_string
));
484 if (isTimeType(field
->Data
->getType().convertedValue
)) {
485 if (matchDates(itemMisc
->Data
.c_str(), field
->Data
->getType().originalValueWoPrefix
.c_str())) {
486 expstring_t tmp_string
= mprintf("{%s:=\"%s\"}",
487 field
->Data
->getName().convertedValue
.c_str(), itemMisc
->Data
.c_str());
488 value
.items_with_value
.push_back(Mstring(tmp_string
));
493 if (isStringType(field
->Data
->getType().convertedValue
)) {
494 expstring_t tmp_string
= mprintf("{%s:=\"%s\"}",
495 field
->Data
->getName().convertedValue
.c_str(), itemMisc
->Data
.c_str());
496 value
.items_with_value
.push_back(Mstring(tmp_string
));
501 if (act_size
== value
.items_with_value
.size()) {
502 printWarning(getModule()->getSchemaname(), getName().convertedValue
,
503 Mstring("The following enumeration did not match any field: ") + itemMisc
->Data
+ Mstring("."));
504 TTCN3ModuleInventory::getInstance().incrNumWarnings();
508 if (value_size
!= value
.items_with_value
.size()) {
509 value
.modified
= true;
513 void SimpleType::nameConversion(NameConversionMode conversion_mode
, const List
<NamespaceType
> & ns
) {
515 switch (conversion_mode
) {
517 nameConversion_names();
520 nameConversion_types(ns
);
527 void SimpleType::nameConversion_names() {
528 Mstring res
, var(module
->getTargetNamespace());
529 XSDName2TTCN3Name(name
.convertedValue
, TTCN3ModuleInventory::getInstance().getTypenames(), type_name
, res
, var
);
530 name
.convertedValue
= res
;
531 addVariant(V_onlyValue
, var
);
532 for (List
<SimpleType
*>::iterator st
= nameDepList
.begin(); st
; st
= st
->Next
) {
533 st
->Data
->setTypeValue(res
);
537 void SimpleType::nameConversion_types(const List
<NamespaceType
> & ns
) {
538 if (type
.convertedValue
== "record" || type
.convertedValue
== "set"
539 || type
.convertedValue
== "union" || type
.convertedValue
== "enumerated") return;
541 Mstring prefix
= type
.convertedValue
.getPrefix(':');
542 Mstring value_str
= type
.convertedValue
.getValueWithoutPrefix(':');
545 for (List
<NamespaceType
>::iterator namesp
= ns
.begin(); namesp
; namesp
= namesp
->Next
) {
546 if (prefix
== namesp
->Data
.prefix
) {
547 uri
= namesp
->Data
.uri
;
552 QualifiedName
tmp(uri
, value_str
);
554 QualifiedNames::iterator origTN
= TTCN3ModuleInventory::getInstance().getTypenames().begin();
555 for (; origTN
; origTN
= origTN
->Next
) {
556 if (tmp
== origTN
->Data
) {
557 QualifiedName
tmp_name(module
->getTargetNamespace(), name
.convertedValue
);
558 if (tmp_name
== origTN
->Data
)
559 continue; // get a new type name
564 if (origTN
!= NULL
) {
565 setTypeValue(origTN
->Data
.name
);
566 // This ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ is always value_str
567 // The only effect here is to remove the "xs:" prefix from type.convertedValue,
568 // otherwise the new value is always the same as the old.
571 XSDName2TTCN3Name(value_str
, TTCN3ModuleInventory::getInstance().getTypenames(), type_reference_name
, res
, var
);
576 void SimpleType::finalModification() {
578 length
.applyFacets();
579 pattern
.applyFacet();
580 whitespace
.applyFacet();
581 enumeration
.applyFacets();
583 if (module
->getElementFormDefault() == qualified
&&
584 element_form_as
== unqualified
) {
585 addVariant(V_formAs
, Mstring("unqualified"));
586 } else if (module
->getElementFormDefault() != qualified
&&
587 element_form_as
== qualified
) {
588 addVariant(V_formAs
, Mstring("qualified"));
591 if (module
->getAttributeFormDefault() == qualified
&&
592 attribute_form_as
== unqualified
) {
593 addVariant(V_formAs
, Mstring("unqualified"));
594 } else if (module
->getAttributeFormDefault() != qualified
&&
595 attribute_form_as
== qualified
) {
596 addVariant(V_formAs
, Mstring("qualified"));
599 if (type
.originalValueWoPrefix
== Mstring("boolean")) {
600 addVariant(V_onlyValueHidden
, Mstring("\"text 'false' as '0'\""));
601 addVariant(V_onlyValueHidden
, Mstring("\"text 'true' as '1'\""));
604 isOptional
= isOptional
|| (minOccurs
== 0 && maxOccurs
== 0);
606 // If the type name is the same as the identifier then we have to prefix it
607 // with the module identifier.
608 if (type
.convertedValue
== name
.convertedValue
&& !outside_reference
.empty()) {
609 List
<const TTCN3Module
*>::iterator import_module
= module
->getImportedModules().begin();
610 for (; import_module
; import_module
= import_module
->Next
) {
611 if (import_module
->Data
->getTargetNamespace() == outside_reference
.get_uri()) {
612 type
.upload(import_module
->Data
->getModulename() + Mstring(".") + type
.convertedValue
);
619 bool SimpleType::hasUnresolvedReference() {
620 if (!outside_reference
.empty() && !outside_reference
.is_resolved()) {
627 void SimpleType::applyRefAttribute(const Mstring
& ref_value
) {
628 if (!ref_value
.empty()) {
629 setReference(ref_value
);
634 void SimpleType::printToFile(FILE * file
) {
641 fputs("type ", file
);
642 if(enumeration
.modified
&& hasVariant(Mstring("\"list\""))){
643 printMinOccursMaxOccurs(file
, false);
644 fprintf(file
, "enumerated\n{\n");
645 enumeration
.sortFacets();
646 enumeration
.printToFile(file
);
647 fprintf(file
, "\n} %s", name
.convertedValue
.c_str());
648 } else if (enumeration
.modified
) {
649 if (isFloatType(builtInBase
)) {
650 fprintf(file
, "%s %s (", type
.convertedValue
.c_str(), name
.convertedValue
.c_str());
651 enumeration
.sortFacets();
652 enumeration
.printToFile(file
);
655 fprintf(file
, "enumerated %s\n{\n", name
.convertedValue
.c_str());
656 enumeration
.sortFacets();
657 enumeration
.printToFile(file
);
661 printMinOccursMaxOccurs(file
, false);
663 int multiplicity
= multi(module
, outside_reference
, this);
664 const RootType
*type_ref
= outside_reference
.get_ref();
665 if ((multiplicity
> 1) && type_ref
666 && type_ref
->getModule() != module
) {
667 fprintf(file
, "%s.", type_ref
->getModule()->getModulename().c_str());
670 fprintf(file
, "%s %s",
671 type
.convertedValue
.c_str(), name
.convertedValue
.c_str());
672 pattern
.printToFile(file
);
673 value
.printToFile(file
);
674 length
.printToFile(file
);
676 enumeration
.insertVariants();
678 fputs(";\n\n\n", file
);
681 void SimpleType::dump(unsigned int depth
) const {
682 static const char *modes
[] = {
683 "", "restriction", "extension", "list"
685 fprintf(stderr
, "%*s SimpleType '%s' -> '%s' at %p\n", depth
* 2, "",
686 name
.originalValueWoPrefix
.c_str(), name
.convertedValue
.c_str(),
688 fprintf(stderr
, "%*s type '%s' -> '%s'\n", depth
* 2, "",
689 type
.originalValueWoPrefix
.c_str(), type
.convertedValue
.c_str());
691 if (mode
!= noMode
) {
692 fprintf(stderr
, "%*s %s, base='%s'\n", depth
* 2, "", modes
[mode
], builtInBase
.c_str());
695 // fprintf (stderr, "%*s rfo='%s' n_d='%s'\n", depth * 2, "",
696 // reference_for_other.c_str(), name_dependency.c_str());
699 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
701 LengthType::LengthType(SimpleType
* a_simpleType
)
702 : parent(a_simpleType
)
705 , facet_maxLength(ULLONG_MAX
)
707 , upper(ULLONG_MAX
) {
710 void LengthType::applyReference(const LengthType
& other
) {
711 if (!modified
) modified
= other
.modified
;
712 if (other
.facet_minLength
> facet_minLength
) facet_minLength
= other
.facet_minLength
;
713 if (other
.facet_maxLength
< facet_maxLength
) facet_maxLength
= other
.facet_maxLength
;
716 void LengthType::applyFacets() // only for string types and list types without QName
718 if (!modified
) return;
720 switch (parent
->getMode()) {
721 case SimpleType::restrictionMode
:
723 const Mstring
& base
= parent
->getBuiltInBase();
724 if ((isStringType(base
) || (isSequenceType(base
) && base
!= "QName") || isAnyType(base
)) || base
.empty()) {
725 lower
= facet_minLength
;
726 upper
= facet_maxLength
;
728 printWarning(parent
->getModule()->getSchemaname(), parent
->getName().convertedValue
,
729 Mstring("Length restriction is not supported on type '") + base
+ Mstring("'."));
730 TTCN3ModuleInventory::getInstance().incrNumWarnings();
734 case SimpleType::extensionMode
:
735 case SimpleType::listMode
:
736 lower
= facet_minLength
;
737 upper
= facet_maxLength
;
739 case SimpleType::noMode
:
743 printError(parent
->getModule()->getSchemaname(), parent
->getName().convertedValue
,
744 Mstring("The upper boundary of length restriction cannot be smaller than the lower boundary."));
745 TTCN3ModuleInventory::getInstance().incrNumErrors();
750 void LengthType::printToFile(FILE * file
) const {
751 if (!modified
) return;
752 if (parent
->getEnumeration().modified
) return;
754 if (lower
== upper
) {
755 fprintf(file
, " length(%llu)", lower
);
757 fprintf(file
, " length(%llu .. ", lower
);
759 if (upper
== ULLONG_MAX
) {
760 fputs("infinity", file
);
762 fprintf(file
, "%llu", upper
);
769 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
771 PatternType::PatternType(SimpleType
* a_simpleType
)
772 : parent(a_simpleType
)
778 void PatternType::applyReference(const PatternType
& other
) {
779 if (!modified
) modified
= other
.modified
;
780 if (facet
.empty()) facet
= other
.facet
;
783 void PatternType::applyFacet() // only for time types and string types without hexBinary
785 if (!modified
) return;
787 const Mstring
& base
= parent
->getBuiltInBase();
788 if (((isStringType(base
) && base
!= "hexBinary") || isTimeType(base
) || isAnyType(base
)) || base
.empty()) {
789 // XSD pattern to TTCN-3 pattern; ETSI ES 201 873-9 clause 6.1.4
790 // FIXME a proper scanner is needed, e.g. from flex
792 for (size_t i
= 0; i
!= facet
.size(); ++i
) {
796 value
+= charclass
? "\\("
800 value
+= charclass
? "\\)"
807 value
+= charclass
? "\\^"
818 case '.': // any character
819 value
+= charclass
? '.'
822 case '*': // 0 or more
823 value
+= '*'; //#(0,)
826 value
+= '+'; //#(1,)
829 value
+= charclass
? "?"
836 if (charclass
== 0) {
839 while (facet
[i
+ k
] != '}') {
844 match
= sscanf(s
.c_str(), "%i,%i", &a
, &b
);
845 if (match
== 1 || match
== 2) {
859 value
+= charclass
? "\\}"
864 // Appendix G1.1 of XML Schema Datatypes: Character class escapes;
865 // specifically, http://www.w3.org/TR/xmlschema11-2/#nt-MultiCharEsc
866 char cn
= facet
[i
+ 1];
869 value
+= charclass
? "\\w\\d.\\-_:"
873 value
+= charclass
? "^\\w\\d.\\-_:"
877 value
+= charclass
? "^\\d"
881 value
+= charclass
? "\\w\\d:"
885 value
+= charclass
? "^\\w\\d:"
889 value
+= charclass
? "\\q{0,0,0,20}\\q{0,0,0,10}\\t\\r"
890 : "[\\q{0,0,0,20}\\q{0,0,0,10}\\t\\r]";
893 value
+= charclass
? "^\\q{0,0,0,20}\\q{0,0,0,10}\\t\\r"
894 : "[^\\q{0,0,0,20}\\q{0,0,0,10}\\t\\r]";
897 value
+= charclass
? "^\\w"
901 printWarning(parent
->getModule()->getSchemaname(), parent
->getName().convertedValue
,
902 Mstring("Character categories and blocks are not supported."));
903 TTCN3ModuleInventory::getInstance().incrNumWarnings();
905 Mstring("Pattern is not converted due to using character categories and blocks in patterns is not supported."));
913 // backslash + another: pass unmodified; this also handles \d and \w
922 if (facet
[i
+ 1] == '#') { // &#....;
925 while (facet
[i
+ k
] != ';') {
929 long long int d
= atoll(s
.c_str());
930 if (d
< 0 || d
> 2147483647) {
931 printError(parent
->getModule()->getSchemaname(), parent
->getName().convertedValue
,
932 Mstring("Invalid unicode character."));
933 TTCN3ModuleInventory::getInstance().incrNumErrors();
935 unsigned char group
= (d
>> 24) & 0xFF;
936 unsigned char plane
= (d
>> 16) & 0xFF;
937 unsigned char row
= (d
>> 8) & 0xFF;
938 unsigned char cell
= d
& 0xFF;
940 expstring_t res
= mprintf("\\q{%d, %d, %d, %d}", group
, plane
, row
, cell
);
946 default: //just_copy:
952 printWarning(parent
->getModule()->getSchemaname(), parent
->getName().convertedValue
,
953 Mstring("Pattern restriction is not supported on type '") + base
+ Mstring("'."));
954 TTCN3ModuleInventory::getInstance().incrNumWarnings();
958 void PatternType::printToFile(FILE * file
) const {
959 if (!modified
|| value
.empty()) return;
960 if (parent
->getEnumeration().modified
) return;
962 fprintf(file
, " (pattern \"%s\")", value
.c_str());
965 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
967 EnumerationType::EnumerationType(SimpleType
* a_simpleType
)
968 : parent(a_simpleType
)
979 void EnumerationType::applyReference(const EnumerationType
& other
) {
980 if (!modified
) modified
= other
.modified
;
981 for (List
<Mstring
>::iterator facet
= other
.facets
.begin(); facet
; facet
= facet
->Next
) {
982 facets
.push_back(facet
->Data
);
986 void EnumerationType::applyFacets() // string types, integer types, float types, time types
988 if (!modified
) return;
990 facets
.remove_dups();
992 const Mstring
& base
= parent
->getBuiltInBase();
994 if (isStringType(base
)) // here length restriction is applicable
996 List
<Mstring
> text_variants
;
997 for (List
<Mstring
>::iterator facet
= facets
.begin(); facet
; facet
= facet
->Next
) {
998 const LengthType
& length
= parent
->getLength();
999 if (length
.lower
<= facet
->Data
.size() && facet
->Data
.size() <= length
.upper
) {
1001 XSDName2TTCN3Name(facet
->Data
, items_string
, enum_id_name
, res
, var
);
1002 text_variants
.push_back(var
);
1005 text_variants
.sort();
1006 for (List
<Mstring
>::iterator var
= text_variants
.end(); var
; var
= var
->Prev
) {
1007 variants
.push_back(var
->Data
);
1009 } else if (isIntegerType(base
)) // here value restriction is applicable
1011 for (List
<Mstring
>::iterator facet
= facets
.begin(); facet
; facet
= facet
->Next
) {
1012 int int_value
= atoi(facet
->Data
.c_str());
1013 const ValueType
& value
= parent
->getValue();
1014 if (value
.lower
<= int_value
&& int_value
<= value
.upper
) {
1016 for (List
<int>::iterator itemInt
= items_int
.begin(); itemInt
; itemInt
= itemInt
->Next
) {
1017 if (int_value
== itemInt
->Data
) {
1022 if (!found
) items_int
.push_back(int_value
);
1024 if (variants
.empty() || variants
.back() != "\"useNumber\"") {
1025 variants
.push_back(Mstring("\"useNumber\""));
1029 } else if (isFloatType(base
)) // here value restriction is applicable
1031 for (List
<Mstring
>::iterator facet
= facets
.begin(); facet
; facet
= facet
->Next
) {
1032 double float_value
= atof(facet
->Data
.c_str());
1033 const ValueType
& value
= parent
->getValue();
1034 if (value
.lower
<= float_value
&& float_value
<= value
.upper
) {
1036 for (List
<double>::iterator itemFloat
= items_float
.begin(); itemFloat
; itemFloat
= itemFloat
->Next
) {
1037 if (float_value
== itemFloat
->Data
) {
1043 items_float
.push_back(float_value
);
1047 } else if (isTimeType(base
)) {
1048 List
<Mstring
> text_variants
;
1049 for (List
<Mstring
>::iterator facet
= facets
.begin(); facet
; facet
= facet
->Next
) {
1051 XSDName2TTCN3Name(facet
->Data
, items_time
, enum_id_name
, res
, var
);
1052 text_variants
.push_back(var
);
1054 text_variants
.sort();
1055 for (List
<Mstring
>::iterator var
= text_variants
.end(); var
; var
= var
->Prev
) {
1056 variants
.push_back(var
->Data
);
1058 } else if (isAnyType(base
)) {
1059 } else if (base
.empty()) {
1061 printWarning(parent
->getModule()->getSchemaname(), parent
->getName().convertedValue
,
1062 Mstring("Enumeration restriction is not supported on type '") + base
+ Mstring("'."));
1063 TTCN3ModuleInventory::getInstance().incrNumWarnings();
1064 parent
->setInvisible();
1068 void EnumerationType::sortFacets() {
1069 items_string
.sort();
1075 void EnumerationType::printToFile(FILE * file
, unsigned int indent_level
) const {
1076 if (!modified
) return;
1078 const Mstring
& base
= parent
->getBuiltInBase();
1079 if (isStringType(base
)) {
1080 for (QualifiedNames::iterator itemString
= items_string
.begin(); itemString
; itemString
= itemString
->Next
) {
1081 if (itemString
!= items_string
.begin()) fputs(",\n", file
);
1082 for (unsigned int l
= 0; l
!= indent_level
; ++l
) fputs("\t", file
);
1083 fprintf(file
, "\t%s", itemString
->Data
.name
.c_str());
1085 } else if (isIntegerType(base
)) {
1086 for (List
<int>::iterator itemInt
= items_int
.begin(); itemInt
; itemInt
= itemInt
->Next
) {
1087 if (itemInt
!= items_int
.begin()) fputs(",\n", file
);
1088 for (unsigned int l
= 0; l
!= indent_level
; ++l
) fputs("\t", file
);
1089 if (itemInt
->Data
< 0) {
1090 fprintf(file
, "\tint_%d(%d)", abs(itemInt
->Data
), itemInt
->Data
);
1092 fprintf(file
, "\tint%d(%d)", itemInt
->Data
, itemInt
->Data
);
1095 } else if (isFloatType(base
)) {
1096 for (List
<double>::iterator itemFloat
= items_float
.begin(); itemFloat
; itemFloat
= itemFloat
->Next
) {
1097 if (itemFloat
!= items_float
.begin()) fputs(", ", file
);
1100 double fracpart
= 0;
1101 fracpart
= modf(itemFloat
->Data
, &intpart
);
1102 if (fracpart
== 0) {
1103 fprintf(file
, "%lld.0", (long long int) (itemFloat
->Data
));
1105 fprintf(file
, "%g", itemFloat
->Data
);
1108 } else if (isTimeType(base
)) {
1109 for (QualifiedNames::iterator itemTime
= items_time
.begin(); itemTime
; itemTime
= itemTime
->Next
) {
1110 if (itemTime
!= items_time
.begin()) fputs(",\n", file
);
1111 for (unsigned int l
= 0; l
!= indent_level
; ++l
) fputs("\t", file
);
1112 fprintf(file
, "\t%s", itemTime
->Data
.name
.c_str());
1117 void EnumerationType::insertVariants(){
1118 if(!modified
) return;
1120 Mstring pre_connector
= empty_string
;
1121 if(parent
->getMinOccurs() == 0 && parent
->getMaxOccurs() == ULLONG_MAX
){
1122 pre_connector
= "([-]) ";
1124 for(List
<Mstring
>::iterator var
= variants
.begin(); var
; var
= var
->Next
){
1125 parent
->addVariant(V_onlyValue
, pre_connector
+ var
->Data
);
1129 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1131 WhitespaceType::WhitespaceType(SimpleType
* a_simpleType
)
1132 : p_parent(a_simpleType
)
1138 void WhitespaceType::applyReference(const WhitespaceType
& other
) {
1139 if (!modified
) modified
= other
.modified
;
1140 if (facet
.empty()) facet
= other
.facet
;
1143 void WhitespaceType::applyFacet() // only for string types: string, normalizedString, token, Name, NCName, language
1145 if (!modified
) return;
1147 const Mstring
& base
= p_parent
->getBuiltInBase();
1148 if (base
== "string" || base
== "normalizedString" || base
== "token" || base
== "language" ||
1149 base
== "Name" || base
== "NCName" || isAnyType(base
) || base
.empty()) {
1150 p_parent
->addVariant(V_whiteSpace
, facet
);
1152 printWarning(p_parent
->getModule()->getSchemaname(), p_parent
->getName().convertedValue
,
1153 Mstring("Facet 'whiteSpace' is not applicable for type '") + base
+ Mstring("'."));
1154 TTCN3ModuleInventory::getInstance().incrNumWarnings();
1158 ValueType::ValueType(SimpleType
* a_simpleType
)
1159 : parent(a_simpleType
)
1161 , facet_minInclusive(-DBL_MAX
)
1162 , facet_maxInclusive(DBL_MAX
)
1163 , facet_minExclusive(-DBL_MAX
)
1164 , facet_maxExclusive(DBL_MAX
)
1165 , facet_totalDigits(-1)
1168 , lowerExclusive(false)
1169 , upperExclusive(false)
1170 , not_a_number(false)
1173 , items_with_value() {
1176 void ValueType::applyReference(const ValueType
& other
) {
1178 modified
= other
.modified
;
1183 if (other
.not_a_number
) not_a_number
= true;
1184 if (other
.facet_minInclusive
> facet_minInclusive
) facet_minInclusive
= other
.facet_minInclusive
;
1185 if (other
.facet_maxInclusive
< facet_maxInclusive
) facet_maxInclusive
= other
.facet_maxInclusive
;
1186 if (other
.facet_minExclusive
> facet_minExclusive
) facet_minExclusive
= other
.facet_minExclusive
;
1187 if (other
.facet_maxExclusive
< facet_maxExclusive
) facet_maxExclusive
= other
.facet_maxExclusive
;
1188 //-1 in case when it is not modified
1189 if (other
.facet_totalDigits
< facet_totalDigits
|| facet_totalDigits
== -1) facet_totalDigits
= other
.facet_totalDigits
;
1190 if (!other
.default_value
.empty()) {
1191 default_value
= other
.default_value
;
1192 parent
->addVariant(V_defaultForEmpty
, default_value
);
1194 if (!other
.fixed_value
.empty()) {
1195 fixed_value
= other
.fixed_value
;
1196 parent
->addVariant(V_defaultForEmpty
, fixed_value
);
1200 void ValueType::applyFacets() // only for integer and float types
1210 const Mstring
& base
= parent
->getBuiltInBase();
1212 * Setting of default value range of built-in types
1214 if (base
== "positiveInteger") {
1216 } else if (base
== "nonPositiveInteger") {
1218 } else if (base
== "negativeInteger") {
1220 } else if (base
== "nonNegativeInteger") {
1222 } else if (base
== "unsignedLong") {
1225 } else if (base
== "int") {
1228 } else if (base
== "unsignedInt") {
1231 } else if (base
== "short") {
1234 } else if (base
== "unsignedShort") {
1237 } else if (base
== "byte") {
1240 } else if (base
== "unsignedByte") {
1245 if (isIntegerType(base
)) {
1246 if (facet_minInclusive
!= -DBL_MAX
&& facet_minInclusive
> lower
) lower
= facet_minInclusive
;
1247 if (facet_maxInclusive
!= DBL_MAX
&& upper
> facet_maxInclusive
) upper
= facet_maxInclusive
;
1248 if (facet_minExclusive
!= -DBL_MAX
&& lower
< facet_minExclusive
) lower
= facet_minExclusive
;
1249 if (facet_maxExclusive
!= DBL_MAX
&& upper
> facet_maxExclusive
) upper
= facet_maxExclusive
;
1250 } else if (isFloatType(base
)) {
1251 if (facet_minInclusive
!= -DBL_MAX
&& lower
< facet_minInclusive
) lower
= facet_minInclusive
;
1252 if (facet_maxInclusive
!= DBL_MAX
&& upper
> facet_maxInclusive
) upper
= facet_maxInclusive
;
1253 if (facet_minExclusive
!= -DBL_MAX
&& lower
< facet_minExclusive
) lower
= facet_minExclusive
;
1254 if (facet_maxExclusive
!= DBL_MAX
&& upper
> facet_maxExclusive
) upper
= facet_maxExclusive
;
1255 } else if (isAnyType(base
) || isTimeType(base
) || isBooleanType(base
)) {
1256 } else if (isStringType(base
) && (
1257 base
.getValueWithoutPrefix(':') != "hexBinary" && base
.getValueWithoutPrefix(':') != "base64Binary")) {
1258 } else if (base
.empty()) {
1260 printWarning(parent
->getModule()->getSchemaname(), parent
->getName().convertedValue
,
1261 Mstring("Value restriction is not supported on type '") + base
+ Mstring("'."));
1262 TTCN3ModuleInventory::getInstance().incrNumWarnings();
1265 // totalDigits facet is only for integer types and decimal
1266 if (facet_totalDigits
> 0) // if this facet is used
1268 double r
= pow(10.0, facet_totalDigits
);
1270 if (base
== "integer") {
1271 lower
= (int) -(r
- 1);
1272 upper
= (int) (r
- 1);
1273 } else if (base
== "positiveInteger") {
1275 upper
= (int) (r
- 1);
1276 } else if (base
== "nonPositiveInteger") {
1277 lower
= (int) -(r
- 1);
1279 } else if (base
== "negativeInteger") {
1280 lower
= (int) -(r
- 1);
1282 } else if (base
== "nonNegativeInteger") {
1284 upper
= (int) (r
- 1);
1285 } else if (base
== "long" ||
1286 base
== "unsignedLong" ||
1288 base
== "unsignedInt" ||
1290 base
== "unsignedShort" ||
1292 base
== "unsignedByte") {
1293 lower
= (int) -(r
- 1);
1294 upper
= (int) (r
- 1);
1295 } else if (base
== "decimal") {
1296 lower
= (int) -(r
- 1);
1297 upper
= (int) (r
- 1);
1299 printWarning(parent
->getModule()->getSchemaname(), parent
->getName().convertedValue
,
1300 Mstring("Facet 'totalDigits' is not applicable for type '") + base
+ Mstring("'."));
1301 TTCN3ModuleInventory::getInstance().incrNumWarnings();
1304 items_with_value
.sort();
1307 void ValueType::printToFile(FILE * file
) const {
1308 if (!modified
) return;
1309 if (parent
->getEnumeration().modified
) return;
1312 fprintf(file
, " ( not_a_number )");
1315 if (!fixed_value
.empty()) {
1316 //Base64binary and hexbyte does not supported
1318 if(isBuiltInType(parent
->getType().originalValueWoPrefix
)){
1319 type
= parent
->getType().originalValueWoPrefix
;
1321 type
= getPrefixByNameSpace(parent
, parent
->getReference().get_uri()) + Mstring(":") + parent
->getReference().get_val();
1323 if(!isBuiltInType(type
)){
1324 type
= findBuiltInType(parent
, type
);
1326 if (isStringType(type
) || isTimeType(type
) || isQNameType(type
) || isAnyType(type
)) {
1327 const Mstring
& name
= type
.getValueWithoutPrefix(':');
1328 if (name
!= "hexBinary" && name
!= "base64Binary") {
1329 fprintf(file
, " (\"%s\")", fixed_value
.c_str());
1331 } else if (isBooleanType(type
)) {
1333 if (fixed_value
== "1") {
1335 } else if (fixed_value
== "0") {
1340 fprintf(file
, " (%s)", val
.c_str());
1342 fprintf(file
, " (%s)", fixed_value
.c_str());
1346 if (!items_with_value
.empty()) {
1347 fputs(" (\n", file
);
1348 for (List
<Mstring
>::iterator itemWithValue
= items_with_value
.begin(); itemWithValue
; itemWithValue
= itemWithValue
->Next
) {
1349 fprintf(file
, "\t%s", itemWithValue
->Data
.c_str());
1350 if (itemWithValue
!= items_with_value
.end()) {
1360 if (lower
== -DBL_MAX
&& upper
== DBL_MAX
) return;
1364 if (isIntegerType(parent
->getBuiltInBase())) {
1365 if (lowerExclusive
) {
1369 if (lower
== -DBL_MAX
) {
1370 fputs("-infinity", file
);
1371 } else if (lower
< 0) {
1372 long double temp_lower
= -lower
;
1373 fprintf(file
, "-%.0Lf", temp_lower
);
1375 fprintf(file
, "%.0Lf", lower
);
1378 fputs(" .. ", file
);
1379 if (upperExclusive
) {
1383 if (upper
== DBL_MAX
) {
1384 fputs("infinity", file
);
1385 } else if (upper
< 0) {
1386 long double temp_upper
= -upper
;
1387 fprintf(file
, "-%.0Lf", temp_upper
);
1389 fprintf(file
, "%.0Lf", upper
);
1391 } else if (isFloatType(parent
->getBuiltInBase())) {
1392 if (lowerExclusive
) {
1396 if (lower
== -DBL_MAX
) {
1397 fputs("-infinity", file
);
1400 double fracpart
= 0;
1401 fracpart
= modf(lower
, &intpart
);
1402 if (fracpart
== 0) {
1403 fprintf(file
, "%.1Lf", lower
);
1405 fprintf(file
, "%Lg", lower
);
1409 fputs(" .. ", file
);
1410 if (upperExclusive
) {
1414 if (upper
== DBL_MAX
) {
1415 fputs("infinity", file
);
1418 double fracpart
= 0;
1419 fracpart
= modf(upper
, &intpart
);
1420 if (fracpart
== 0) {
1421 fprintf(file
, "%.1Lf", upper
);
1423 fprintf(file
, "%Lg", upper
);