ComplexType.cc 76.6 KB
Newer Older
Elemer Lelik's avatar
Elemer Lelik committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/******************************************************************************
 * Copyright (c) 2000-2016 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Balasko, Jeno
 *   Beres, Szabolcs
 *   Godar, Marton
 *   Ormandi, Matyas
 *   Raduly, Csaba
 *   Szabo, Bence Janos
 *
 ******************************************************************************/
Elemer Lelik's avatar
Elemer Lelik committed
17
18
19
20
21
22
#include "ComplexType.hh"

#include "GeneralFunctions.hh"
#include "XMLParser.hh"
#include "TTCN3Module.hh"
#include "TTCN3ModuleInventory.hh"
Elemer Lelik's avatar
Elemer Lelik committed
23
#include "Annotation.hh"
Elemer Lelik's avatar
Elemer Lelik committed
24
25
26
27

#include <assert.h>

ComplexType::ComplexType(XMLParser * a_parser, TTCN3Module * a_module, ConstructType a_construct)
Elemer Lelik's avatar
Elemer Lelik committed
28
29
30
31
32
: SimpleType(a_parser, a_module, a_construct)
, top(true)
, nillable(false)
, enumerated(false)
, embed(false)
Elemer Lelik's avatar
Elemer Lelik committed
33
, with_union(false)
Elemer Lelik's avatar
Elemer Lelik committed
34
35
, first_child(false)
, fromAll(false)
36
37
38
, listPrint(false)
, listMinOccurs(1)
, listMaxOccurs(1)
Elemer Lelik's avatar
Elemer Lelik committed
39
40
41
42
43
44
45
46
47
, max_alt(0)
, skipback(0)
, lastType()
, actualPath(empty_string)
, actfield(this)
, nameDep(NULL)
, nillable_field(NULL)
, basefield(NULL)
, cmode(CT_undefined_mode)
Elemer Lelik's avatar
Elemer Lelik committed
48
, resolved(No)
Elemer Lelik's avatar
Elemer Lelik committed
49
, parentTypeSubsGroup(NULL)
Elemer Lelik's avatar
Elemer Lelik committed
50
51
52
53
54
, complexfields()
, attribfields()
, enumfields()
, tagNames() {
  xsdtype = n_complexType;
Elemer Lelik's avatar
Elemer Lelik committed
55
56
}

Elemer Lelik's avatar
Elemer Lelik committed
57
58
59
60
61
62
ComplexType::ComplexType(ComplexType & other)
: SimpleType(other)
, top(other.top)
, nillable(other.nillable)
, enumerated(other.enumerated)
, embed(other.embed)
Elemer Lelik's avatar
Elemer Lelik committed
63
, with_union(other.with_union)
Elemer Lelik's avatar
Elemer Lelik committed
64
65
, first_child(other.first_child)
, fromAll(other.fromAll)
66
67
68
, listPrint(other.listPrint)
, listMinOccurs(other.listMinOccurs)
, listMaxOccurs(other.listMaxOccurs)
Elemer Lelik's avatar
Elemer Lelik committed
69
70
71
72
73
74
75
76
77
, max_alt(other.max_alt)
, skipback(other.skipback)
, lastType(other.lastType)
, actualPath(other.actualPath)
, actfield(this)
, nameDep(other.nameDep)
, nillable_field(NULL)
, basefield(NULL)
, cmode(other.cmode)
Elemer Lelik's avatar
Elemer Lelik committed
78
79
, resolved(other.resolved)
, parentTypeSubsGroup(other.parentTypeSubsGroup) {
Elemer Lelik's avatar
Elemer Lelik committed
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  type.originalValueWoPrefix = other.type.originalValueWoPrefix;
  for (List<AttributeType*>::iterator attr = other.attribfields.begin(); attr; attr = attr->Next) {
    attribfields.push_back(new AttributeType(*attr->Data));
    attribfields.back()->parent = this;
  }

  for (List<ComplexType*>::iterator field = other.complexfields.begin(); field; field = field->Next) {
    complexfields.push_back(new ComplexType(*field->Data));
    complexfields.back()->parent = this;
    if(field->Data == other.basefield){
      basefield = complexfields.back();
    }else if(field->Data == other.nillable_field){
      nillable_field = complexfields.back();
    }
Elemer Lelik's avatar
Elemer Lelik committed
94
  }
Elemer Lelik's avatar
Elemer Lelik committed
95
96
97
98
99
100
101
102
103

  if (other.nameDep != NULL) {
    SimpleType* dep = other.nameDep;
    if(dep->getSubstitution() != NULL){
      dep->getSubstitution()->addToNameDepList(this);
      nameDep = dep->getSubstitution();
    }else {
      other.nameDep->addToNameDepList(this);
    }
Elemer Lelik's avatar
Elemer Lelik committed
104
105
106
  }
}

Elemer Lelik's avatar
Elemer Lelik committed
107
108
109
110
111
112
ComplexType::ComplexType(ComplexType * other)
: SimpleType(other->getParser(), other->getModule(), c_unknown)
, top(false)
, nillable(false)
, enumerated(false)
, embed(false)
Elemer Lelik's avatar
Elemer Lelik committed
113
, with_union(false)
Elemer Lelik's avatar
Elemer Lelik committed
114
115
, first_child(false)
, fromAll(false)
116
117
118
, listPrint(false)
, listMinOccurs(1)
, listMaxOccurs(1)
Elemer Lelik's avatar
Elemer Lelik committed
119
120
121
122
123
124
125
126
127
, max_alt(0)
, skipback(0)
, lastType()
, actualPath(empty_string)
, actfield(this)
, nameDep(NULL)
, nillable_field(NULL)
, basefield(NULL)
, cmode(CT_undefined_mode)
Elemer Lelik's avatar
Elemer Lelik committed
128
, resolved(No)
Elemer Lelik's avatar
Elemer Lelik committed
129
, parentTypeSubsGroup(NULL)
Elemer Lelik's avatar
Elemer Lelik committed
130
131
132
133
134
135
136
137
, complexfields()
, attribfields()
, enumfields()
, tagNames() {
  xsdtype = n_complexType;
  parent = other;
  outside_reference = ReferenceData();
}
Elemer Lelik's avatar
Elemer Lelik committed
138

Elemer Lelik's avatar
Elemer Lelik committed
139
140
141
142
143
144
145
146
147
ComplexType::ComplexType(const SimpleType & other, CT_fromST c)
: SimpleType(other)
, top(true)
, nillable(false)
, enumerated(false)
, embed(false)
, with_union(false)
, first_child(false)
, fromAll(false)
148
149
150
, listPrint(false)
, listMinOccurs(1)
, listMaxOccurs(1)
Elemer Lelik's avatar
Elemer Lelik committed
151
152
153
154
155
156
157
158
159
160
, max_alt(0)
, skipback(0)
, lastType()
, actualPath(empty_string)
, actfield(this)
, nameDep(NULL)
, nillable_field(NULL)
, basefield(NULL)
, cmode(CT_simpletype_mode)
, resolved(No)
Elemer Lelik's avatar
Elemer Lelik committed
161
, parentTypeSubsGroup(NULL)
Elemer Lelik's avatar
Elemer Lelik committed
162
163
164
165
166
, complexfields()
, attribfields()
, enumfields()
, tagNames() {

Elemer Lelik's avatar
Elemer Lelik committed
167
  if(c != fromTagSubstitution && c != fromTypeSubstitution){
Elemer Lelik's avatar
Elemer Lelik committed
168
169
    module->replaceLastMainType(this);
    module->setActualXsdConstruct(c_complexType);
Elemer Lelik's avatar
Elemer Lelik committed
170
  }
Elemer Lelik's avatar
Elemer Lelik committed
171
  construct = c_complexType;
Elemer Lelik's avatar
Elemer Lelik committed
172

Elemer Lelik's avatar
Elemer Lelik committed
173
174
  switch (c) {
    case fromTagUnion:
175
      type.upload(Mstring("union"), false);
Elemer Lelik's avatar
Elemer Lelik committed
176
177
178
179
180
      with_union = true;
      xsdtype = n_union;
      break;
    case fromTagNillable:
      addVariant(V_useNil);
181
      type.upload(Mstring("record"), false);
Elemer Lelik's avatar
Elemer Lelik committed
182
183
      break;
    case fromTagComplexType:
184
      type.upload(Mstring("record"), false);
Elemer Lelik's avatar
Elemer Lelik committed
185
186
      xsdtype = n_complexType;
      break;
Elemer Lelik's avatar
Elemer Lelik committed
187
    case fromTagSubstitution:
188
      type.upload(Mstring("union"), false);
Elemer Lelik's avatar
Elemer Lelik committed
189
190
191
192
      name.upload(getName().originalValueWoPrefix + Mstring("_group"));
      xsdtype = n_union;
      subsGroup = this;
      variant.clear();
Elemer Lelik's avatar
Elemer Lelik committed
193
      hidden_variant.clear();
Elemer Lelik's avatar
Elemer Lelik committed
194
195
196
197
198
199
      enumeration.modified = false;
      value.modified = false;
      pattern.modified = false;
      length.modified = false;
      whitespace.modified = false;
      break;
Elemer Lelik's avatar
Elemer Lelik committed
200
    case fromTypeSubstitution:
201
      type.upload(Mstring("union"), false);
Elemer Lelik's avatar
Elemer Lelik committed
202
203
204
205
206
207
208
209
210
211
212
      name.upload(getName().originalValueWoPrefix + Mstring("_derivations"));
      xsdtype = n_union;
      substitutionGroup = empty_string;
      typeSubsGroup = this;
      variant.clear();
      hidden_variant.clear();
      enumeration.modified = false;
      value.modified = false;
      pattern.modified = false;
      length.modified = false;
      whitespace.modified = false;
Elemer Lelik's avatar
Elemer Lelik committed
213
214
215
  }
}

Elemer Lelik's avatar
Elemer Lelik committed
216
217
218
219
220
221
ComplexType::~ComplexType() {
  for (List<ComplexType*>::iterator field = complexfields.begin(); field; field = field->Next) {
    delete field->Data;
    field->Data = NULL;
  }
  complexfields.clear();
Elemer Lelik's avatar
Elemer Lelik committed
222

Elemer Lelik's avatar
Elemer Lelik committed
223
224
225
226
227
  for (List<AttributeType*>::iterator field = attribfields.begin(); field; field = field->Next) {
    delete field->Data;
    field->Data = NULL;
  }
  attribfields.clear();
Elemer Lelik's avatar
Elemer Lelik committed
228
229
}

Elemer Lelik's avatar
Elemer Lelik committed
230
231
232
233
234
235
236
void ComplexType::loadWithValues() {
  //Find the last field where the tag is found
  if (this != actfield) {
    actfield->loadWithValues();
    return;
  }
  
Elemer Lelik's avatar
Elemer Lelik committed
237
  const XMLParser::TagAttributes & atts = parser->getActualTagAttributes();
Elemer Lelik's avatar
Elemer Lelik committed
238
239
240
241
242
243
  
  switch (parser->getActualTagName()) {
    case n_sequence:
      if (!top && xsdtype != n_sequence && xsdtype != n_complexType && xsdtype != n_extension && xsdtype != n_restriction && xsdtype != n_element) {
        //Create new record
        ComplexType * rec = new ComplexType(this);
244
        rec->type.upload(Mstring("record"), false);
Elemer Lelik's avatar
Elemer Lelik committed
245
246
247
248
249
250
251
252
253
254
255
        rec->name.upload(Mstring("sequence"));
        rec->addVariant(V_untagged);
        rec->setMinMaxOccurs(atts.minOccurs, atts.maxOccurs);
        rec->setXsdtype(n_sequence);
        complexfields.push_back(rec);
        actfield = rec;
      } else {
        //Do not create new record, it is an embedded sequence
        if (xsdtype == n_sequence && atts.minOccurs == 1 && atts.maxOccurs == 1) {
          skipback += 1;
        }
256
        type.upload(Mstring("record"), false);
Elemer Lelik's avatar
Elemer Lelik committed
257
258
259
        xsdtype = n_sequence;
        setMinMaxOccurs(atts.minOccurs, atts.maxOccurs);
      }
Elemer Lelik's avatar
Elemer Lelik committed
260
      break;
Elemer Lelik's avatar
Elemer Lelik committed
261
262
263
264
    case n_choice:
      if (!top || xsdtype != n_group) {
        //Create new union field
        ComplexType * choice = new ComplexType(this);
265
        choice->type.upload(Mstring("union"), false);
Elemer Lelik's avatar
Elemer Lelik committed
266
267
268
269
270
271
272
273
        choice->name.upload(Mstring("choice"));
        choice->setXsdtype(n_choice);
        choice->addVariant(V_untagged);
        choice->setMinMaxOccurs(atts.minOccurs, atts.maxOccurs);
        actfield = choice;
        complexfields.push_back(choice);
      } else {
        xsdtype = n_choice;
274
        type.upload(Mstring("union"), false);
Elemer Lelik's avatar
Elemer Lelik committed
275
276
277
      }
      break;
    case n_all:
Elemer Lelik's avatar
Elemer Lelik committed
278
    {
Elemer Lelik's avatar
Elemer Lelik committed
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
      //Create the record of enumerated field
      xsdtype = n_all;
      ComplexType * enumField = new ComplexType(this);
      enumField->setTypeValue(Mstring("enumerated"));
      enumField->setNameValue(Mstring("order"));
      enumField->setBuiltInBase(Mstring("string"));
      enumField->enumerated = true;
      enumField->setMinMaxOccurs(0, ULLONG_MAX, false);
      setMinMaxOccurs(atts.minOccurs, atts.maxOccurs);
      addVariant(V_useOrder);
      complexfields.push_back(enumField);
      if (atts.minOccurs == 0) {
        isOptional = true;
      }
      break;
    }
    case n_restriction:
      mode = restrictionMode;
      //If it is an xsd:union then call SimpleType::loadWithValues
298
      if (parent != NULL && parent->with_union && parent->hasVariant(Mstring("useUnion"))) {
Elemer Lelik's avatar
Elemer Lelik committed
299
300
301
302
303
304
305
306
307
308
309
310
311
        SimpleType::loadWithValues();
        break;
      }
      if (cmode == CT_simpletype_mode) {
        //if it is from a SimpleType, then create a base field
        ComplexType * f = new ComplexType(this);
        f->name.upload(Mstring("base"));
        f->type.upload(atts.base);
        f->setReference(atts.base);
        f->addVariant(V_untagged);
        complexfields.push_back(f);
        basefield = f;
        actfield = f;
312
313
314
315
316
317
        
        // If it is a restriction of a list, then no new basefield will be 
        // present, to we apply the references to the parent.
        if(parent != NULL && parent->inList) {
          parent->applyReference(*f, true);
        }
Elemer Lelik's avatar
Elemer Lelik committed
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
      } else if (cmode == CT_complextype_mode) {
        setReference(atts.base);
        xsdtype = n_restriction;
      }
      break;
    case n_extension:
      mode = extensionMode;
      if (cmode == CT_simpletype_mode) {
        //if it is from a SimpleType, then create a base field
        ComplexType * f = new ComplexType(this);
        f->name.upload(Mstring("base"));
        f->type.upload(atts.base);
        f->setReference(atts.base);
        f->addVariant(V_untagged);
        complexfields.push_back(f);
        basefield = f;
        actfield = f;
      } else if (cmode == CT_complextype_mode) {
        setReference(atts.base);
        xsdtype = n_extension;
      }
      break;
    case n_element:
Elemer Lelik's avatar
Elemer Lelik committed
341
    {
Elemer Lelik's avatar
Elemer Lelik committed
342
343
344
345
346
      if (atts.nillable) {
        if(cmode == CT_simpletype_mode){
          //If a simple top level element is nillable
          ComplexType * nilrec = new ComplexType(this);
          if (atts.type.empty()) {
347
            nilrec->type.upload(Mstring("record"), false);
Elemer Lelik's avatar
Elemer Lelik committed
348
349
350
351
352
353
354
355
          } else {
            nilrec->type.upload(atts.type);
          }
          nilrec->name.upload(Mstring("content"));
          nilrec->isOptional = true;
          nilrec->nillable = true;
          setMinMaxOccurs(atts.minOccurs, atts.maxOccurs);
          complexfields.push_back(nilrec);
356
          type.upload(Mstring("record"), false);
Elemer Lelik's avatar
Elemer Lelik committed
357
358
359
360
361
362
363
364
          name.upload(atts.name);
          actfield = nilrec;
          nillable_field = nilrec;
        } else {
          //From a complexType element is nillable
          ComplexType * record = new ComplexType(this);
          ComplexType * nilrec = new ComplexType(record);
          if (atts.type.empty()) {
365
            nilrec->type.upload(Mstring("record"), false);
Elemer Lelik's avatar
Elemer Lelik committed
366
367
368
369
          } else {
            nilrec->type.upload(atts.type);
          }
          record->name.upload(atts.name);
370
          record->type.upload(Mstring("record"), false);
Elemer Lelik's avatar
Elemer Lelik committed
371
372
373
374
375
376
377
378
379
380
381
          record->complexfields.push_back(nilrec);
          record->addVariant(V_useNil);
          record->nillable_field = nilrec;
          record->setMinMaxOccurs(atts.minOccurs, atts.maxOccurs);

          nilrec->name.upload(Mstring("content"));
          nilrec->nillable = true;
          nilrec->isOptional = true;
          nilrec->tagNames.push_back(parser->getActualTagName());
          complexfields.push_back(record);
          actfield = nilrec;
Elemer Lelik's avatar
Elemer Lelik committed
382
        }
Elemer Lelik's avatar
Elemer Lelik committed
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
      }else {
        //It is a simple element
        ComplexType* c = new ComplexType(this);
        c->setXsdtype(n_element);
        c->type.upload(atts.type);
        c->name.upload(atts.name);
        c->setReference(atts.type);
        c->setMinMaxOccurs(atts.minOccurs, atts.maxOccurs);
        c->applyDefaultAttribute(atts.default_);
        c->applyFixedAttribute(atts.fixed);
        c->setElementFormAs(atts.form);
        if (atts.ref.empty()) {
          c->setReference(atts.type);
        } else {
          c->applyRefAttribute(atts.ref);
          c->name.upload(atts.ref.getValueWithoutPrefix(':'));
          c->type.upload(atts.ref);
Elemer Lelik's avatar
Elemer Lelik committed
400
        }
Elemer Lelik's avatar
Elemer Lelik committed
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
        c->applySubstitionGroupAttribute(atts.substitionGroup);
        c->applyBlockAttribute(atts.block);
        actfield = c;

        //Inside all have some special conditions
        if (xsdtype == n_all) {
          if (atts.minOccurs > 1) {
            printError(getModule()->getSchemaname(), name.convertedValue,
              Mstring("Inside <all>, minOccurs must be 0 or 1"));
            TTCN3ModuleInventory::incrNumErrors();
          }
          if (atts.maxOccurs != 1) {
            printError(getModule()->getSchemaname(), name.convertedValue,
              Mstring("Inside <all>, maxOccurs must be 1"));
            TTCN3ModuleInventory::incrNumErrors();
          }
          c->fromAll = true;
          complexfields.push_back(c);
          if (isOptional) {
            c->isOptional = true;
          }
        } else {
          complexfields.push_back(c);
Elemer Lelik's avatar
Elemer Lelik committed
424
425
426
427
        }
      }
      break;
    }
Elemer Lelik's avatar
Elemer Lelik committed
428
    case n_attribute:
Elemer Lelik's avatar
Elemer Lelik committed
429
    {
Elemer Lelik's avatar
Elemer Lelik committed
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
      AttributeType * attribute = new AttributeType(this);
      attribute->addVariant(V_attribute);
      attribute->applyMinMaxOccursAttribute(0, 1);
      attribute->setXsdtype(n_attribute);
      attribute->applyDefaultAttribute(atts.default_);
      attribute->applyFixedAttribute(atts.fixed);
      attribute->setUseVal(atts.use);
      attribute->setAttributeFormAs(atts.form);
      lastType = n_attribute;
      if (atts.ref.empty()) {
        attribute->setNameOfField(atts.name);
        attribute->setTypeOfField(atts.type);
        attribute->setReference(atts.type, true);
      } else {
        attribute->applyRefAttribute(atts.ref);
Elemer Lelik's avatar
Elemer Lelik committed
445
      }
Elemer Lelik's avatar
Elemer Lelik committed
446
447
448
449
450
451
452
453
454
455
456
457
458
      actfield = attribute;
      
      //In case of nillable parent it is difficult...
      if (nillable && parent != NULL) {
        parent->attribfields.push_back(attribute);
        attribute->parent = parent;
      } else if (nillable && !complexfields.empty() && parent == NULL) {
        complexfields.back()->attribfields.push_back(attribute);
      } else if (parent != NULL && (parent->mode == extensionMode || parent->mode == restrictionMode) && name.convertedValue == Mstring("base")) {
        parent->attribfields.push_back(attribute);
        attribute->parent = parent;
      } else {
        attribfields.push_back(attribute);
Elemer Lelik's avatar
Elemer Lelik committed
459
      }
Elemer Lelik's avatar
Elemer Lelik committed
460
      break;
Elemer Lelik's avatar
Elemer Lelik committed
461
    }
Elemer Lelik's avatar
Elemer Lelik committed
462
463
464
465
    case n_any:
    {
      ComplexType * any = new ComplexType(this);
      any->name.upload(Mstring("elem"));
466
      any->type.upload(Mstring("string"), false);
Elemer Lelik's avatar
Elemer Lelik committed
467
468
469
470
471
      any->applyNamespaceAttribute(V_anyElement, atts.namespace_);
      any->setMinMaxOccurs(atts.minOccurs, atts.maxOccurs);
      any->setXsdtype(n_any);
      complexfields.push_back(any);
      break;
Elemer Lelik's avatar
Elemer Lelik committed
472
    }
Elemer Lelik's avatar
Elemer Lelik committed
473
    case n_anyAttribute:
Elemer Lelik's avatar
Elemer Lelik committed
474
    {
Elemer Lelik's avatar
Elemer Lelik committed
475
476
477
      AttributeType * anyattr = new AttributeType(this);
      anyattr->setXsdtype(n_anyAttribute);
      anyattr->setNameOfField(Mstring("attr"));
478
      anyattr->setTypeValue(Mstring("string"));
Elemer Lelik's avatar
Elemer Lelik committed
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
      anyattr->setToAnyAttribute();
      anyattr->applyMinMaxOccursAttribute(0, ULLONG_MAX);
      anyattr->addNameSpaceAttribute(atts.namespace_);
      actfield = anyattr;

      //In case of nillable parent it is difficult...
      if (nillable && parent != NULL) {
        parent->attribfields.push_back(anyattr);
        anyattr->parent = parent;
      } else if (nillable && !complexfields.empty() && parent == NULL) {
        complexfields.back()->attribfields.push_back(anyattr);
      } else if (parent != NULL && (parent->mode == extensionMode || parent->mode == restrictionMode) && name.convertedValue == Mstring("base")) {
        parent->attribfields.push_back(anyattr);
        anyattr->parent = parent;
      } else {
        attribfields.push_back(anyattr);
Elemer Lelik's avatar
Elemer Lelik committed
495
      }
Elemer Lelik's avatar
Elemer Lelik committed
496
      break;
Elemer Lelik's avatar
Elemer Lelik committed
497
    }
Elemer Lelik's avatar
Elemer Lelik committed
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
    case n_attributeGroup:
      if (!atts.ref.empty()) {
        ComplexType * g = new ComplexType(this);
        g->setXsdtype(n_attributeGroup);
        g->setReference(atts.ref);
        complexfields.push_back(g);
        actfield = g;
      } else {
        xsdtype = n_attributeGroup;
        name.upload(Mstring(atts.name));
        setInvisible();
      }
      break;
    case n_group:
      if (atts.ref.empty()) {
        //It is a definition
        xsdtype = n_group;
        name.upload(atts.name);
      } else {
        //It is a reference
        ComplexType* group = new ComplexType(this);
        group->setXsdtype(n_group);
        group->name.upload(atts.name);
        group->setReference(Mstring(atts.ref));
        group->setMinMaxOccurs(atts.minOccurs, atts.maxOccurs);
        complexfields.push_back(group);
        actfield = group;
      }
      break;
    case n_union:
Elemer Lelik's avatar
Elemer Lelik committed
528
    {
Elemer Lelik's avatar
Elemer Lelik committed
529
530
      with_union = true;
      xsdtype = n_union;
531
      type.upload(Mstring("union"), false);
Elemer Lelik's avatar
Elemer Lelik committed
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
      addVariant(V_useUnion);
      if (!atts.memberTypes.empty()) {
        List<Mstring> types;
        //Get the union values
        expstring_t valueToSplitIntoTokens = mcopystr(atts.memberTypes.c_str());
        char * token;
        token = strtok(valueToSplitIntoTokens, " ");
        while (token != NULL) {
          types.push_back(Mstring(token));
          token = strtok(NULL, " ");
        }
        Free(valueToSplitIntoTokens);
        
        //Create the union elements and push into the container
        for (List<Mstring>::iterator memberType = types.begin(); memberType; memberType = memberType->Next) {
          Mstring tmp_name = memberType->Data.getValueWithoutPrefix(':');
          ComplexType * f = new ComplexType(this);
          f->name.upload(tmp_name);
          f->type.upload(memberType->Data);
          f->setXsdtype(n_simpleType);
          f->setReference(memberType->Data);
          complexfields.push_back(f);
        }
Elemer Lelik's avatar
Elemer Lelik committed
555
      }
Elemer Lelik's avatar
Elemer Lelik committed
556
      break;
Elemer Lelik's avatar
Elemer Lelik committed
557
    }
Elemer Lelik's avatar
Elemer Lelik committed
558
559
    case n_simpleType:
    case n_simpleContent:
Elemer Lelik's avatar
Elemer Lelik committed
560
    {
Elemer Lelik's avatar
Elemer Lelik committed
561
562
563
      xsdtype = parser->getActualTagName();
      cmode = CT_simpletype_mode;
      Mstring fieldname;
564
      if (with_union && hasVariant(Mstring("useUnion"))) {
Elemer Lelik's avatar
Elemer Lelik committed
565
566
567
        if (max_alt == 0) {
          fieldname = Mstring("alt_");
        } else {
568
569
570
          expstring_t new_name = mprintf("alt_%d", max_alt);
          fieldname = new_name;
          Free(new_name);
Elemer Lelik's avatar
Elemer Lelik committed
571
572
573
574
575
576
577
578
        }
        max_alt++;
        ComplexType * field = new ComplexType(this);
        field->name.upload(fieldname);
        field->setXsdtype(n_simpleType);
        field->addVariant(V_nameAs, empty_string, true);
        complexfields.push_back(field);
        actfield = field;
Elemer Lelik's avatar
Elemer Lelik committed
579
      }
Elemer Lelik's avatar
Elemer Lelik committed
580
      break;
Elemer Lelik's avatar
Elemer Lelik committed
581
    }
Elemer Lelik's avatar
Elemer Lelik committed
582
583
    case n_complexType:
      name.upload(atts.name);
584
      type.upload(Mstring("record"), false);
Elemer Lelik's avatar
Elemer Lelik committed
585
586
587
588
589
590
591
592
593
594
      applyAbstractAttribute(atts.abstract);
      applySubstitionGroupAttribute(atts.substitionGroup);
      applyBlockAttribute(atts.block);
      // fall through
    case n_complexContent:
      tagNames.push_back(parser->getActualTagName());
      cmode = CT_complextype_mode;
      if (atts.mixed) {
        ComplexType * mixed = new ComplexType(this);
        mixed->name.upload(Mstring("embed_values"));
595
        mixed->type.upload(Mstring("string"), false);
Elemer Lelik's avatar
Elemer Lelik committed
596
597
598
599
600
601
602
        mixed->setMinMaxOccurs(0, ULLONG_MAX, false);
        mixed->embed = true;
        complexfields.push_back(mixed);
        addVariant(V_embedValues);
      }
      break;
    case n_list:
ebensza's avatar
ebensza committed
603
      if (parent != NULL && parent->basefield == this) {
604
605
606
607
608
609
610
611
612
613
614
615
616
617
        if (parent->getMaxOccurs() == 1) { // optional or minOccurs = maxOccurs = 1
          if (parent->getMinOccurs() == 0) {
            parent->isOptional = true;
            if (parent->parent != NULL && parent->parent->getXsdtype() == n_choice) {
              parent->listPrint = true;
              parent->listMinOccurs = parent->getMinOccurs();
              parent->listMaxOccurs = parent->getMaxOccurs();
            }
          }
        } else if (parent->parent != NULL){
          parent->listPrint = true;
          parent->listMinOccurs = parent->getMinOccurs();
          parent->listMaxOccurs = parent->getMaxOccurs();
        }
ebensza's avatar
ebensza committed
618
        parent->basefield = NULL;
619
        parent->SimpleType::loadWithValues();
ebensza's avatar
ebensza committed
620
        setInvisible();
621
      } else if(parent != NULL) {
622
623
624
625
626
627
628
629
630
631
632
633
634
635
        if (getMaxOccurs() == 1) { // optional or minOccurs = maxOccurs = 1
          if (getMinOccurs() == 0) {
            isOptional = true;
            if (parent->getXsdtype() == n_choice) {
              listPrint = true;
              listMinOccurs = getMinOccurs();
              listMaxOccurs = getMaxOccurs();
            }
          }
        } else {
          listPrint = true;
          listMinOccurs = getMinOccurs();
          listMaxOccurs = getMaxOccurs();
        }
636
        SimpleType::loadWithValues();
ebensza's avatar
ebensza committed
637
      }
638
      break;
Elemer Lelik's avatar
Elemer Lelik committed
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
    case n_length:
    case n_minLength:
    case n_maxLength:
    case n_pattern:
    case n_enumeration:
    case n_whiteSpace:
    case n_minInclusive:
    case n_maxInclusive:
    case n_minExclusive:
    case n_maxExclusive:
    case n_totalDigits:
    case n_fractionDigits:
      SimpleType::loadWithValues();
      break;
    case n_label:
      addComment(Mstring("LABEL:"));
      break;
    case n_definition:
      addComment(Mstring("DEFINITION:"));
      break;
    default:
      break;
Elemer Lelik's avatar
Elemer Lelik committed
661
662
663
664
  }
}

// called from endelementHandler
Elemer Lelik's avatar
Elemer Lelik committed
665
666
667
668
669
670
671
void ComplexType::modifyValues() {
  if (this != actfield) {
    actfield->modifyValues();
    return;
  }
  if (xsdtype == n_sequence) {
    skipback = skipback - 1;
Elemer Lelik's avatar
Elemer Lelik committed
672
673
  }

ebensza's avatar
ebensza committed
674
675
  if ( parent != NULL && 
      (xsdtype == n_element || 
Elemer Lelik's avatar
Elemer Lelik committed
676
677
678
679
680
681
682
683
684
685
       xsdtype == n_complexType || 
       xsdtype == n_complexContent || 
       xsdtype == n_all || 
       xsdtype == n_attribute || 
       xsdtype == n_anyAttribute ||
       xsdtype == n_choice || 
       xsdtype == n_group || 
       xsdtype == n_attributeGroup || 
       xsdtype == n_extension || 
       xsdtype == n_restriction || 
686
       (xsdtype == n_simpleType && !inList) || 
Elemer Lelik's avatar
Elemer Lelik committed
687
688
       xsdtype == n_simpleContent ||
       (xsdtype == n_sequence && skipback < 0)
ebensza's avatar
ebensza committed
689
      )) {
Elemer Lelik's avatar
Elemer Lelik committed
690
691
692
693
694
695
696
697
    if (!tagNames.empty() && tagNames.back() == parser->getParentTagName()) {
      if (nillable && tagNames.back() == n_element) {
        parent->modifyValues();
      }
      tagNames.pop_back();
    } else if (tagNames.empty()) {
      parent->actfield = parent;
      parent->lastType = xsdtype;
Elemer Lelik's avatar
Elemer Lelik committed
698
699
    }
  }
700
701
702
  if (xsdtype == n_simpleType) {
    inList = false;
  }
Elemer Lelik's avatar
Elemer Lelik committed
703
704
}

705
706
707
708
709
710
711
712
713
714
715
void ComplexType::modifyList() {
  if (this != actfield) {
    ((SimpleType*)actfield)->modifyList();
    return;
  }
  if (!inList && mode == listMode && parent != NULL) {
    parent->actfield = parent;
    parent->lastType = xsdtype;
  }
}

Elemer Lelik's avatar
Elemer Lelik committed
716
717
718
719
720
void ComplexType::referenceResolving() {
  if (resolved != No) return; // nothing to do
  if(this == subsGroup){
    resolved = Yes;
    return;
Elemer Lelik's avatar
Elemer Lelik committed
721
  }
Elemer Lelik's avatar
Elemer Lelik committed
722
723
724
725
  resolved = InProgress;
  for (List<ComplexType*>::iterator ct = complexfields.begin(); ct; ct = ct->Next) {
    // Referenece resolving of ComplexTypes
    ct->Data->referenceResolving();
Elemer Lelik's avatar
Elemer Lelik committed
726
  }
Elemer Lelik's avatar
Elemer Lelik committed
727
728
729
  for (List<AttributeType*>::iterator attr = attribfields.begin(); attr; attr = attr->Next) {
    //Reference resolving for Attributes
    resolveAttribute(attr->Data);
Elemer Lelik's avatar
Elemer Lelik committed
730
  }
Elemer Lelik's avatar
Elemer Lelik committed
731
732
733
  
  reference_resolving_funtion();
  
Elemer Lelik's avatar
Elemer Lelik committed
734
  if(!substitutionGroup.empty()){
Elemer Lelik's avatar
Elemer Lelik committed
735
    addToSubstitutions();
Elemer Lelik's avatar
Elemer Lelik committed
736
  }
Elemer Lelik's avatar
Elemer Lelik committed
737
  resolved = Yes;
Elemer Lelik's avatar
Elemer Lelik committed
738
739
}

Elemer Lelik's avatar
Elemer Lelik committed
740
741
742
void ComplexType::reference_resolving_funtion() {
  //Every child element references are resolved here.
  if (outside_reference.empty() && basefield == NULL) {
Elemer Lelik's avatar
Elemer Lelik committed
743
744
745
746
747
    //Its not in the resolveElement function because we need the built in type
    //reference too, and then the outside_reference is empty.
    if(xsdtype == n_element){
      collectElementTypes(NULL, NULL);
    }
Elemer Lelik's avatar
Elemer Lelik committed
748
    return;
Elemer Lelik's avatar
Elemer Lelik committed
749
750
  }

Elemer Lelik's avatar
Elemer Lelik committed
751
752
753
754
755
756
757
758
  SimpleType * st = (SimpleType*) TTCN3ModuleInventory::getInstance().lookup(this, want_BOTH);
  if (st == NULL && basefield == NULL) {
    printError(module->getSchemaname(), name.convertedValue,
      "Reference for a non-defined type: " + getReference().repr());
    TTCN3ModuleInventory::getInstance().incrNumErrors();
    outside_reference.set_resolved(NULL);
    return;
  }
Elemer Lelik's avatar
Elemer Lelik committed
759

Elemer Lelik's avatar
Elemer Lelik committed
760
  resolveAttributeGroup(st);
Elemer Lelik's avatar
Elemer Lelik committed
761

Elemer Lelik's avatar
Elemer Lelik committed
762
  resolveGroup(st);
Elemer Lelik's avatar
Elemer Lelik committed
763

Elemer Lelik's avatar
Elemer Lelik committed
764
  resolveElement(st);
Elemer Lelik's avatar
Elemer Lelik committed
765

Elemer Lelik's avatar
Elemer Lelik committed
766
  resolveSimpleTypeExtension();
Elemer Lelik's avatar
Elemer Lelik committed
767

Elemer Lelik's avatar
Elemer Lelik committed
768
  resolveSimpleTypeRestriction();
Elemer Lelik's avatar
Elemer Lelik committed
769

Elemer Lelik's avatar
Elemer Lelik committed
770
  resolveComplexTypeExtension();
Elemer Lelik's avatar
Elemer Lelik committed
771

Elemer Lelik's avatar
Elemer Lelik committed
772
  resolveComplexTypeRestriction();
Elemer Lelik's avatar
Elemer Lelik committed
773

Elemer Lelik's avatar
Elemer Lelik committed
774
  resolveUnion(st);
Elemer Lelik's avatar
Elemer Lelik committed
775

Elemer Lelik's avatar
Elemer Lelik committed
776
777
  addToTypeSubstitutions();

Elemer Lelik's avatar
Elemer Lelik committed
778
779
}

Elemer Lelik's avatar
Elemer Lelik committed
780
781
void ComplexType::setParent(ComplexType * par, SimpleType * child) {
  child->parent = par;
Elemer Lelik's avatar
Elemer Lelik committed
782
783
}

Elemer Lelik's avatar
Elemer Lelik committed
784
785
void ComplexType::applyReference(const SimpleType & other, const bool on_attributes) {
  type.convertedValue = other.getType().convertedValue;
Elemer Lelik's avatar
Elemer Lelik committed
786
  type.originalValueWoPrefix = other.getType().convertedValue.getValueWithoutPrefix(':');
Elemer Lelik's avatar
Elemer Lelik committed
787

788
789
  if (other.getMinOccurs() > getMinOccurs() ||
      other.getMaxOccurs() < getMaxOccurs()) {
Elemer Lelik's avatar
Elemer Lelik committed
790
791
792
793
794
795
    if (!on_attributes) {
      expstring_t temp = memptystr();
      temp = mputprintf(
        temp,
        "The occurrence range (%llu .. %llu) of the element (%s) is not compatible "
        "with the occurrence range (%llu .. %llu) of the referenced element.",
796
797
        getMinOccurs(),
        getMaxOccurs(),
Elemer Lelik's avatar
Elemer Lelik committed
798
799
800
801
802
803
        name.originalValueWoPrefix.c_str(),
        other.getMinOccurs(),
        other.getMaxOccurs());
      printError(module->getSchemaname(), parent->getName().originalValueWoPrefix,
        Mstring(temp));
      Free(temp);
Elemer Lelik's avatar
Elemer Lelik committed
804
805
      TTCN3ModuleInventory::getInstance().incrNumErrors();
    }
Elemer Lelik's avatar
Elemer Lelik committed
806
  } else {
807
808
    setMinOccurs(llmax(getMinOccurs(), other.getMinOccurs()));
    setMaxOccurs(llmin(getMaxOccurs(), other.getMaxOccurs()));
Elemer Lelik's avatar
Elemer Lelik committed
809
810
  }

Elemer Lelik's avatar
Elemer Lelik committed
811
812
813
814
815
  for (List<Mstring>::iterator var = other.getVariantRef().begin(); var; var = var->Next) {
    bool found = false;
    for (List<Mstring>::iterator var1 = variant.begin(); var1; var1 = var1->Next) {
      if (var->Data == var1->Data) {
        found = true;
Elemer Lelik's avatar
Elemer Lelik committed
816
817
818
        break;
      }
    }
Elemer Lelik's avatar
Elemer Lelik committed
819
820
821
    if (!found) {
      variant.push_back(var->Data);
      variant_ref.push_back(var->Data);
Elemer Lelik's avatar
Elemer Lelik committed
822
823
824
    }
  }

Elemer Lelik's avatar
Elemer Lelik committed
825
  builtInBase = other.getBuiltInBase();
Elemer Lelik's avatar
Elemer Lelik committed
826

Elemer Lelik's avatar
Elemer Lelik committed
827
828
829
830
831
  length.applyReference(other.getLength());
  pattern.applyReference(other.getPattern());
  enumeration.applyReference(other.getEnumeration());
  whitespace.applyReference(other.getWhitespace());
  value.applyReference(other.getValue());
Elemer Lelik's avatar
Elemer Lelik committed
832
833
}

Elemer Lelik's avatar
Elemer Lelik committed
834
835
836
837
838
839
840
841
842
843
844
845
void ComplexType::nameConversion(NameConversionMode conversion_mode, const List<NamespaceType> & ns) {
  if(!visible) return;
  switch (conversion_mode) {
    case nameMode:
      nameConversion_names(ns);
      break;
    case typeMode:
      nameConversion_types(ns);
      break;
    case fieldMode:
      nameConversion_fields(ns);
      break;
Elemer Lelik's avatar
Elemer Lelik committed
846
847
848
  }
}

Elemer Lelik's avatar
Elemer Lelik committed
849
void ComplexType::nameConversion_names(const List<NamespaceType> &) {
Elemer Lelik's avatar
Elemer Lelik committed
850
851
852
853
  Mstring res, var(module->getTargetNamespace());
  XSDName2TTCN3Name(name.convertedValue, TTCN3ModuleInventory::getInstance().getTypenames(), type_name, res, var);
  name.convertedValue = res;
  bool found = false;
Elemer Lelik's avatar
Elemer Lelik committed
854
  for (List<Mstring>::iterator vari = variant.begin(); vari; vari = vari->Next) {
Elemer Lelik's avatar
Elemer Lelik committed
855
856
857
858
859
860
861
862
    if (vari->Data == "\"untagged\"") {
      found = true;
      break;
    }
  }
  if (!found) {
    addVariant(V_onlyValue, var);
  }
Elemer Lelik's avatar
Elemer Lelik committed
863
864
  for (List<SimpleType*>::iterator dep = nameDepList.begin(); dep; dep = dep->Next) {
    dep->Data->setTypeValue(res);
Elemer Lelik's avatar
Elemer Lelik committed
865
866
867
  }
}

Elemer Lelik's avatar
Elemer Lelik committed
868
869
870
871
872
873
874
875
876
877
878
879
void ComplexType::nameConversion_types(const List<NamespaceType> & ns) {
  attribfields.sort(compareAttributeNameSpaces);
  attribfields.sort(compareAttributeTypes);
  for (List<AttributeType*>::iterator field = attribfields.begin(); field; field = field->Next) {
    field->Data->nameConversion(typeMode, ns);
  }

  for (List<ComplexType*>::iterator field = complexfields.begin(); field; field = field->Next) {
    field->Data->nameConversion_types(ns);
  }

  Mstring prefix, uri, typeValue;
Elemer Lelik's avatar
Elemer Lelik committed
880
881
882
883

  if (type.convertedValue == "record" ||
    type.convertedValue == "set" ||
    type.convertedValue == "union" ||
Elemer Lelik's avatar
Elemer Lelik committed
884
    type.convertedValue == "enumerated") {
Elemer Lelik's avatar
Elemer Lelik committed
885
    return;
Elemer Lelik's avatar
Elemer Lelik committed
886
  }
Elemer Lelik's avatar
Elemer Lelik committed
887
888

  prefix = type.convertedValue.getPrefix(':');
Elemer Lelik's avatar
Elemer Lelik committed
889
  typeValue = type.convertedValue.getValueWithoutPrefix(':');
Elemer Lelik's avatar
Elemer Lelik committed
890

Elemer Lelik's avatar
Elemer Lelik committed
891
  for (List<NamespaceType>::iterator namesp = ns.begin(); namesp; namesp = namesp->Next) {
Elemer Lelik's avatar
Elemer Lelik committed
892
893
894
895
896
897
    if (prefix == namesp->Data.prefix) {
      uri = namesp->Data.uri;
      break;
    }
  }

Elemer Lelik's avatar
Elemer Lelik committed
898
  QualifiedName in(uri, typeValue); // ns uri + original name
Elemer Lelik's avatar
Elemer Lelik committed
899
900
901

  // Check all known types
  QualifiedNames::iterator origTN = TTCN3ModuleInventory::getInstance().getTypenames().begin();
Elemer Lelik's avatar
Elemer Lelik committed
902
  for (; origTN; origTN = origTN->Next) {
Elemer Lelik's avatar
Elemer Lelik committed
903
904
    if (origTN->Data == in) {
      QualifiedName tmp_name(module->getTargetNamespace(), name.convertedValue);
Elemer Lelik's avatar
Elemer Lelik committed
905
      if (origTN->Data != tmp_name){
Elemer Lelik's avatar
Elemer Lelik committed
906
        break;
Elemer Lelik's avatar
Elemer Lelik committed
907
      }
Elemer Lelik's avatar
Elemer Lelik committed
908
909
910
911
912
    }
  }

  if (origTN != NULL) {
    setTypeValue(origTN->Data.name);
Elemer Lelik's avatar
Elemer Lelik committed
913
  } else {
Elemer Lelik's avatar
Elemer Lelik committed
914
    Mstring res, var;
Elemer Lelik's avatar
Elemer Lelik committed
915
    XSDName2TTCN3Name(typeValue, TTCN3ModuleInventory::getInstance().getTypenames(), type_reference_name, res, var, type.no_replace);
Elemer Lelik's avatar
Elemer Lelik committed
916
917
918
919
    setTypeValue(res);
  }
}

Elemer Lelik's avatar
Elemer Lelik committed
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
void ComplexType::nameConversion_fields(const List<NamespaceType> & ns) {
  QualifiedNames used_field_names;
  
  for (List<AttributeType*>::iterator field = attribfields.begin(); field; field = field->Next) {
    field->Data->nameConversion_names(used_field_names);
  }

  for (List<ComplexType*>::iterator field = complexfields.begin(); field; field = field->Next) {
    if (field->Data->getMinOccurs() == 0 && field->Data->getMaxOccurs() == 0) {
      continue;
    }
    if (!field->Data->isVisible()) {
      continue;
    }
    
    field->Data->nameConversion_fields(ns);
Elemer Lelik's avatar
Elemer Lelik committed
936
937

    Mstring prefix = field->Data->getType().convertedValue.getPrefix(':');
Elemer Lelik's avatar
Elemer Lelik committed
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
    Mstring typeValue = field->Data->getType().convertedValue.getValueWithoutPrefix(':');

    Mstring res, var;
    var = getModule()->getTargetNamespace();
    XSDName2TTCN3Name(typeValue, TTCN3ModuleInventory::getInstance().getTypenames(), type_reference_name, res, var);

    field->Data->addVariant(V_onlyValue, var);
    var = getModule()->getTargetNamespace();

    if (field->Data->getName().list_extension) {
      field->Data->useNameListProperty();
      XSDName2TTCN3Name(field->Data->getName().convertedValue,
        used_field_names, field_name, res, var);
      field->Data->setNameValue(res);
      bool found_in_variant = false;
      for (List<Mstring>::iterator vari = field->Data->getVariant().begin(); vari; vari = vari->Next) {
        if (vari->Data == Mstring("\"untagged\"")) {
          found_in_variant = true;
          break;
        }
      }
      if (!field->Data->getName().originalValueWoPrefix.empty() &&
        field->Data->getName().originalValueWoPrefix != "sequence" &&
        field->Data->getName().originalValueWoPrefix != "choice" &&
        field->Data->getName().originalValueWoPrefix != "elem" &&
        !found_in_variant) {
        field->Data->addVariant(V_nameAs, field->Data->getName().originalValueWoPrefix);
Elemer Lelik's avatar
Elemer Lelik committed
965
966
      }

Elemer Lelik's avatar
Elemer Lelik committed
967
968
969
970
971
972
973
974
975

      if (!found_in_variant) {
        field->Data->addVariant(V_untagged, empty_string, true);
      }
    } else {
      XSDName2TTCN3Name(field->Data->getName().convertedValue,
        used_field_names, field_name, res, var);
      field->Data->setNameValue(res);
      field->Data->addVariant(V_onlyValue, var);
Elemer Lelik's avatar
Elemer Lelik committed
976
    }
Elemer Lelik's avatar
Elemer Lelik committed
977
978
979
980
981
982
983
984

  }
}

void ComplexType::setFieldPaths(Mstring path) {
  if (path.empty()) {
    if (!top) {
      Mstring field_prefix = empty_string;
985
      if(parent->getMinOccurs() == 0 && parent->getMaxOccurs() == ULLONG_MAX){
Elemer Lelik's avatar
Elemer Lelik committed
986
        field_prefix = "[-].";
Elemer Lelik's avatar
Elemer Lelik committed
987
      }
Elemer Lelik's avatar
Elemer Lelik committed
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
      path = field_prefix + getName().convertedValue;
      actualPath = field_prefix + getName().convertedValue;
    }else {
      actualPath = getName().convertedValue;
    }
  } else if (parent != NULL && (parent->getMinOccurs() != 1 || parent->getMaxOccurs() != 1) &&
             (parent->getName().list_extension || parent->mode == listMode)) {
    path = path + Mstring("[-].") + getName().convertedValue;
    actualPath = path;
  } else {
    path = path + Mstring(".") + getName().convertedValue;
    actualPath = path;
  }

  for (List<ComplexType*>::iterator field = complexfields.begin(); field; field = field->Next) {
    field->Data->setFieldPaths(path);
  }
  for (List<AttributeType*>::iterator attr = attribfields.begin(); attr; attr = attr->Next) {
    attr->Data->setFieldPath(path);
  }
}

void ComplexType::finalModification2() {  
  //Call SimpleType finalModification
  SimpleType::finalModification();
1013
  
Elemer Lelik's avatar
Elemer Lelik committed
1014
  //Set isOptional field
1015
  isOptional = isOptional || (getMinOccurs() == 0 && getMaxOccurs() == 1);
Elemer Lelik's avatar
Elemer Lelik committed
1016
1017
1018
1019
1020
1021
  
  //
  List<Mstring> enumNames;
  for (List<ComplexType*>::iterator field = complexfields.begin(), nextField; field; field = nextField) {
    nextField = field->Next;
    //Remove invisible fields
1022
    if ((field->Data->getMinOccurs() == 0 && field->Data->getMaxOccurs() == 0) || !field->Data->isVisible()) {
Elemer Lelik's avatar
Elemer Lelik committed
1023
1024
1025
1026
1027
1028
1029
1030
1031
      delete field->Data;
      field->Data = NULL;
      complexfields.remove(field);
    } else {
      //Recursive call
      field->Data->finalModification2();
      //collect <xsd:all> elements
      if (field->Data->fromAll) {
        enumNames.push_back(field->Data->getName().convertedValue);
Elemer Lelik's avatar
Elemer Lelik committed
1032
1033
      }
    }
Elemer Lelik's avatar
Elemer Lelik committed
1034
  }
Elemer Lelik's avatar
Elemer Lelik committed
1035

Elemer Lelik's avatar
Elemer Lelik committed
1036
1037
  ComplexType * embedField = NULL;
  ComplexType * enumField = NULL;
Elemer Lelik's avatar
Elemer Lelik committed
1038

Elemer Lelik's avatar
Elemer Lelik committed
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
  //Find the embed and order fields, and remove them
  for (List<ComplexType*>::iterator field = complexfields.begin(), nextField; field; field = nextField) {
    nextField = field->Next;
    if (field->Data->embed) {
      embedField = new ComplexType(*field->Data);
      embedField->parent = this;
      delete field->Data;
      field->Data = NULL;
      complexfields.remove(field);
    } else if (field->Data->enumerated) {
      enumField = new ComplexType(*field->Data);
      enumField->parent = this;
      delete field->Data;
      field->Data = NULL;
      complexfields.remove(field);
    }
  }
Elemer Lelik's avatar
Elemer Lelik committed
1056

Elemer Lelik's avatar
Elemer Lelik committed
1057
1058
1059
1060
1061
1062
  if (enumField != NULL) {
    //Insert the order field in the front
    complexfields.push_front(enumField);
    //Push the field names into the order field
    for (List<Mstring>::iterator field = enumNames.begin(); field; field = field->Next) {
      enumField->enumfields.push_back(field->Data);
Elemer Lelik's avatar
Elemer Lelik committed
1063
    }
Elemer Lelik's avatar
Elemer Lelik committed
1064
  }
Elemer Lelik's avatar
Elemer Lelik committed
1065

Elemer Lelik's avatar
Elemer Lelik committed
1066
1067
1068
1069
  if (embedField != NULL) {
    //Insert the embed field to the front
    complexfields.push_front(embedField);
  }
Elemer Lelik's avatar
Elemer Lelik committed
1070

Elemer Lelik's avatar
Elemer Lelik committed
1071
1072
1073
1074
1075
1076
1077
  if (with_union) {
    unsigned number = 0;
    for (List<ComplexType*>::iterator field = complexfields.begin(); field; field = field->Next) {
      if (field->Data->name.convertedValue.foundAt("alt_") == field->Data->name.convertedValue.c_str()) {
        if (number == 0) {
          field->Data->name.upload(Mstring("alt_"));
        } else {
1078
1079
1080
          expstring_t new_name = mprintf("alt_%d", number);
          field->Data->name.upload(Mstring(new_name));
          Free(new_name);
Elemer Lelik's avatar
Elemer Lelik committed
1081
        }
Elemer Lelik's avatar
Elemer Lelik committed
1082
        number++;
Elemer Lelik's avatar
Elemer Lelik committed
1083
      }
Elemer Lelik's avatar
Elemer Lelik committed
1084
1085
    }
  }
Elemer Lelik's avatar
Elemer Lelik committed
1086

Elemer Lelik's avatar
Elemer Lelik committed
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
  AttributeType * anyAttr = NULL;
  for (List<AttributeType*>::iterator field = attribfields.begin(), nextField; field; field = nextField) {
    nextField = field->Next;
    field->Data->applyUseAttribute();
    //Find anyattribute, and remove it
    if (field->Data->isAnyAttribute()) {
      anyAttr = new AttributeType(*field->Data);
      setParent(this, anyAttr);
      delete field->Data;
      field->Data = NULL;
      attribfields.remove(field);
    } else if (field->Data->getUseVal() == prohibited || !field->Data->isVisible()) {
      //Not visible attribute removed
      delete field->Data;
      field->Data = NULL;
      attribfields.remove(field);
    } else {
      field->Data->SimpleType::finalModification();
    }
  }
  
  //Push anyattribute to the front
  if (anyAttr != NULL) {
    anyAttr->applyNamespaceAttribute(V_anyAttributes);
    attribfields.push_back(anyAttr);
  }

  //Substitution group ordering
Elemer Lelik's avatar
Elemer Lelik committed
1115
  if(subsGroup == this || typeSubsGroup == this){ //We are a generated substitution group
Elemer Lelik's avatar
Elemer Lelik committed
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
    //Substitution group never empty
    ComplexType * front = complexfields.front();
    List<ComplexType*>::iterator it = complexfields.begin();
    complexfields.remove(it);
    complexfields.sort(compareComplexTypeNameSpaces);
    complexfields.sort(compareTypes);
    complexfields.push_front(front);
  }
}

void ComplexType::finalModification() {
  finalModification2();
  setFieldPaths(empty_string);
  List<Mstring> container;
  collectVariants(container);
  variant.clear();
  variant = container;
}

void ComplexType::printToFile(FILE * file) {
  printToFile(file, 0, false);
}

void ComplexType::printToFile(FILE * file, const unsigned level, const bool is_union) {
  if (!isVisible()) {
    return;
  }
  printComment(file, level);
  if (top) {
    fprintf(file, "type ");
    if(mode == listMode){
      printMinOccursMaxOccurs(file, is_union);
      fprintf(file, "%s", type.convertedValue.c_str());
    }else {
      fprintf(file, "%s %s", type.convertedValue.c_str(), name.convertedValue.c_str());
    }
    fprintf(file, "\n{\n");

    if (attribfields.empty() && complexfields.empty()) {
      fprintf(file, "\n");
    }

    for (List<ComplexType*>::iterator c = complexfields.begin(), nextField; c; c = nextField) {
      nextField = c->Next;
      if (c->Data->embed || c->Data->enumerated) {
        c->Data->printToFile(file, level + 1, is_union);
        if (c->Next != NULL || !attribfields.empty()) {
          fprintf(file, ",\n");
        } else {
          fprintf(file, "\n");
Elemer Lelik's avatar
Elemer Lelik committed
1166
        }
Elemer Lelik's avatar
Elemer Lelik committed
1167
1168
1169
        delete c->Data;
        c->Data = NULL;
        complexfields.remove(c);
Elemer Lelik's avatar
Elemer Lelik committed
1170
      }
Elemer Lelik's avatar
Elemer Lelik committed
1171
1172
1173
1174
1175
1176
1177
1178
    }

    for (List<AttributeType*>::iterator f = attribfields.begin(); f; f = f->Next) {
      f->Data->printToFile(file, level + 1);
      if (f->Next != NULL || !complexfields.empty()) {
        fprintf(file, ",\n");
      } else {
        fprintf(file, "\n");
Elemer Lelik's avatar
Elemer Lelik committed
1179
1180
      }
    }
Elemer Lelik's avatar
Elemer Lelik committed
1181
1182
1183
1184
1185
1186
1187

    for (List<ComplexType*>::iterator c = complexfields.begin(); c; c = c->Next) {
      c->Data->printToFile(file, level + 1, is_union);
      if (c->Next != NULL) {
        fprintf(file, ",\n");
      } else {
        fprintf(file, "\n");
Elemer Lelik's avatar
Elemer Lelik committed
1188
1189
      }
    }
Elemer Lelik's avatar
Elemer Lelik committed
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
  } else {
    const bool field_is_record = getType().convertedValue == Mstring("record");
    const bool field_is_union = getType().convertedValue == "union";
    if (complexfields.empty() && attribfields.empty() && (field_is_record || field_is_union)) {
      if (field_is_record) {
        indent(file, level);
        printMinOccursMaxOccurs(file, is_union);
        fprintf(file, "%s {\n", getType().convertedValue.c_str());
        indent(file, level);
        fprintf(file, "} %s", getName().convertedValue.c_str());
        if (isOptional) {
          fprintf(file, " optional");
        }
      } else if (field_is_union) {
        indent(file, level);
        printMinOccursMaxOccurs(file, is_union);
        fprintf(file, "%s {\n", getType().convertedValue.c_str());
        indent(file, level + 1);
        fprintf(file, "record length(0 .. 1) of enumerated { NULL_ } choice\n");
        indent(file, level);
        fprintf(file, "} %s", getName().convertedValue.c_str());
        if (isOptional) {
          fprintf(file, " optional");
        }
      }
    } else {
      indent(file, level);
      if (getEnumeration().modified) {
        if (isFloatType(getBuiltInBase())) {
          fprintf(file, "%s (", type.convertedValue.c_str());
          getEnumeration().sortFacets();
          getEnumeration().printToFile(file);
          fprintf(file, ")");
        } else {
          printMinOccursMaxOccurs(file, with_union);
          fprintf(file, "enumerated {\n");
          //getEnumeration().sortFacets();
          getEnumeration().printToFile(file, level);
          fprintf(file, "\n");
          indent(file, level);
          fprintf(file, "} ");
        }
      } else {
        int multiplicity = multi(module, getReference(), this);
        if ((multiplicity > 1) && getReference().get_ref()) {
          fprintf(file, "%s.", getReference().get_ref()->getModule()->getModulename().c_str());
        }
1237
1238
1239
1240
1241
1242
1243
        if (field_is_record || field_is_union || listPrint) {
          unsigned long long int tempMin = getMinOccurs();
          unsigned long long int tempMax = getMaxOccurs();
          if (listPrint) {
            setMinOccurs(listMinOccurs);
            setMaxOccurs(listMaxOccurs);
          }
Elemer Lelik's avatar
Elemer Lelik committed
1244
          printMinOccursMaxOccurs(file, with_union, !first_child || parent->getXsdtype() != n_choice);
1245
1246
1247
          if (listPrint) {
            setMinOccurs(tempMin);
            setMaxOccurs(tempMax);
Elemer Lelik's avatar
Elemer Lelik committed
1248
          }
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
          if (listPrint && complexfields.size() == 0) {
            printMinOccursMaxOccurs(file, false);
            fprintf(file, "%s ",getType().convertedValue.c_str());
          } else {
            fprintf(file, "%s {\n", getType().convertedValue.c_str());
            for (List<AttributeType*>::iterator f = attribfields.begin(); f; f = f->Next) {
              f->Data->printToFile(file, level + 1);
              if (f->Next != NULL || !complexfields.empty()) {
                fprintf(file, ",\n");
              } else {
                fprintf(file, "\n");
              }
            }
Elemer Lelik's avatar
Elemer Lelik committed
1262

1263
1264
1265
1266
1267
1268
1269
            for (List<ComplexType*>::iterator c = complexfields.begin(); c; c = c->Next) {
              c->Data->printToFile(file, level + 1, is_union);
              if (c->Next != NULL) {
                fprintf(file, ",\n");
              } else {
                fprintf(file, "\n");
              }
Elemer Lelik's avatar
Elemer Lelik committed
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
            }
          }
        } else {
          printMinOccursMaxOccurs(file, with_union, !first_child);
          fprintf(file, "%s ", getType().convertedValue.c_str());
          if (getName().convertedValue == Mstring("order") && getType().convertedValue == Mstring("enumerated")) {
            fprintf(file, "{\n");
            for (List<Mstring>::iterator e = enumfields.begin(); e; e = e->Next) {
              indent(file, level + 1);
              fprintf(file, "%s", e->Data.c_str());
              if (e->Next != NULL) {
                fprintf(file, ",\n");
              } else {
                fprintf(file, "\n");
              }
            }
            indent(file, level);
            fprintf(file, "} ");
          }
        }
Elemer Lelik's avatar
Elemer Lelik committed
1290
      }
1291
      if ((field_is_record || field_is_union) && !listPrint) {
Elemer Lelik's avatar
Elemer Lelik committed
1292
1293
        indent(file, level);
        fprintf(file, "} ");
Elemer Lelik's avatar
Elemer Lelik committed
1294
      }
Elemer Lelik's avatar
Elemer Lelik committed
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309

      fprintf(file, "%s", getName().convertedValue.c_str());
      getPattern().printToFile(file);
      getValue().printToFile(file);
      getLength().printToFile(file);
      if (!with_union && isOptional) {
        fprintf(file, " optional");
      }
    }
  }

  if (top) {
    fprintf(file, "}");
    if(mode == listMode){
      fprintf(file, " %s", name.convertedValue.c_str());
Elemer Lelik's avatar
Elemer Lelik committed
1310
    }
Elemer Lelik's avatar
Elemer Lelik committed
1311
1312
    printVariant(file);
    fprintf(file, ";\n\n\n");
Elemer Lelik's avatar
Elemer Lelik committed
1313
1314
1315
  }
}

Elemer Lelik's avatar
Elemer Lelik committed
1316
1317
1318
1319
1320
1321
1322
1323
1324
void ComplexType::collectVariants(List<Mstring>& container) {

  if (e_flag_used || !isVisible()) {
    return;
  }

  if (top) {
    bool useUnionVariantWhenMainTypeIsRecordOf = false;
    for (List<Mstring>::iterator var = variant.end(); var; var = var->Prev) {
1325
      if ((getMinOccurs() != 1 || getMaxOccurs() != 1) && (var->Data == "\"useUnion\"")) { // main type is a record of
Elemer Lelik's avatar
Elemer Lelik committed
1326
1327
1328
1329
1330
1331
1332
1333
        useUnionVariantWhenMainTypeIsRecordOf = true; // TR HL15893
      } else {
        container.push_back(Mstring("variant ") + Mstring(var->Data.c_str()) + Mstring(";\n"));
      }
    }
    if (useUnionVariantWhenMainTypeIsRecordOf) {
      container.push_back(Mstring("variant ([-]) \"useUnion\";\n"));
    }
Elemer Lelik's avatar
Elemer Lelik committed
1334
1335
1336
    for (List<Mstring>::iterator var = hidden_variant.end(); var; var = var->Prev) {
      container.push_back(Mstring("//variant ") + Mstring(var->Data.c_str()) + Mstring(";\n"));
    }
Elemer Lelik's avatar
Elemer Lelik committed
1337
1338
1339
1340
1341
1342
1343
1344
1345
  }

  //Collect variants of attributes
  for (List<AttributeType*>::iterator field = attribfields.begin(); field; field = field->Next) {
    field->Data->collectVariants(container);
  }

  for (List<ComplexType*>::iterator field = complexfields.begin(); field; field = field->Next) {

Elemer Lelik's avatar
Elemer Lelik committed
1346
1347
1348
    if (!field->Data->isVisible()) {
      continue;
    }
Elemer Lelik's avatar
Elemer Lelik committed
1349
1350
1351
1352

    if (field->Data->getVariant().empty() && field->Data->getHiddenVariant().empty() &&
        field->Data->complexfields.empty() && field->Data->attribfields.empty() &&
        field->Data->enumeration.variants.empty()) {
Elemer Lelik's avatar
Elemer Lelik committed
1353
1354
1355
      continue;
    }

Elemer Lelik's avatar
Elemer Lelik committed
1356
    bool already_used = false;
Elemer Lelik's avatar
Elemer Lelik committed
1357

Elemer Lelik's avatar
Elemer Lelik committed
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
    for (List<Mstring>::iterator var2 = field->Data->getVariant().end(); var2; var2 = var2->Prev) {
      if (var2->Data == "\"untagged\"" && !already_used) {
        container.push_back(Mstring("variant (") + field->Data->actualPath + Mstring(") ") + Mstring(var2->Data.c_str()) + Mstring(";\n"));
        already_used = true;
      } else {
        if ((field->Data->getMinOccurs() != 1 || field->Data->getMaxOccurs() != 1) &&
          (field->Data->getName().list_extension || var2->Data == "\"useUnion\"")) {
          container.push_back(Mstring("variant (") + field->Data->actualPath + Mstring("[-]) ") + Mstring(var2->Data.c_str()) + Mstring(";\n"));
        } else if (var2->Data != "\"untagged\"") {
          container.push_back(Mstring("variant (") + field->Data->actualPath + Mstring(") ") + Mstring(var2->Data.c_str()) + Mstring(";\n"));
        }
      }
Elemer Lelik's avatar
Elemer Lelik committed
1370
    }
Elemer Lelik's avatar
Elemer Lelik committed
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
    for (List<Mstring>::iterator hidden_var = field->Data->getHiddenVariant().end();
      hidden_var; hidden_var = hidden_var->Prev) {
      if ((field->Data->getMinOccurs() != 1 || field->Data->getMaxOccurs() != 1) &&
        field->Data->g