Titan Core Initial Contribution
[deliverable/titan.core.git] / xsdconvert / GeneralFunctions.cc
CommitLineData
970ed795
EL
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 "GeneralFunctions.hh"
9#include "SimpleType.hh"
10#include "TTCN3Module.hh"
11
12#include <cctype> // for using "toupper" function
13#include <cstring>
14#include <cstdio>
15#include <cmath>
16
17extern bool w_flag_used;
18
19// XSDName2TTCN3Name function:
20// Parameters:
21// in - input string - XSD name
22// used_names - set of previously defined types, used field names etc.
23// type_of_the_name - mode of the function behaviour
24// res - generated result
25// variant - generated variant string for TTCN-3
26//
27void XSDName2TTCN3Name(const Mstring& in, QualifiedNames & used_names, modeType type_of_the_name,
28 Mstring & res, Mstring & variant)
29{
30 static const char* TTCN3_reserved_words[] =
31 {
32 "action", "activate", "address", "alive", "all", "alt", "altstep", "and", "and4b", "any", "anytype", "apply",
33 "bitstring", "boolean", "break",
34 "call", "case", "catch", "char", "charstring", "check", "clear", "complement", "component", "connect",
35 "const", "continue", "control", "create",
36 "deactivate", "default", "derefers", "disconnect", "display", "do", "done",
37 "else", "encode", "enumerated", "error", "except", "exception", "execute", "extends", "extension",
38 "external",
39 "fail", "false", "float", "for", "friend", "from", "function",
40 "getverdict", "getcall", "getreply", "goto", "group",
41 "halt", "hexstring",
42 "if", "if present", "import", "in", "inconc", "infinity", "inout", "integer", "interleave",
43 "kill", "killed",
44 "label", "language", "length", "log",
45 "map", "match", "message", "mixed", "mod", "modifies", "module", "modulepar", "mtc",
46 "noblock", "none", "not", "not4b", "nowait", "null",
47 "objid", "octetstring", "of", "omit", "on", "optional", "or", "or4b", "out", "override",
48 "param", "pass", "pattern", "permutation", "port", "present", "private", "procedure", "public",
49 "raise", "read", "receive", "record", "recursive", "refers", "rem", "repeat", "reply", "return", "running", "runs",
50 "select", "self", "send", "sender", "set", "setverdict", "signature", "start", "stop", "subset",
51 "superset", "system",
52 "template", "testcase", "timeout", "timer", "to", "trigger", "true", "type",
53 "union", "universal", "unmap",
54 "value", "valueof", "var", "variant", "verdicttype",
55 "while", "with",
56 "xor", "xor4b",
57 NULL
58 };
59 static const char* TTCN3_predefined_functions[] =
60 {
61 "bit2int", "bit2hex", "bit2oct", "bit2str",
62 "char2int", "char2oct",
63 "decomp", "decvalue",
64 "encvalue", "enum2int",
65 "float2int", "float2str",
66 "hex2bit", "hex2int", "hex2oct", "hex2str",
67 "int2bit", "int2char", "int2float", "int2hex", "int2oct", "int2str", "int2unichar",
68 "isvalue", "ischosen", "ispresent",
69 "lengthof", "log2str",
70 "oct2bit", "oct2char", "oct2hex", "oct2int", "oct2str", "oct2unichar"
71 "regexp", "replace", "rnd", "remove_bom", "get_stringencoding",
72 "sizeof", "str2bit", "str2float", "str2hex", "str2int", "str2oct", "substr",
73 "testcasename",
74 "unichar2int", "unichar2char", "unichar2oct",
75 NULL
76 };
77 static const char* ASN1_reserved_words[] =
78 {
79 "ABSENT", "ABSTRACT-SYNTAX", "ALL", "APPLICATION", "AUTOMATIC",
80 "BEGIN", "BIT", "BMPString", "BOOLEAN", "BY",
81 "CHARACTER", "CHOICE", "CLASS", "COMPONENT", "COMPONENTS", "CONSTRAINED", "CONTAINING",
82 "DEFAULT", "DEFINITIONS",
83 "EMBEDDED", "ENCODED", "END", "ENUMERATED", "EXCEPT", "EXPLICIT", "EXPORTS", "EXTENSIBILITY",
84 "EXTERNAL",
85 "FALSE", "FROM",
86 "GeneralizedTime", "GeneralString", "GraphicString",
87 "IA5String", "IDENTIFIER", "IMPLICIT", "IMPLIED", "IMPORTS", "INCLUDES", "INSTANCE", "INTEGER",
88 "INTERSECTION", "ISO646String",
89 "MAX", "MIN", "MINUS-INFINITY",
90 "NULL", "NumericString",
91 "OBJECT", "ObjectDescriptor", "OCTET", "OF", "OPTIONAL",
92 "PATTERN", "PDV", "PLUS-INFINITY", "PRESENT", "PrintableString", "PRIVATE",
93 "REAL", "RELATIVE-OID",
94 "SEQUENCE", "SET", "SIZE", "STRING", "SYNTAX",
95 "T61String", "TAGS", "TeletexString", "TRUE", "TYPE-IDENTIFIER",
96 "UNION", "UNIQUE", "UNIVERSAL", "UniversalString", "UTCTime", "UTF8String",
97 "VideotexString", "VisibleString",
98 "WITH",
99 NULL
100 };
101
102 Mstring ns_uri(variant);
103
104 res.clear();
105 variant.clear();
106 res = in;
107
108 if (res.size() > 0) {
109 /********************************************************
110 * STEP 0 - recognizing XSD built-in types
111 *
112 * ******************************************************/
113 // If the type or field reference name is an XSD built-in type then it will be capitalized and get a prefix "XSD."
114 // if (type_of_the_name == type_reference_name || type_of_the_name == field_reference_name) {
115
116 if (type_of_the_name == type_reference_name)
117 {
118 if (isBuiltInType(res)) {
119 res[0] = toupper(res[0]);
120 res = "XSD." + res;
121 return;
122 }
123 if (res == "record" ||
124 res == "union" ||
125 res == "set" )
126 {
127 return;
128 }
129 }
130
131 if (type_of_the_name == enum_id_name)
132 {
133 bool found = false;
134 for (QualifiedNames::iterator used = used_names.begin(); used; used = used->Next)
135 {
136 QualifiedName tmp(empty_string, res);
137 if (tmp == used->Data) {
138 found = true;
139 break;
140 }
141 }
142 if (found) return;
143 }
144 /********************************************************
145 * STEP 1 - character changes
146 *
147 * according to
148 * clause 5.2.2.1 - Generic name transformation rules
149 * ******************************************************/
150 // the characters ' '(SPACE), '.'(FULL STOP) and '-'(HYPEN-MINUS)shall all be replaced by a "_" (LOW LINE)
151 for (size_t i = 0; i != res.size(); ++i) {
152 if ((res[i] == ' ') ||
153 (res[i] == '.') ||
154 (res[i] == '-'))
155 {
156 res[i] = '_';
157 }
158 }
159 // any character except "A" to "Z", "a" to "z" or "0" to "9" and "_" shall be removed
160 for (size_t i = 0; i != res.size(); ++i) {
161 if (!isalpha((const unsigned char)res[i]) && !isdigit((const unsigned char)res[i]) && (res[i] != '_')) {
162 res.eraseChar(i);
163 }
164 }
165 // a sequence of two of more "_" (LOW LINE) shall be replaced with a single "_" (LOW LINE)
166 for (size_t i = 1; i < res.size(); ++i) {
167 if (res[i] == '_' && res[i-1] == '_') {
168 res.eraseChar(i--);
169 }
170 }
171 // "_" (LOW LINE) characters occurring at the end of the name shall be removed
172 if (!res.empty() && res[res.size()-1] == '_') res.eraseChar(res.size()-1);
173 // "_" (LOW LINE) characters occurring at the beginning of the name shall be removed
174 if (!res.empty() && res[0] == '_') res.eraseChar(0);
175 }
176
177 switch (type_of_the_name)
178 {
179 case type_reference_name:
180 case type_name:
181 if (res.empty()) {
182 res = "X";
183 }
184 else {
185 if (islower((const unsigned char)res[0])) res.setCapitalized();
186 else if (isdigit((const unsigned char)res[0])) res.insertChar(0, 'X');
187 }
188 break;
189 case field_name:
190 case enum_id_name:
191 if (res.empty()) {
192 res = "x";
193 }
194 else {
195 if (isupper((const unsigned char)res[0])) res.setUncapitalized();
196 else if (isdigit((const unsigned char)res[0])) res.insertChar(0, 'x');
197 }
198 break;
199 }
200 /********************************************************
201 * STEP 2 - process if the generated name is
202 * - already used
203 * - a TTCN3 keyword
204 * - an ASN.1 keyword
205 * and after any change is made
206 * according to
207 * clause 5.2.2.2 - Succeeding rules
208 * ******************************************************/
209 /********************************************************
210 * according to paragraph a)
211 * ******************************************************/
212 bool postfixing = false;
213 QualifiedName qual_name(ns_uri, res);
214
215 switch (type_of_the_name)
216 {
217 // Do not use "res" in this switch; only qual_name
218 case type_name: {
219 for (int k = 0; ASN1_reserved_words[k]; k++) {
220 if (qual_name.name == ASN1_reserved_words[k]) {
221 postfixing = true;
222 break;
223 }
224 }
225
226 for (QualifiedNames::iterator used = used_names.begin(); used; used = used->Next)
227 {
228 if (qual_name == used->Data) {
229 postfixing = true;
230 break;
231 }
232 }
233
234 if (postfixing)
235 {
236 bool found = false;
237 int counter = 1;
238 expstring_t tmpname = NULL;
239 do {
240 found = false;
241 Free(tmpname);
242 tmpname = mprintf("%s_%d", qual_name.name.c_str(), counter);
243 for (QualifiedNames::iterator used = used_names.begin(); used; used = used->Next)
244 {
245 if (QualifiedName(/* empty_string ? */ ns_uri, Mstring(tmpname)) == used->Data) {
246 found = true;
247 break;
248 }
249 }
250 counter++;
251 } while (found);
252 qual_name.name = tmpname; // NULL will result in an empty string
253 Free(tmpname);
254 postfixing = false;
255 }
256 break; }
257 case field_name:
258 case enum_id_name:
259 for (int k = 0; TTCN3_reserved_words[k]; k++) {
260 if (qual_name.name == TTCN3_reserved_words[k]) postfixing = true;
261 }
262 for (int k = 0; TTCN3_predefined_functions[k]; k++) {
263 if (qual_name.name == TTCN3_predefined_functions[k]) postfixing = true;
264 }
265 if (postfixing)
266 {
267 qual_name.name += "_";
268 postfixing = false;
269 }
270
271 for (QualifiedNames::iterator used = used_names.begin(); used; used = used->Next)
272 {
273 if (qual_name == used->Data) postfixing = true;
274 }
275
276 if (postfixing)
277 {
278 bool found = false;
279 int counter = 0;
280 if (type_of_the_name == field_name) counter = 1;
281 else if (type_of_the_name == enum_id_name) counter = 0;
282 if (qual_name.name[qual_name.name.size()-1] == '_')
283 qual_name.name.eraseChar(qual_name.name.size()-1);
284 expstring_t tmpname = mprintf("%s_%d", qual_name.name.c_str(), counter);
285 do {
286 found = false;
287 if (counter > 0) {
288 Free(tmpname);
289 tmpname = mprintf("%s_%d", qual_name.name.c_str(), counter);
290 }
291 for (QualifiedNames::iterator used = used_names.begin(); used; used = used->Next)
292 {
293 if (QualifiedName(/* empty_string ? */ns_uri, Mstring(tmpname)) == used->Data) {
294 found = true;
295 break;
296 }
297 }
298 counter++;
299 } while (found);
300 qual_name.name = tmpname;
301 Free(tmpname);
302 postfixing = false;
303 }
304 break;
305 default:
306 break;
307 }
308
309 res = qual_name.name;
310
311 /********************************************************
312 * STEP 3 - the defined name is put into the set of "not_av_names"
313 * ******************************************************/
314 // Finally recently defined name will be put into the set of "set<string> not_av_names"
315 if (type_of_the_name != type_reference_name)
316 {
317 bool found = false;
318 for (QualifiedNames::iterator used = used_names.begin(); used; used = used->Next)
319 {
320 if (qual_name == used->Data) {
321 found = true;
322 break;
323 }
324 }
325
326 if (!found) {
327 used_names.push_back(qual_name);
328 }
329 }
330 /********************************************************
331 * STEP 4
332 *
333 * ******************************************************/
334 if (in == "sequence" ||
335 in == "choice" ||
336 in == "sequence_list" ||
337 in == "choice_list")
338 {
339 return;
340 }
341 /********************************************************
342 * STEP 5 - if "input name - in" and "generated name - res"
343 * are different
344 * then a "variant string" has to be generated
345 * ******************************************************/
346 // If the final generated type name, field name or enumeration identifier (res) is different from the original one (in) then ...
347 if (in != res) {
348 Mstring tmp1 = in;
349 Mstring tmp2 = res;
350 tmp1.setUncapitalized();
351 tmp2.setUncapitalized();
352 switch (type_of_the_name)
353 {
354 case type_name:
355 if (tmp1 == tmp2) { // If the only difference is the case of the first letter
356 if (isupper(in[0])) variant += "\"name as capitalized\"";
357 else variant += "\"name as uncapitalized\"";
358 } else { // Otherwise if other letters have changed too
359 variant += "\"name as '" + in + "'\"";
360 }
361 break;
362 case field_name:
363 // Creating a variant string from a field of a complex type needs to write out the path of the fieldname
364 if (tmp1 == tmp2) { // If the only difference is the case of the first letter
365 if (isupper(in[0])) variant += "\"name as capitalized\"";
366 else variant += "\"name as uncapitalized\"";
367 } else { // Otherwise if other letters have changed too
368 variant += "\"name as '" + in + "'\"";
369 }
370 break;
371 case enum_id_name:
372 if (tmp1 == tmp2) { // If the only difference is the case of the first letter
373 if ( isupper(in[0]) ) {
374 variant += "\"text \'" + res + "\' as capitalized\"";
375 } else {
376 variant += "\"text \'" + res + "\' as uncapitalized\"";
377 }
378 } else { // Otherwise if other letters have changed too
379 variant += "\"text \'" + res + "\' as '" + in + "'\"";
380 }
381 break;
382 default:
383 break;
384 }
385 }
386}
387
388bool isBuiltInType(const Mstring& in)
389{
390 static const char* XSD_built_in_types[] = {
391 "string", "normalizedString", "token", "Name", "NMTOKEN", "NCName", "ID", "IDREF", "ENTITY",
392 "hexBinary", "base64Binary", "anyURI", "language", "integer", "positiveInteger", "nonPositiveInteger",
393 "negativeInteger", "nonNegativeInteger", "long", "unsignedLong", "int", "unsignedInt", "short",
394 "unsignedShort", "byte", "unsignedByte", "decimal", "float", "double", "duration", "dateTime", "time",
395 "date", "gYearMonth", "gYear", "gMonthDay", "gDay", "gMonth", "NMTOKENS", "IDREFS", "ENTITIES",
396 "QName", "boolean", "anyType", "anySimpleType", NULL
397 };
398 const Mstring& name = in.getValueWithoutPrefix(':');
399 for (int i = 0; XSD_built_in_types[i]; ++i) {
400 if (name == XSD_built_in_types[i]) return true;
401 }
402 return false;
403}
404
405bool isStringType(const Mstring& in)
406{
407 static const char* string_types[] = {
408 "string", "normalizedString", "token", "Name", "NMTOKEN", "NCName", "ID", "IDREF", "ENTITY",
409 "hexBinary", "base64Binary", "anyURI", "language", NULL
410 };
411 const Mstring& name = in.getValueWithoutPrefix(':');
412 for (int i = 0; string_types[i]; ++i) {
413 if (name == string_types[i]) return true;
414 }
415 return false;
416}
417
418bool isIntegerType(const Mstring& in)
419{
420 static const char* integer_types[] = {
421 "integer", "positiveInteger", "nonPositiveInteger", "negativeInteger", "nonNegativeInteger", "long",
422 "unsignedLong", "int", "unsignedInt", "short", "unsignedShort", "byte", "unsignedByte", NULL
423 };
424 const Mstring& name = in.getValueWithoutPrefix(':');
425 for (int i = 0; integer_types[i]; ++i) {
426 if (name == integer_types[i]) return true;
427 }
428 return false;
429}
430
431bool isFloatType(const Mstring& in)
432{
433 static const char* float_types[] = {
434 "decimal", "float", "double", NULL
435 };
436 const Mstring& name = in.getValueWithoutPrefix(':');
437 for (int i = 0; float_types[i]; ++i) {
438 if (name == float_types[i]) return true;
439 }
440 return false;
441}
442
443bool isTimeType(const Mstring& in)
444{
445 static const char* time_types[] = {
446 "duration", "dateTime", "time", "date", "gYearMonth", "gYear", "gMonthDay", "gDay", "gMonth", NULL
447 };
448 const Mstring& name = in.getValueWithoutPrefix(':');
449 for (int i = 0; time_types[i]; ++i) {
450 if (name == time_types[i]) return true;
451 }
452 return false;
453}
454
455bool isSequenceType(const Mstring& in)
456{
457 static const char* sequence_types[] = {
458 "NMTOKENS", "IDREFS", "ENTITIES", "QName", NULL
459 };
460 const Mstring& name = in.getValueWithoutPrefix(':');
461 for (int i = 0; sequence_types[i]; ++i) {
462 if (name == sequence_types[i]) return true;
463 }
464 return false;
465}
466
467bool isBooleanType(const Mstring& in)
468{
469 static const Mstring booltype("boolean");
470 return booltype == in.getValueWithoutPrefix(':');
471}
472
473bool isQNameType(const Mstring& in)
474{
475 static const Mstring qntype("QName");
476 return qntype == in.getValueWithoutPrefix(':');
477}
478
479bool isAnyType(const Mstring& in)
480{
481 static const char* any_types[] = {
482 "anyType", "anySimpleType", NULL
483 };
484 const Mstring& name = in.getValueWithoutPrefix(':');
485 for (int i = 0; any_types[i]; ++i) {
486 if (name == any_types[i]) return true;
487 }
488 return false;
489}
490
491void printError(const Mstring& filename, int lineNumber, const Mstring& text)
492{
493 fprintf(stderr,
494 "ERROR:\n"
495 "%s (in line %d): "
496 "%s\n",
497 filename.c_str(),
498 lineNumber,
499 text.c_str());
500}
501
502void printError(const Mstring& filename, const Mstring& typeName, const Mstring& text)
503{
504 fprintf(stderr,
505 "ERROR:\n"
506 "%s (in type %s): "
507 "%s\n",
508 filename.c_str(),
509 typeName.c_str(),
510 text.c_str());
511}
512
513void printWarning(const Mstring& filename, int lineNumber, const Mstring& text)
514{
515 if (w_flag_used) return;
516 fprintf(stderr,
517 "WARNING:\n"
518 "%s (in line %d): "
519 "%s\n",
520 filename.c_str(),
521 lineNumber,
522 text.c_str());
523}
524
525void printWarning(const Mstring& filename, const Mstring& typeName, const Mstring& text)
526{
527 if (w_flag_used) return;
528 fprintf(stderr,
529 "WARNING:\n"
530 "%s (in type %s): "
531 "%s\n",
532 filename.c_str(),
533 typeName.c_str(),
534 text.c_str());
535}
536
537long double stringToLongDouble(const char *input)
538{
539 long double result = 0.0;
540 // `strtold()' is not available on older platforms.
541 sscanf(input, "%Lf", &result);
542 return result;
543}
544
545Mstring truncatePathWithOneElement(const Mstring& path)
546{
547 Mstring result;
548 size_t pathlen = path.size();
549 if (pathlen > 1) {
550 expstring_t temp = mcopystr(path.c_str()); // modifiable copy
551 temp[pathlen - 1] = '\0'; // ignore last character
552 char * point = strrchr(temp, '.');
553 if (point != NULL) {
554 point[1] = '\0'; // truncate just past the dot
555 result = Mstring(temp);
556 }
557 Free(temp);
558 }
559 return result;
560}
561
562RootType * lookup (const List<TTCN3Module*> mods, const SimpleType * reference, wanted w)
563{
564 const Mstring& uri = reference->getReference().get_uri();
565 const Mstring& name = reference->getReference().get_val();
566
567 return lookup(mods, name, uri, reference, w);
568}
569
570RootType * lookup (const List<TTCN3Module*> mods,
571 const Mstring& name, const Mstring& nsuri, const RootType *reference, wanted w)
572{
573 RootType *ret = NULL;
574 for (List<TTCN3Module*>::iterator module = mods.begin(); module; module = module->Next)
575 {
576 ret = lookup1(module->Data, name, nsuri, reference, w);
577 if (ret != NULL) break;
578 } // next doc
579
580 return ret;
581}
582
583RootType *lookup1(const TTCN3Module *module,
584 const Mstring& name, const Mstring& nsuri, const RootType *reference, wanted w)
585{
586 if (nsuri != module->getTargetNamespace()) return NULL;
587
588 for (List<RootType*>::iterator type = module->getDefinedTypes().begin(); type; type = type->Next)
589 {
590 switch (type->Data->getConstruct())
591 {
592 case c_simpleType:
593 case c_element:
594 case c_attribute:
595 if (w == want_ST) {
596 if ((const RootType*)reference != type->Data
597 && name == type->Data->getName().convertedValue) {
598 return type->Data;
599 }
600 }
601 break;
602
603 case c_complexType:
604 case c_group:
605 case c_attributeGroup:
606 if (w == want_CT) {
607 if ((const RootType*)reference != type->Data
608 && name == type->Data->getName().convertedValue) {
609 return type->Data;
610 }
611 }
612 break;
613
614 default:
615 break;
616 }
617 }
618
619 return NULL;
620}
621
622int multi(const TTCN3Module *module, ReferenceData const& outside_reference,
623 const RootType *obj)
624{
625 int multiplicity = 0;
626
627 RootType * st = ::lookup1(module, outside_reference.get_val(), outside_reference.get_uri(), obj, want_ST);
628 RootType * ct = ::lookup1(module, outside_reference.get_val(), outside_reference.get_uri(), obj, want_CT);
629 if (st || ct) {
630 multiplicity = 1; // locally defined, no qualif needed
631 }
632 else for (List<const TTCN3Module*>::iterator it = module->getImportedModules().begin(); it; it = it->Next) {
633 // Artificial lookup
634 st = ::lookup1(it->Data, outside_reference.get_val(), it->Data->getTargetNamespace(), obj, want_ST);
635 ct = ::lookup1(it->Data, outside_reference.get_val(), it->Data->getTargetNamespace(), obj, want_CT);
636 if (st || ct) {
637 ++multiplicity;
638 }
639 }
640 return multiplicity;
641}
642
This page took 0.047993 seconds and 5 git commands to generate.