exip  Alpha 0.5.4
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
treeTableToGrammars.c
Go to the documentation of this file.
1 /*==================================================================*\
2 | EXIP - Embeddable EXI Processor in C |
3 |--------------------------------------------------------------------|
4 | This work is licensed under BSD 3-Clause License |
5 | The full license terms and conditions are located in LICENSE.txt |
6 \===================================================================*/
7 
18 #include "treeTableSchema.h"
19 #include "stringManipulate.h"
20 #include "genUtils.h"
21 #include "memManagement.h"
22 #include "initSchemaInstance.h"
23 #include "grammars.h"
24 
25 #define DEFAULT_GLOBAL_QNAME_COUNT 200
26 
27 // TODO: check if this empty grammar is needed?
28 // Also this is platform dependent and must be fixed! - maybe auto-generation?
29 static Production static_grammar_prod_empty[1] = {{0x28FFFFFF, INDEX_MAX, {URI_MAX, LN_MAX}}};
30 static GrammarRule static_grammar_rule_empty[1] = {{static_grammar_prod_empty, 1, 0x01}};
31 static EXIGrammar static_grammar_empty = {static_grammar_rule_empty, 0x42000000, 1};
32 
34 static EXIPSchema* globalSchemaPtr;
35 
37 {
41 };
42 
44 
50 {
53  Index emptyGrIndex; // The empty grammar index in the grammar table
55  AllocList tmpMemList; // Temporary allocations during the schema creation
59 };
60 
61 typedef struct buildContext BuildContext;
62 
65 {
69 };
70 
73 {
77 };
78 
79 // Functions for handling of schema elements (defined in the global scope)
80 // START
88 static errorCode handleElementEl(BuildContext* ctx, QualifiedTreeTableEntry* treeTEntry, boolean isGlobal, QNameIDGrIndx* qNmGrIndex);
89 
95 static errorCode handleSimpleTypeEl(BuildContext* ctx, QualifiedTreeTableEntry* stEntry);
96 
102 static errorCode handleComplexTypeEl(BuildContext* ctx, QualifiedTreeTableEntry* ctEntry);
103 
104 // END - handling of schema elements
105 
106 // Functions for converting schema definitions to protogrammars
107 // START
108 
116 static errorCode getContentTypeProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* contEntry, ProtoGrammar** content);
117 
125 static errorCode getAttributeUseProtoGrammars(BuildContext* ctx, QualifiedTreeTableEntry* attrEntry, ProtoGrammarArray* attrUseArray, String** attrWildcardNS, struct localAttrNames* aNamesTbl);
126 
132 static errorCode getElementTermProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* elementEntry, QNameIDGrIndx qGrIndex, ProtoGrammar** elTerm);
133 
140 static errorCode getAttributeProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* attrEntry, boolean isGlobal, boolean isRequired, ProtoGrammar** attr);
141 
146 static errorCode getSimpleTypeProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* simpleEntry, ProtoGrammar** simplType);
147 
152 static errorCode getSimpleContentProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* sContEntry, ProtoGrammar** sCont);
153 
158 static errorCode getComplexTypeProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* complEntry, ProtoGrammar** complType);
159 
164 static errorCode getComplexContentProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* cConEntry, ProtoGrammar** cCont);
165 
170 static errorCode getSequenceProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* seqEntry, ProtoGrammar** seq);
171 
176 static errorCode getAnyProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* anyEntry, ProtoGrammar** any);
177 
182 static errorCode getChoiceProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* chEntry, ProtoGrammar** choice);
183 
188 static errorCode getAllProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* allEntry, ProtoGrammar** all);
189 
194 static errorCode getGroupProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* grEntry, ProtoGrammar** group);
195 
200 static errorCode getExtensionComplexProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* extEntry, ProtoGrammar** ext);
201 
206 static errorCode getExtensionSimpleProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* extEntry, ProtoGrammar** ext);
207 
212 static errorCode getRestrictionSimpleProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* resEntry, ProtoGrammar** restr);
213 
218 static errorCode getRestrictionComplexProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* resEntry, ProtoGrammar** restr);
219 
224 static errorCode getListProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* listEntry, ProtoGrammar** list);
225 
226 // END - converting schema definitions to protogrammars
227 
228 // Helper functions
229 
232 static int compareProductions(const void* prod1, const void* prod2);
233 
240 static void assignCodes(ProtoGrammar* grammar);
241 
243 static void sortAttributeUseGrammars(ProtoGrammarArray* attrUseArray);
244 
246 static int compareAttrUse(const void* attrPG1, const void* attrPG2);
247 
249 static int compareGlobalElemQName(const void* QNameId1, const void* QNameId2);
250 
255 static errorCode parseOccuranceAttribute(const String occurance, int* outInt);
256 
261 static errorCode getTypeId(BuildContext* ctx, const QNameID typeQnameId, QualifiedTreeTableEntry* typeEntry, Index* typeId);
262 
269 static errorCode getAnonymousTypeId(BuildContext* ctx, QualifiedTreeTableEntry* typeEntry, Index* typeId);
270 
277 static errorCode storeGrammar(BuildContext* ctx, QNameID qnameID, ProtoGrammar* pGrammar, boolean isNillable, Index* grIndex);
278 
279 static void sortGlobalElemQnameTable(GlobalElemQNameTable *gElTbl);
280 
281 static void sortEnumTable(EXIPSchema *schema);
282 
286 static char isAttrAlreadyPresent(String aName, struct localAttrNames* lAttrTbl);
287 
290 static errorCode recursiveSubsitutionGroupAdd(BuildContext* ctx, QNameIDGrIndx headQGrIndex, struct subsGroupElTbl* subsElGrTbl);
291 
292 static void sortSubsitutionGroup(struct subsGroupElTbl* subsElGrTbl);
293 
294 errorCode convertTreeTablesToExipSchema(TreeTable* treeT, unsigned int count, EXIPSchema* schema, SubstituteTable* subsTbl)
295 {
296  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
297  unsigned int i = 0;
298  unsigned int j = 0;
299  BuildContext ctx;
301  QNameIDGrIndx qGrIndex; // Qname and Index of the grammar in the schemaGrammarTable
302 
303  ctx.schema = schema;
304  ctx.subsTbl = subsTbl;
305  globalSchemaPtr = schema;
306  ctx.emptyGrIndex = INDEX_MAX;
308 
311 
313  for(i = 0; i < count; i++)
314  {
315  qEntry.treeT = &treeT[i];
317  for(j = 0; j < treeT[i].count; j++)
318  {
319  qEntry.entry = &treeT[i].tree[j];
320  switch(qEntry.entry->element)
321  {
322  case ELEMENT_ELEMENT:
323  tmp_err_code = handleElementEl(&ctx, &qEntry, TRUE, &qGrIndex);
324  break;
325  case ELEMENT_SIMPLE_TYPE:
326  tmp_err_code = handleSimpleTypeEl(&ctx, &qEntry);
327  break;
329  tmp_err_code = handleComplexTypeEl(&ctx, &qEntry);
330  break;
331  case ELEMENT_GROUP:
332  // The model groups are only needing when referenced within a complex type definition
333  tmp_err_code = EXIP_OK;
334  break;
336  // The attribute groups are only needing when referenced within a complex type definition
337  tmp_err_code = EXIP_OK;
338  break;
339  case ELEMENT_ATTRIBUTE:
340  // AT (*) in schema-informed grammars bears an untyped value unless there is a
341  // global attribute definition available for the qname of the attribute.
342  // When a global attribute definition is available the attribute value is
343  // represented according to the datatype of the global attribute.
344  // TODO: There is a need for array of global attributes in the EXIPSchema object.
345  // This array must be sorted according to qname
346  tmp_err_code = EXIP_OK;
347  break;
348  case ELEMENT_IMPORT:
349  //TODO: implement validation checks
350  // 1) the namespace of an <import> element must be a target namespace of some tree table
351  tmp_err_code = EXIP_OK;
352  break;
353  case ELEMENT_INCLUDE:
354  tmp_err_code = EXIP_OK;
355  break;
356  case ELEMENT_REDEFINE:
357  tmp_err_code = EXIP_OK;
358  break;
359  case ELEMENT_NOTATION:
360  tmp_err_code = EXIP_OK;
361  break;
362  default:
363  tmp_err_code = EXIP_UNEXPECTED_ERROR;
364  break;
365  }
366 
367  if(tmp_err_code != EXIP_OK)
368  {
370  return tmp_err_code;
371  }
372  }
373  }
374 
375  sortGlobalElemQnameTable(&ctx.gElTbl);
376 
377  TRY(createDocGrammar(schema, ctx.gElTbl.qname, ctx.gElTbl.count));
378 
380  sortEnumTable(schema);
381  schema->staticGrCount = schema->grammarTable.count;
383 
384  // Assign the chunkEntries for URL and LN tables to their entries count
385  // so it is known how many are the static ones from the schema
386  // after more are added.
387  schema->uriTable.dynArray.chunkEntries = schema->uriTable.count;
388 
389  for(i = 0; i < schema->uriTable.count; i++)
390  {
393  }
394 
395  return tmp_err_code;
396 }
397 
398 static errorCode parseOccuranceAttribute(const String occurance, int* outInt)
399 {
400  if(isStringEmpty(&occurance))
401  *outInt = 1; // The default value
402  else if(stringEqualToAscii(occurance, "unbounded"))
403  *outInt = -1;
404  else
405  {
406  return stringToInteger(&occurance, outInt);
407  }
408 
409  return EXIP_OK;
410 }
411 
412 static int compareAttrUse(const void* attrPG1, const void* attrPG2)
413 {
414  ProtoGrammar** a1 = (ProtoGrammar**) attrPG1;
415  ProtoGrammar** a2 = (ProtoGrammar**) attrPG2;
416 
417  return compareQNameID(&((*a1)->rule[0].prod[0].qnameId), &((*a2)->rule[0].prod[0].qnameId), &globalSchemaPtr->uriTable);
418 }
419 
420 static void sortAttributeUseGrammars(ProtoGrammarArray* attrUseArray)
421 {
422  qsort(attrUseArray->pg, attrUseArray->count, sizeof(ProtoGrammar*), compareAttrUse);
423 }
424 
425 static errorCode getElementTermProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* elementEntry, QNameIDGrIndx qGrIndex, ProtoGrammar** elTerm)
426 {
427  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
428  ProtoGrammar elTermGrammar;
429  ProtoGrammar* elParticleGrammar;
430  int minOccurs = 1;
431  int maxOccurs = 1;
432  struct subsGroupElTbl subsElGrTbl;
433 
434  *elTerm = NULL;
435 
436  TRY(parseOccuranceAttribute(elementEntry->entry->attributePointers[ATTRIBUTE_MIN_OCCURS], &minOccurs));
437  TRY(parseOccuranceAttribute(elementEntry->entry->attributePointers[ATTRIBUTE_MAX_OCCURS], &maxOccurs));
438 
439  if(minOccurs < 0 || maxOccurs < -1)
440  return EXIP_UNEXPECTED_ERROR;
441 
442  TRY(createDynArray(&subsElGrTbl.dynArray, sizeof(QNameIDGrIndx), 10));
443 
444  TRY(recursiveSubsitutionGroupAdd(ctx, qGrIndex, &subsElGrTbl));
445 
446  sortSubsitutionGroup(&subsElGrTbl);
447 
448  TRY(createElementTermGrammar(&elTermGrammar, subsElGrTbl.sGroupSet, subsElGrTbl.count));
449 
450  destroyDynArray(&subsElGrTbl.dynArray);
451 
452  elParticleGrammar = (ProtoGrammar*) memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
453  if(elParticleGrammar == NULL)
455 
456  TRY(createParticleGrammar(minOccurs, maxOccurs, &elTermGrammar, elParticleGrammar));
457 
458  destroyProtoGrammar(&elTermGrammar);
459 
460  *elTerm = elParticleGrammar;
461 
462  return EXIP_OK;
463 }
464 
465 static errorCode handleElementEl(BuildContext* ctx, QualifiedTreeTableEntry* treeTEntry, boolean isGlobal, QNameIDGrIndx* qNmGrIndex)
466 {
467  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
468  String type;
469  QNameID elQNameID;
470  QNameID typeQNameID;
471  boolean isNillable = FALSE;
472 
473 #if DEBUG_GRAMMAR_GEN == ON && EXIP_DEBUG_LEVEL == INFO
474  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Handle Element: "));
476  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, (" of type: "));
478 #endif
479 
480  type = treeTEntry->entry->attributePointers[ATTRIBUTE_TYPE];
481 
482  // Validation checks
484  {
485  // The element does not have a name attribute.
486  // Then it should be local and have a ref="..." attribute.
487  // It must not have a type attribute as well.
488  if(isGlobal || isStringEmpty(&treeTEntry->entry->attributePointers[ATTRIBUTE_REF]) || !isStringEmpty(&type))
489  return EXIP_UNEXPECTED_ERROR;
490  }
491  else
492  {
496  if(isGlobal || treeTEntry->treeT->globalDefs.elemFormDefault == QUALIFIED || stringEqualToAscii(treeTEntry->entry->attributePointers[ATTRIBUTE_FORM], "qualified"))
497  elQNameID.uriId = treeTEntry->treeT->globalDefs.targetNsId;
498  else
499  elQNameID.uriId = 0;
500 
502  if(!lookupLn(&ctx->schema->uriTable.uri[elQNameID.uriId].lnTable, treeTEntry->entry->attributePointers[ATTRIBUTE_NAME], &elQNameID.lnId))
503  return EXIP_UNEXPECTED_ERROR;
504  }
505 
506  qNmGrIndex->qnameId = elQNameID;
507 
508  if(isGlobal)
509  {
510  // Check if the element grammar is not already created
511  if(GET_LN_URI_QNAME(ctx->schema->uriTable, elQNameID).elemGrammar != INDEX_MAX)
512  {
513  qNmGrIndex->grIndex = GET_LN_URI_QNAME(ctx->schema->uriTable, elQNameID).elemGrammar;
514  return EXIP_OK;
515  }
516  }
517 
520  {
521  isNillable = TRUE;
522  }
523 
524  /* Check if the element declaration has a type="..." attribute */
525  if(isStringEmpty(&type))
526  {
527  /*
528  * The element does not have a named type at this point
529  * i.e. there must be some complex/simple type as a child.
530  * Create the grammars for this QNameID
531  */
532  ProtoGrammar* pg = NULL;
533 
534  /* If the element does not have a type then it should have either ref="..."
535  * attribute or an anonymous type definition. If both are missing then it is
536  * an empty element declaration (<xs:element name="unconstrained"/>) that has ·xs:anyType· by default */
537  if(treeTEntry->entry->child.entry == NULL)
538  {
540  GET_LN_URI_QNAME(ctx->schema->uriTable, elQNameID).elemGrammar = qNmGrIndex->grIndex;
541  return EXIP_OK;
542  }
543  else if(treeTEntry->entry->child.entry->element == ELEMENT_SIMPLE_TYPE)
544  {
545  TRY(getSimpleTypeProtoGrammar(ctx, &treeTEntry->entry->child, &pg));
546  }
547  else if(treeTEntry->entry->child.entry->element == ELEMENT_COMPLEX_TYPE)
548  {
549  TRY(getComplexTypeProtoGrammar(ctx, &treeTEntry->entry->child, &pg));
550  }
551  else if(treeTEntry->entry->child.entry->element == ELEMENT_ELEMENT)
552  {
553  // In case of ref="..." attribute
554 
555  return handleElementEl(ctx, &treeTEntry->entry->child, TRUE, qNmGrIndex);
556  }
557  else
558  return EXIP_UNEXPECTED_ERROR;
559 
560  if(treeTEntry->entry->child.entry->loopDetection != 0 && treeTEntry->entry->child.entry->loopDetection != INDEX_MAX)
561  {
562  // This should be the case only for entry->child.entry->element == ELEMENT_COMPLEX_TYPE
563  qNmGrIndex->grIndex = treeTEntry->entry->child.entry->loopDetection;
564 
565  if(pg != NULL)
566  {
567  EXIGrammar exiGr;
568 
569  assignCodes(pg);
570  TRY(convertProtoGrammar(&ctx->schema->memList, pg, &exiGr));
571 
572  // The grammar has a content2 grammar if and only if there are AT
573  // productions that point to the content grammar rule OR the content index is 0.
574  if(GET_CONTENT_INDEX(exiGr.props) == 0)
575  SET_HAS_CONTENT2(exiGr.props);
576  else
577  {
578  Index r, p;
579  boolean prodFound = FALSE;
580  for(r = 0; r < GET_CONTENT_INDEX(exiGr.props); r++)
581  {
582  for(p = 0; p < RULE_GET_AT_COUNT(exiGr.rule[r].meta); p++)
583  {
584  if(GET_PROD_NON_TERM(exiGr.rule[r].production[exiGr.rule[r].pCount-1-p].content) == GET_CONTENT_INDEX(exiGr.props))
585  {
586  SET_HAS_CONTENT2(exiGr.props);
587  prodFound = TRUE;
588  break;
589  }
590  }
591  if(prodFound)
592  break;
593  }
594  }
595 
596  ctx->schema->grammarTable.grammar[qNmGrIndex->grIndex].count = exiGr.count;
597  ctx->schema->grammarTable.grammar[qNmGrIndex->grIndex].props = exiGr.props;
598  ctx->schema->grammarTable.grammar[qNmGrIndex->grIndex].rule = exiGr.rule;
599 
601  }
602  }
603  else
604  {
605  TRY(storeGrammar(ctx, elQNameID, pg, isNillable, &qNmGrIndex->grIndex));
606  }
607  /* If the element is globally defined -> store the index of its grammar in the
608  * LnEntry in the string tables */
609  if(isGlobal == TRUE)
610  GET_LN_URI_QNAME(ctx->schema->uriTable, elQNameID).elemGrammar = qNmGrIndex->grIndex;
611 
612  }
613  else // The element has a particular named type
614  {
615  /* Find the QNameID of the type of this element */
616  TRY(getTypeQName(ctx->schema, treeTEntry->treeT, type, &typeQNameID));
617 
618  /*
619  * If the grammars for the type are already created, simply assign them to this QNameID,
620  * otherwise, create the type grammars first and then assign them to this QNameID.
621  */
622 
623  if(GET_LN_URI_QNAME(ctx->schema->uriTable, typeQNameID).typeGrammar == INDEX_MAX)
624  {
625  // the type definition is still not reached.
626  // The type definition should be linked to the child of the element description in the tree table
627  ProtoGrammar* pg = NULL;
628 
629  if(treeTEntry->entry->child.entry == NULL)
630  return EXIP_UNEXPECTED_ERROR;
631  else if(treeTEntry->entry->child.entry->element == ELEMENT_SIMPLE_TYPE)
632  {
633  TRY(getSimpleTypeProtoGrammar(ctx, &treeTEntry->entry->child, &pg));
634  }
635  else if(treeTEntry->entry->child.entry->element == ELEMENT_COMPLEX_TYPE)
636  {
637  TRY(getComplexTypeProtoGrammar(ctx, &treeTEntry->entry->child, &pg));
638  }
639  else
640  return EXIP_UNEXPECTED_ERROR;
641 
642  if(treeTEntry->entry->child.entry->loopDetection != 0 && treeTEntry->entry->child.entry->loopDetection != INDEX_MAX)
643  {
644  // This should be the case only for entry->child.entry->element == ELEMENT_COMPLEX_TYPE
645  qNmGrIndex->grIndex = treeTEntry->entry->child.entry->loopDetection;
646 
647  if(pg != NULL)
648  {
649  EXIGrammar exiGr;
650 
651  assignCodes(pg);
652  TRY(convertProtoGrammar(&ctx->schema->memList, pg, &exiGr));
653 
654  // The grammar has a content2 grammar if and only if there are AT
655  // productions that point to the content grammar rule OR the content index is 0.
656  if(GET_CONTENT_INDEX(exiGr.props) == 0)
657  SET_HAS_CONTENT2(exiGr.props);
658  else
659  {
660  Index r, p;
661  boolean prodFound = FALSE;
662  for(r = 0; r < GET_CONTENT_INDEX(exiGr.props); r++)
663  {
664  for(p = 0; p < RULE_GET_AT_COUNT(exiGr.rule[r].meta); p++)
665  {
666  if(GET_PROD_NON_TERM(exiGr.rule[r].production[exiGr.rule[r].pCount-1-p].content) == GET_CONTENT_INDEX(exiGr.props))
667  {
668  SET_HAS_CONTENT2(exiGr.props);
669  prodFound = TRUE;
670  break;
671  }
672  }
673  if(prodFound)
674  break;
675  }
676  }
677 
678  ctx->schema->grammarTable.grammar[qNmGrIndex->grIndex].count = exiGr.count;
679  ctx->schema->grammarTable.grammar[qNmGrIndex->grIndex].props = exiGr.props;
680  ctx->schema->grammarTable.grammar[qNmGrIndex->grIndex].rule = exiGr.rule;
681 
683  }
684  }
685  else
686  {
687  TRY(storeGrammar(ctx, typeQNameID, pg, isNillable, &qNmGrIndex->grIndex));
688  }
689 
690  /* Store the index of the type grammar in the
691  * LnEntry in the string tables */
692  GET_LN_URI_QNAME(ctx->schema->uriTable, typeQNameID).typeGrammar = qNmGrIndex->grIndex;
693  }
694 
695  /* If the element is globally defined -> store the index of its type grammar in the
696  * LnEntry in the string tables. Otherwise simply assigned the returned grammar index to
697  * the index of its type grammar */
698  if(isGlobal == TRUE)
699  GET_LN_URI_QNAME(ctx->schema->uriTable, elQNameID).elemGrammar = GET_LN_URI_QNAME(ctx->schema->uriTable, typeQNameID).typeGrammar;
700 
701  qNmGrIndex->grIndex = GET_LN_URI_QNAME(ctx->schema->uriTable, typeQNameID).typeGrammar;
702  }
703 
704  /*
705  * If the element is global and it is not recursively added already,
706  * add it to the GlobalElemQNameTable.
707  * This table is used to generate the schema-informed document grammar.
708  */
709  if(isGlobal && treeTEntry->entry->loopDetection == 0)
710  {
711  Index dynElID;
712 
713  TRY(addDynEntry(&ctx->gElTbl.dynArray, &elQNameID, &dynElID));
714  treeTEntry->entry->loopDetection = INDEX_MAX;
715  }
716 
717  return EXIP_OK;
718 }
719 
720 static errorCode getAttributeProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* attrEntry, boolean isGlobal, boolean isRequired, ProtoGrammar** attr)
721 {
722  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
723  boolean required = FALSE;
724  Index typeId;
725  QNameID atQnameID;
726 
727  if(isGlobal)
728  {
729  required = isRequired;
730  }
731  else if (!isStringEmpty(&(attrEntry->entry->attributePointers[ATTRIBUTE_USE])) &&
732  stringEqualToAscii(attrEntry->entry->attributePointers[ATTRIBUTE_USE], "required"))
733  {
734  required = TRUE;
735  }
736 
737  // Validation checks
739  {
740  // The attribute does not have a name.
741  // Then it should be local and have a ref="..." attribute.
742  // It must not have a type attribute as well.
744  return EXIP_UNEXPECTED_ERROR;
745  }
746  else
747  {
748  /* If the attribute form "qualified" then the element attribute is the target namespace */
749  if(isGlobal || attrEntry->treeT->globalDefs.attrFormDefault == QUALIFIED || stringEqualToAscii(attrEntry->entry->attributePointers[ATTRIBUTE_FORM], "qualified"))
750  atQnameID.uriId = attrEntry->treeT->globalDefs.targetNsId;
751  else
752  atQnameID.uriId = 0; // URI 0 "" [empty string]
753 
754  /* The attribute qname must be already in the string tables */
755  if(!lookupLn(&ctx->schema->uriTable.uri[atQnameID.uriId].lnTable, attrEntry->entry->attributePointers[ATTRIBUTE_NAME], &atQnameID.lnId))
756  return EXIP_UNEXPECTED_ERROR;
757  }
758 
760  {
761  // The attribute has defined type
762  QNameID stQNameID;
763  // global type for the attribute
764  TRY(getTypeQName(ctx->schema, attrEntry->treeT, attrEntry->entry->attributePointers[ATTRIBUTE_TYPE], &stQNameID));
765  TRY(getTypeId(ctx, stQNameID, &attrEntry->entry->child, &typeId));
766  }
767  else
768  {
769  if(attrEntry->entry->child.entry == NULL)
770  {
771  // The attribute does not have defined type and anonymous simple type definition:
772  // hence ·xs:anySimpleType·
773 
775  }
776  else if(attrEntry->entry->child.entry->element == ELEMENT_ATTRIBUTE)
777  {
778  // A reference to a global attribute
779  return getAttributeProtoGrammar(ctx, &attrEntry->entry->child, TRUE, required, attr);
780  }
781  else
782  {
783  // an anonymous type for the attribute
784  TRY(getAnonymousTypeId(ctx, &attrEntry->entry->child, &typeId));
785  }
786  }
787 
788  *attr = (ProtoGrammar*) memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
789  if(*attr == NULL)
791 
792  TRY(createAttributeUseGrammar(required, typeId, *attr, atQnameID));
793 
794  return EXIP_OK;
795 }
796 
797 static errorCode getSimpleTypeProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* simpleEntry, ProtoGrammar** simplType)
798 {
799  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
800 
801  if(simpleEntry->entry->child.entry == NULL)
802  {
804  *simplType = NULL;
805  }
806  else if(simpleEntry->entry->child.entry->element == ELEMENT_RESTRICTION)
807  {
808  TRY(getRestrictionSimpleProtoGrammar(ctx, &simpleEntry->entry->child, simplType));
809  }
810  else if(simpleEntry->entry->child.entry->element == ELEMENT_LIST)
811  {
812  TRY(getListProtoGrammar(ctx, &simpleEntry->entry->child, simplType));
813  }
814  else if(simpleEntry->entry->child.entry->element == ELEMENT_UNION)
815  {
816  *simplType = (ProtoGrammar*) memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
817  if(*simplType == NULL)
819 
821  }
822  else
823  return EXIP_UNEXPECTED_ERROR;
824 
825  return EXIP_OK;
826 }
827 
828 static errorCode handleSimpleTypeEl(BuildContext* ctx, QualifiedTreeTableEntry* stEntry)
829 {
830  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
831 
832 #if DEBUG_GRAMMAR_GEN == ON && EXIP_DEBUG_LEVEL == INFO
833  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Handle SimpleType: "));
835 #endif
836 
838  {
839  // Named simple type
840  QNameID stQNameID;
841  ProtoGrammar* simpleProtoGrammar;
842 
843  stQNameID.uriId = stEntry->treeT->globalDefs.targetNsId;
844 
846  if(!lookupLn(&ctx->schema->uriTable.uri[stQNameID.uriId].lnTable, stEntry->entry->attributePointers[ATTRIBUTE_NAME], &stQNameID.lnId))
847  return EXIP_UNEXPECTED_ERROR;
848 
849  if(GET_LN_URI_QNAME(ctx->schema->uriTable, stQNameID).typeGrammar == INDEX_MAX)
850  {
851  // The EXIP grammars corresponding to this simple type are not yet created
852  Index grIndex;
853 
854  TRY(getSimpleTypeProtoGrammar(ctx, stEntry, &simpleProtoGrammar));
855  TRY(storeGrammar(ctx, stQNameID, simpleProtoGrammar, FALSE, &grIndex));
856 
857  GET_LN_URI_QNAME(ctx->schema->uriTable, stQNameID).typeGrammar = grIndex;
858  }
859 
860  // When Strict is True: If Tk either has named sub-types or is a simple type definition of which {variety} is union...
861  if(stEntry->entry->child.entry->element == ELEMENT_RESTRICTION)
862  {
863  QNameID baseTypeQnameId;
864 
866  {
867  /* In case of derivation by list (e.g., IDREFS and ENTITIES in XML Schema) the base
868  type is not an attribute of <xs:restriction>. Rather it is given as a
869  "itemType" attribte of the <xs:list> element which is subelement of <xs:simpleType> */
870 
871  if(stEntry->entry->child.entry->child.entry != NULL &&
872  stEntry->entry->child.entry->child.entry->child.entry != NULL &&
873  stEntry->entry->child.entry->child.entry->child.entry->element == ELEMENT_LIST) // simpleType->restriction->simpleType->list exists
874  {
876  }
877  else
878  return EXIP_UNEXPECTED_ERROR;
879  }
880  else
881  TRY(getTypeQName(ctx->schema, stEntry->entry->child.treeT, stEntry->entry->child.entry->attributePointers[ATTRIBUTE_BASE], &baseTypeQnameId));
882 
883  SET_NAMED_SUB_TYPE_OR_UNION((GET_TYPE_GRAMMAR_QNAMEID(ctx->schema, baseTypeQnameId))->props);
884  }
885  else if(stEntry->entry->child.entry->element == ELEMENT_UNION)
886  {
888  }
889  }
890  else
891  {
892  // The global simple types must have names
893  return EXIP_UNEXPECTED_ERROR;
894  }
895 
896  return EXIP_OK;
897 }
898 
899 static errorCode getSimpleContentProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* sContEntry, ProtoGrammar** sCont)
900 {
901  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
902 
903  if(sContEntry->entry->child.entry == NULL)
904  return EXIP_UNEXPECTED_ERROR;
905  else if(sContEntry->entry->child.entry->element == ELEMENT_RESTRICTION)
906  {
907  tmp_err_code = getRestrictionSimpleProtoGrammar(ctx, &sContEntry->entry->child, sCont);
908  }
909  else if(sContEntry->entry->child.entry->element == ELEMENT_EXTENSION)
910  {
911  tmp_err_code = getExtensionSimpleProtoGrammar(ctx, &sContEntry->entry->child, sCont);
912  }
913  else
914  tmp_err_code = EXIP_UNEXPECTED_ERROR;
915 
916  return tmp_err_code;
917 }
918 
919 /* entry should be a complex_type or extension element */
920 static errorCode getContentTypeProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* contEntry, ProtoGrammar** content)
921 {
922  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
923 
924  *content = NULL;
925 
926  if(contEntry->entry->child.entry == NULL)
927  {
928  // empty complex_type or extension element
929  tmp_err_code = EXIP_OK;
930  }
931  else if(contEntry->entry->element == ELEMENT_COMPLEX_TYPE && contEntry->entry->child.entry->element == ELEMENT_SIMPLE_CONTENT)
932  {
933  tmp_err_code = getSimpleContentProtoGrammar(ctx, &contEntry->entry->child, content);
934  }
935  else if(contEntry->entry->element == ELEMENT_COMPLEX_TYPE && contEntry->entry->child.entry->element == ELEMENT_COMPLEX_CONTENT)
936  {
937  tmp_err_code = getComplexContentProtoGrammar(ctx, &contEntry->entry->child, content);
938  }
939  else if(contEntry->entry->child.entry->element == ELEMENT_SEQUENCE)
940  {
941  tmp_err_code = getSequenceProtoGrammar(ctx, &contEntry->entry->child, content);
942  }
943  else if(contEntry->entry->child.entry->element == ELEMENT_GROUP)
944  {
945  tmp_err_code = getGroupProtoGrammar(ctx, &contEntry->entry->child, content);
946  }
947  else if(contEntry->entry->child.entry->element == ELEMENT_ALL)
948  {
949  tmp_err_code = getAllProtoGrammar(ctx, &contEntry->entry->child, content);
950  }
951  else if(contEntry->entry->child.entry->element == ELEMENT_CHOICE)
952  {
953  tmp_err_code = getChoiceProtoGrammar(ctx, &contEntry->entry->child, content);
954  }
955  else if(contEntry->entry->child.entry->element == ELEMENT_ATTRIBUTE ||
956  contEntry->entry->child.entry->element == ELEMENT_ATTRIBUTE_GROUP ||
958  {
959  // Ignored -> attributes are handles by getAttributeUseProtoGrammars()
960  tmp_err_code = EXIP_OK;
961  }
962  else
963  return EXIP_UNEXPECTED_ERROR;
964 
965  return tmp_err_code;
966 }
967 
968 /* entry should be a complex_type or extension or restriction or attributeGroup element */
969 static errorCode getAttributeUseProtoGrammars(BuildContext* ctx, QualifiedTreeTableEntry* attrEntry, ProtoGrammarArray* attrUseArray, String** attrWildcardNS, struct localAttrNames* aNamesTbl)
970 {
971  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
972  QualifiedTreeTableEntry attrUse;
973 
974  attrUse.entry = NULL;
975 
976  if(attrEntry->entry->child.entry != NULL)
977  {
978  if(attrEntry->entry->child.entry->element == ELEMENT_ATTRIBUTE ||
979  attrEntry->entry->child.entry->element == ELEMENT_ATTRIBUTE_GROUP ||
981  {
982  attrUse = attrEntry->entry->child;
983  }
984  else if(attrEntry->entry->child.entry->next != NULL &&
985  (attrEntry->entry->child.entry->next->element == ELEMENT_ATTRIBUTE ||
988  )
989  {
990  attrUse.treeT = attrEntry->entry->child.treeT;
991  attrUse.entry = attrEntry->entry->child.entry->next;
992  }
993  else if(attrEntry->entry->child.entry->element == ELEMENT_SIMPLE_CONTENT && attrEntry->entry->child.entry->child.entry != NULL && attrEntry->entry->child.entry->child.entry->element == ELEMENT_EXTENSION)
994  {
995  if(attrEntry->entry->child.entry->child.entry->child.entry != NULL)
996  {
1000  {
1001  attrUse = attrEntry->entry->child.entry->child.entry->child;
1002  }
1003  else if(attrEntry->entry->child.entry->child.entry->child.entry->next != NULL &&
1007  )
1008  {
1009  attrUse.treeT = attrEntry->entry->child.entry->child.entry->child.treeT;
1010  attrUse.entry = attrEntry->entry->child.entry->child.entry->child.entry->next;
1011  }
1012  }
1013  }
1014 
1015  if(attrUse.entry != NULL)
1016  {
1017  ProtoGrammar* attrPG;
1018  Index entryId;
1019  do
1020  {
1021  if(attrUse.entry->element == ELEMENT_ATTRIBUTE)
1022  {
1023  String aName;
1025  aName = attrUse.entry->attributePointers[ATTRIBUTE_REF];
1026  else
1027  aName = attrUse.entry->attributePointers[ATTRIBUTE_NAME];
1028 
1029  if(!isAttrAlreadyPresent(aName, aNamesTbl))
1030  {
1031  TRY(addDynEntry(&aNamesTbl->dynArray, &aName, &entryId));
1032 
1033  if(!stringEqualToAscii(attrUse.entry->attributePointers[ATTRIBUTE_USE], "prohibited"))
1034  {
1035  TRY(getAttributeProtoGrammar(ctx, &attrUse, FALSE, FALSE, &attrPG));
1036  TRY(addDynEntry(&attrUseArray->dynArray, &attrPG, &entryId));
1037  }
1038  }
1039  }
1040  else if(attrUse.entry->element == ELEMENT_ATTRIBUTE_GROUP)
1041  {
1042  if(attrUse.entry->child.entry != NULL)
1043  {
1044  TRY(getAttributeUseProtoGrammars(ctx, &attrUse.entry->child, attrUseArray, attrWildcardNS, aNamesTbl));
1045  }
1046  else
1047  return EXIP_UNEXPECTED_ERROR;
1048  }
1049  else if(attrUse.entry->element == ELEMENT_ANY_ATTRIBUTE)
1050  {
1051  *attrWildcardNS = &attrUse.entry->attributePointers[ATTRIBUTE_NAMESPACE];
1052  }
1053  else
1054  return EXIP_UNEXPECTED_ERROR;
1055 
1056  attrUse.entry = attrUse.entry->next;
1057  }
1058  while(attrUse.entry != NULL);
1059  }
1060 
1061  if(attrEntry->entry->element == ELEMENT_COMPLEX_TYPE)
1062  {
1063  if((attrEntry->entry->child.entry->element == ELEMENT_COMPLEX_CONTENT) &&
1064  (attrEntry->entry->child.entry->child.entry != NULL))
1065  {
1066  // Follow the extensions and restrictions.
1067  // entry->child.entry->child.entry->element is either ELEMENT_EXTENSION or ELEMENT_RESTRICTION
1068  TRY(getAttributeUseProtoGrammars(ctx, &attrEntry->entry->child.entry->child, attrUseArray, attrWildcardNS, aNamesTbl));
1069  }
1070  }
1071  }
1072 
1073  if(attrEntry->entry->element == ELEMENT_EXTENSION || attrEntry->entry->element == ELEMENT_RESTRICTION)
1074  {
1075  if(attrEntry->entry->supertype.entry != NULL && attrEntry->entry->supertype.entry->element == ELEMENT_COMPLEX_TYPE)
1076  {
1077  TRY(getAttributeUseProtoGrammars(ctx, &attrEntry->entry->supertype, attrUseArray, attrWildcardNS, aNamesTbl));
1078  }
1079  }
1080 
1081  /* NOTE ON:
1082  * === Deriving complex types through restriction ===
1083  * When deriving complex types through restriction it is not required by
1084  * the XSD spec that you repeat all the inherited attributes.
1085  * This is yet another quirk in the XSD spec - all content elements should be repeated
1086  * during restriction but not the attribute uses!?!?
1087  * In any way, the schema code is much more comprehensible when the attribute uses are
1088  * repeated but still this messy code here is needed to keep the compliance with the
1089  * XSD specification.
1090  */
1091 
1092  return EXIP_OK;
1093 }
1094 
1095 static errorCode getComplexTypeProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* complEntry, ProtoGrammar** complType)
1096 {
1097  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
1098  ProtoGrammarArray attrUseArray;
1099  ProtoGrammar* contentTypeGrammar = NULL;
1100  String* attrWildcardNS = NULL;
1101  boolean isMixedContent = FALSE;
1102  Index i;
1103 
1104  if(complEntry->entry->loopDetection == 0)
1105  {
1106  // The complexType entry has not been processed before
1107  complEntry->entry->loopDetection = INDEX_MAX;
1108  }
1109  else if(complEntry->entry->loopDetection == INDEX_MAX)
1110  {
1111  // The complexType has already been processed once.
1112  // Add dummy grammar to the grammarTable that will be replaced by the real one later
1113  TRY(addDynEntry(&ctx->schema->grammarTable.dynArray, &static_grammar_empty, &complEntry->entry->loopDetection));
1114  *complType = NULL;
1115  return EXIP_OK;
1116  }
1117  else
1118  {
1119  // The complexType entry has already been processed at least twice
1120  *complType = NULL;
1121  return EXIP_OK;
1122  }
1123 
1125  && stringEqualToAscii(complEntry->entry->attributePointers[ATTRIBUTE_MIXED], "true"))
1126  {
1127  isMixedContent = TRUE;
1128  }
1129 
1130  TRY(getContentTypeProtoGrammar(ctx, complEntry, &contentTypeGrammar));
1131  TRY(createDynArray(&attrUseArray.dynArray, sizeof(ProtoGrammar*), 10));
1132 
1133  { // get all the attribute uses
1134  struct localAttrNames aNamesTbl;
1135  TRY(createDynArray(&aNamesTbl.dynArray, sizeof(String), 20));
1136  TRY(getAttributeUseProtoGrammars(ctx, complEntry, &attrUseArray, &attrWildcardNS, &aNamesTbl));
1137 
1138  destroyDynArray(&aNamesTbl.dynArray);
1139  }
1140 
1141  sortAttributeUseGrammars(&attrUseArray);
1142 
1143  if(attrWildcardNS != NULL)
1144  {
1145  // There is an {attribute wildcard} ANY_ATTRIBUTE
1146  NsTable nsTable;
1147  Index dummyEntryId;
1148  QNameID qnameID;
1149  ProtoRuleEntry* pRuleEntry;
1150  ProtoGrammar* pAttrWildGrammar;
1151 
1152  TRY(createDynArray(&nsTable.dynArray, sizeof(String), 5));
1153  TRY(getNsList(complEntry->treeT, *attrWildcardNS, &nsTable));
1154 
1155  pAttrWildGrammar = memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
1156  if(pAttrWildGrammar == NULL)
1158 
1159  TRY(createProtoGrammar(2, pAttrWildGrammar));
1160  TRY(addProtoRule(pAttrWildGrammar, 5, &pRuleEntry));
1161  TRY(addEEProduction(pRuleEntry));
1162  TRY(addDynEntry(&attrUseArray.dynArray, &pAttrWildGrammar, &dummyEntryId));
1163 
1164  if(nsTable.count == 0 || // default is "##any"
1165  (nsTable.count == 1 &&
1166  (stringEqualToAscii(nsTable.base[0], "##any") || stringEqualToAscii(nsTable.base[0], "##other"))
1167  )
1168  )
1169  {
1170  for(i = 0; i < attrUseArray.count; i++)
1171  {
1172  qnameID.uriId = URI_MAX;
1173  qnameID.lnId = LN_MAX;
1174  TRY(addProduction(&attrUseArray.pg[i]->rule[0], EVENT_AT_ALL, INDEX_MAX, qnameID, 0));
1175  }
1176  }
1177  else if(nsTable.count >= 1)
1178  {
1179  Index j;
1180 
1181  qnameID.lnId = LN_MAX;
1182 
1183  for(j = 0; j < nsTable.count; j++)
1184  {
1185  if(!lookupUri(&ctx->schema->uriTable, nsTable.base[j], &qnameID.uriId))
1186  return EXIP_UNEXPECTED_ERROR;
1187 
1188  for(i = 0; i < attrUseArray.count; i++)
1189  {
1190  TRY(addProduction(&attrUseArray.pg[i]->rule[0], EVENT_AT_URI, INDEX_MAX, qnameID, 0));
1191  }
1192  }
1193  }
1194  else
1195  return EXIP_UNEXPECTED_ERROR;
1196 
1197  destroyDynArray(&nsTable.dynArray);
1198  }
1199 
1200  if(contentTypeGrammar == NULL && attrUseArray.count == 0) // An empty element: <xsd:complexType />
1201  {
1202  *complType = NULL;
1203  }
1204  else
1205  {
1206  *complType = (ProtoGrammar*) memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
1207  if(*complType == NULL)
1209 
1210  TRY(createComplexTypeGrammar(&attrUseArray, contentTypeGrammar, isMixedContent, *complType));
1211 
1212  if(contentTypeGrammar != NULL)
1213  destroyProtoGrammar(contentTypeGrammar);
1214  }
1215 
1216  for(i = 0; i < attrUseArray.count; i++)
1217  {
1218  destroyProtoGrammar(attrUseArray.pg[i]);
1219  }
1220 
1221  destroyDynArray(&attrUseArray.dynArray);
1222 
1223  return EXIP_OK;
1224 }
1225 
1226 static errorCode handleComplexTypeEl(BuildContext* ctx, QualifiedTreeTableEntry* ctEntry)
1227 {
1228  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
1229 
1230 #if DEBUG_GRAMMAR_GEN == ON && EXIP_DEBUG_LEVEL == INFO
1231  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Handle ComplexType: "));
1233 #endif
1234 
1236  {
1237  QNameID ctQNameID;
1238 
1239  ctQNameID.uriId = ctEntry->treeT->globalDefs.targetNsId;
1240 
1242  if(!lookupLn(&ctx->schema->uriTable.uri[ctQNameID.uriId].lnTable, ctEntry->entry->attributePointers[ATTRIBUTE_NAME], &ctQNameID.lnId))
1243  return EXIP_UNEXPECTED_ERROR;
1244 
1245  if(GET_LN_URI_QNAME(ctx->schema->uriTable, ctQNameID).typeGrammar == INDEX_MAX)
1246  {
1247  // The EXIP grammars are not yet created
1248  ProtoGrammar* complType;
1249  Index grIndex;
1250 
1251  TRY(getComplexTypeProtoGrammar(ctx, ctEntry, &complType));
1252 
1253  if(ctEntry->entry->loopDetection != 0 && ctEntry->entry->loopDetection != INDEX_MAX)
1254  {
1255  // This should be the case only for entry->element == ELEMENT_COMPLEX_TYPE
1256  grIndex = ctEntry->entry->loopDetection;
1257  if(complType != NULL)
1258  {
1259  EXIGrammar exiGr;
1260 
1261  assignCodes(complType);
1262  TRY(convertProtoGrammar(&ctx->schema->memList, complType, &exiGr));
1263 
1264  // The grammar has a content2 grammar if and only if there are AT
1265  // productions that point to the content grammar rule OR the content index is 0.
1266  if(GET_CONTENT_INDEX(exiGr.props) == 0)
1267  SET_HAS_CONTENT2(exiGr.props);
1268  else
1269  {
1270  Index r, p;
1271  boolean prodFound = FALSE;
1272  for(r = 0; r < GET_CONTENT_INDEX(exiGr.props); r++)
1273  {
1274  for(p = 0; p < RULE_GET_AT_COUNT(exiGr.rule[r].meta); p++)
1275  {
1276  if(GET_PROD_NON_TERM(exiGr.rule[r].production[exiGr.rule[r].pCount-1-p].content) == GET_CONTENT_INDEX(exiGr.props))
1277  {
1278  SET_HAS_CONTENT2(exiGr.props);
1279  prodFound = TRUE;
1280  break;
1281  }
1282  }
1283  if(prodFound)
1284  break;
1285  }
1286  }
1287 
1288  ctx->schema->grammarTable.grammar[grIndex].count = exiGr.count;
1289  ctx->schema->grammarTable.grammar[grIndex].props = exiGr.props;
1290  ctx->schema->grammarTable.grammar[grIndex].rule = exiGr.rule;
1291 
1292  destroyProtoGrammar(complType);
1293  }
1294  }
1295  else
1296  {
1297  TRY(storeGrammar(ctx, ctQNameID, complType, FALSE, &grIndex));
1298  }
1299 
1300  GET_LN_URI_QNAME(ctx->schema->uriTable, ctQNameID).typeGrammar = grIndex;
1301  }
1302 
1303  // When Strict is True: If Tk either has named sub-types or is a simple type definition of which {variety} is union...
1304  if(ctEntry->entry->child.entry != NULL && ctEntry->entry->child.entry->child.entry != NULL)
1305  {
1306  if(ctEntry->entry->child.entry->element == ELEMENT_SIMPLE_CONTENT ||
1308  {
1309  if(ctEntry->entry->child.entry->child.entry->element == ELEMENT_RESTRICTION ||
1311  {
1312  QNameID baseTypeQnameId;
1313 
1314  TRY(getTypeQName(ctx->schema, ctEntry->entry->child.entry->child.treeT, ctEntry->entry->child.entry->child.entry->attributePointers[ATTRIBUTE_BASE], &baseTypeQnameId));
1315 
1316  SET_NAMED_SUB_TYPE_OR_UNION((GET_TYPE_GRAMMAR_QNAMEID(ctx->schema, baseTypeQnameId))->props);
1317  }
1318  }
1319  }
1320 
1321  }
1322  else
1323  {
1324  // The global complex types must have names
1325  return EXIP_UNEXPECTED_ERROR;
1326  }
1327 
1328  return EXIP_OK;
1329 }
1330 
1331 static errorCode getComplexContentProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* cConEntry, ProtoGrammar** cCont)
1332 {
1333  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
1334 
1335  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Handle Complex Content Proto Grammar"));
1336 
1337  if(cConEntry->entry->child.entry == NULL)
1338  return EXIP_UNEXPECTED_ERROR;
1339  else if(cConEntry->entry->child.entry->element == ELEMENT_RESTRICTION)
1340  {
1341  tmp_err_code = getRestrictionComplexProtoGrammar(ctx, &cConEntry->entry->child, cCont);
1342  }
1343  else if(cConEntry->entry->child.entry->element == ELEMENT_EXTENSION)
1344  {
1345  tmp_err_code = getExtensionComplexProtoGrammar(ctx, &cConEntry->entry->child, cCont);
1346  }
1347  else
1348  tmp_err_code = EXIP_UNEXPECTED_ERROR;
1349 
1350  return tmp_err_code;
1351 }
1352 
1353 static errorCode getSequenceProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* seqEntry, ProtoGrammar** seq)
1354 {
1355  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
1356  ProtoGrammar* particleGrammar = NULL;
1357  ProtoGrammar seqGrammar;
1358  ProtoGrammar* seqPartGrammar;
1359  int minOccurs = 1;
1360  int maxOccurs = 1;
1361  QualifiedTreeTableEntry nextIterator;
1362  ProtoGrammarArray partGrammarTbl;
1363  Index dummyTblIndx;
1364  Index i;
1365 
1366  TRY(createDynArray(&partGrammarTbl.dynArray, sizeof(ProtoGrammar*), 30));
1367 
1368  TRY(parseOccuranceAttribute(seqEntry->entry->attributePointers[ATTRIBUTE_MIN_OCCURS], &minOccurs));
1369  TRY(parseOccuranceAttribute(seqEntry->entry->attributePointers[ATTRIBUTE_MAX_OCCURS], &maxOccurs));
1370 
1371  if(minOccurs < 0 || maxOccurs < -1)
1372  return EXIP_UNEXPECTED_ERROR;
1373 
1374  nextIterator = seqEntry->entry->child;
1375  while(nextIterator.entry != NULL)
1376  {
1377  if(nextIterator.entry->element == ELEMENT_ELEMENT)
1378  {
1379  QNameIDGrIndx qGrIndex;
1380 
1381  TRY(handleElementEl(ctx, &nextIterator, FALSE, &qGrIndex));
1382  TRY(getElementTermProtoGrammar(ctx, &nextIterator, qGrIndex, &particleGrammar));
1383  }
1384  else if(nextIterator.entry->element == ELEMENT_GROUP)
1385  {
1386  TRY(getGroupProtoGrammar(ctx, &nextIterator, &particleGrammar));
1387  }
1388  else if(nextIterator.entry->element == ELEMENT_CHOICE)
1389  {
1390  TRY(getChoiceProtoGrammar(ctx, &nextIterator, &particleGrammar));
1391  }
1392  else if(nextIterator.entry->element == ELEMENT_SEQUENCE)
1393  {
1394  TRY(getSequenceProtoGrammar(ctx, &nextIterator, &particleGrammar));
1395  }
1396  else if(nextIterator.entry->element == ELEMENT_ANY)
1397  {
1398  TRY(getAnyProtoGrammar(ctx, &nextIterator, &particleGrammar));
1399  }
1400  else
1401  return EXIP_UNEXPECTED_ERROR;
1402 
1403  TRY(addDynEntry(&partGrammarTbl.dynArray, &particleGrammar, &dummyTblIndx));
1404  nextIterator.entry = nextIterator.entry->next;
1405  }
1406 
1407  TRY(createSequenceModelGroupsGrammar(partGrammarTbl.pg, partGrammarTbl.count, &seqGrammar));
1408 
1409  for(i = 0; i < partGrammarTbl.count; i++)
1410  {
1411  destroyProtoGrammar(partGrammarTbl.pg[i]);
1412  }
1413 
1414  destroyDynArray(&partGrammarTbl.dynArray);
1415 
1416  seqPartGrammar = (ProtoGrammar*) memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
1417  if(seqPartGrammar == NULL)
1419 
1420  TRY(createParticleGrammar(minOccurs, maxOccurs, &seqGrammar, seqPartGrammar));
1421 
1422  destroyProtoGrammar(&seqGrammar);
1423  *seq = seqPartGrammar;
1424 
1425  return EXIP_OK;
1426 }
1427 
1428 static errorCode getAnyProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* anyEntry, ProtoGrammar** any)
1429 {
1430  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
1431  ProtoGrammar wildTermGrammar;
1432  ProtoGrammar* wildParticleGrammar;
1433  int minOccurs = 1;
1434  int maxOccurs = 1;
1435  NsTable nsTable;
1436 
1437  TRY(createDynArray(&nsTable.dynArray, sizeof(String), 5));
1438 
1439  TRY(getNsList(anyEntry->treeT, anyEntry->entry->attributePointers[ATTRIBUTE_NAMESPACE], &nsTable));
1440 
1441  TRY(parseOccuranceAttribute(anyEntry->entry->attributePointers[ATTRIBUTE_MIN_OCCURS], &minOccurs));
1442  TRY(parseOccuranceAttribute(anyEntry->entry->attributePointers[ATTRIBUTE_MAX_OCCURS], &maxOccurs));
1443 
1444  if(minOccurs < 0 || maxOccurs < -1)
1445  return EXIP_UNEXPECTED_ERROR;
1446 
1447  TRY(createWildcardTermGrammar(nsTable.base, nsTable.count, &ctx->schema->uriTable, &wildTermGrammar));
1448 
1449  wildParticleGrammar = (ProtoGrammar*)memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
1450  if(wildParticleGrammar == NULL)
1452 
1453  TRY(createParticleGrammar(minOccurs, maxOccurs, &wildTermGrammar, wildParticleGrammar));
1454 
1455  destroyProtoGrammar(&wildTermGrammar);
1456  destroyDynArray(&nsTable.dynArray);
1457 
1458  *any = wildParticleGrammar;
1459 
1460  return EXIP_OK;
1461 }
1462 
1463 static errorCode getChoiceProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* chEntry, ProtoGrammar** choice)
1464 {
1465  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
1466  ProtoGrammar choiceGrammar;
1467  ProtoGrammar* choicePartGrammar;
1468  QualifiedTreeTableEntry nextIterator;
1469  ProtoGrammarArray particleProtoGrammarArray;
1470  ProtoGrammar* particleGrammar = NULL;
1471  Index entryId, i;
1472  int minOccurs = 1;
1473  int maxOccurs = 1;
1474 
1475  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Handle Choice "));
1476 
1477  TRY(parseOccuranceAttribute(chEntry->entry->attributePointers[ATTRIBUTE_MIN_OCCURS], &minOccurs));
1478  TRY(parseOccuranceAttribute(chEntry->entry->attributePointers[ATTRIBUTE_MAX_OCCURS], &maxOccurs));
1479 
1480  if(minOccurs < 0 || maxOccurs < -1)
1481  return EXIP_UNEXPECTED_ERROR;
1482 
1483  TRY(createDynArray(&particleProtoGrammarArray.dynArray, sizeof(ProtoGrammar*), 15));
1484 
1485  nextIterator = chEntry->entry->child;
1486  while(nextIterator.entry != NULL)
1487  {
1488  if(nextIterator.entry->element == ELEMENT_ELEMENT)
1489  {
1490  QNameIDGrIndx qGrIndex;
1491  TRY(handleElementEl(ctx, &nextIterator, FALSE, &qGrIndex));
1492  TRY(getElementTermProtoGrammar(ctx, &nextIterator, qGrIndex, &particleGrammar));
1493  }
1494  else if(nextIterator.entry->element == ELEMENT_GROUP)
1495  {
1496  TRY(getGroupProtoGrammar(ctx, &nextIterator, &particleGrammar));
1497  }
1498  else if(nextIterator.entry->element == ELEMENT_CHOICE)
1499  {
1500  TRY(getChoiceProtoGrammar(ctx, &nextIterator, &particleGrammar));
1501  }
1502  else if(nextIterator.entry->element == ELEMENT_SEQUENCE)
1503  {
1504  TRY(getSequenceProtoGrammar(ctx, &nextIterator, &particleGrammar));
1505  }
1506  else if(nextIterator.entry->element == ELEMENT_ANY)
1507  {
1508  TRY(getAnyProtoGrammar(ctx, &nextIterator, &particleGrammar));
1509  }
1510  else
1511  return EXIP_UNEXPECTED_ERROR;
1512 
1513  TRY(addDynEntry(&particleProtoGrammarArray.dynArray, &particleGrammar, &entryId));
1514  nextIterator.entry = nextIterator.entry->next;
1515  }
1516 
1517  TRY(createChoiceModelGroupsGrammar(&particleProtoGrammarArray, &choiceGrammar));
1518 
1519  for(i = 0; i < particleProtoGrammarArray.count; i++)
1520  {
1521  destroyProtoGrammar(particleProtoGrammarArray.pg[i]);
1522  }
1523 
1524  destroyDynArray(&particleProtoGrammarArray.dynArray);
1525 
1526  choicePartGrammar = (ProtoGrammar*)memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
1527  if(choicePartGrammar == NULL)
1529 
1530  TRY(createParticleGrammar(minOccurs, maxOccurs, &choiceGrammar, choicePartGrammar));
1531  destroyProtoGrammar(&choiceGrammar);
1532  *choice = choicePartGrammar;
1533 
1534  return EXIP_OK;
1535 }
1536 
1537 static errorCode getAllProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* allEntry, ProtoGrammar** all)
1538 {
1539  return EXIP_NOT_IMPLEMENTED_YET;
1540 }
1541 
1542 static errorCode getGroupProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* grEntry, ProtoGrammar** group)
1543 {
1544  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
1545  ProtoGrammar* particleGrammar = NULL;
1546  ProtoGrammar* grPartGrammar;
1547  int minOccurs = 1;
1548  int maxOccurs = 1;
1549 
1550 #if DEBUG_GRAMMAR_GEN == ON && EXIP_DEBUG_LEVEL == INFO
1551  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Handle Group: "));
1553 #endif
1554 
1555  TRY(parseOccuranceAttribute(grEntry->entry->attributePointers[ATTRIBUTE_MIN_OCCURS], &minOccurs));
1556  TRY(parseOccuranceAttribute(grEntry->entry->attributePointers[ATTRIBUTE_MAX_OCCURS], &maxOccurs));
1557 
1558  if(minOccurs < 0 || maxOccurs < -1)
1559  return EXIP_UNEXPECTED_ERROR;
1560 
1561  // There should be a global group definition referenced through ref attribute
1562  if(grEntry->entry->child.entry == NULL)
1563  return EXIP_UNEXPECTED_ERROR;
1564 
1565  if(grEntry->entry->child.entry->child.entry == NULL)
1566  {
1567  // empty group.
1568  // The content of 'group (global)' must match (annotation?, (all | choice | sequence)). Not enough
1569  // elements were found.
1570  return EXIP_UNEXPECTED_ERROR;
1571  }
1572  else if(grEntry->entry->child.entry->child.entry->element == ELEMENT_SEQUENCE)
1573  {
1574  TRY(getSequenceProtoGrammar(ctx, &grEntry->entry->child.entry->child, &particleGrammar));
1575  }
1576  else if(grEntry->entry->child.entry->child.entry->element == ELEMENT_CHOICE)
1577  {
1578  TRY(getChoiceProtoGrammar(ctx, &grEntry->entry->child.entry->child, &particleGrammar));
1579  }
1580  else if(grEntry->entry->child.entry->child.entry->element == ELEMENT_ALL)
1581  {
1582  TRY(getAllProtoGrammar(ctx, &grEntry->entry->child.entry->child, &particleGrammar));
1583  }
1584  else
1585  return EXIP_UNEXPECTED_ERROR;
1586 
1587  grPartGrammar = (ProtoGrammar*)memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
1588  if(grPartGrammar == NULL)
1590 
1591  TRY(createParticleGrammar(minOccurs, maxOccurs, particleGrammar, grPartGrammar));
1592 
1593  destroyProtoGrammar(particleGrammar);
1594  *group = grPartGrammar;
1595 
1596  return EXIP_OK;
1597 }
1598 
1599 static errorCode getExtensionSimpleProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* extEntry, ProtoGrammar** ext)
1600 {
1601  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
1602  QNameID baseTypeId;
1603  ProtoGrammar* resultProtoGrammar = NULL;
1604  Index typeId;
1605 
1606 #if DEBUG_GRAMMAR_GEN == ON && EXIP_DEBUG_LEVEL == INFO
1607  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Handle SimpleContent Extension: "));
1609 #endif
1610 
1611  TRY(getTypeQName(ctx->schema, extEntry->treeT, extEntry->entry->attributePointers[ATTRIBUTE_BASE], &baseTypeId));
1612 
1613  resultProtoGrammar = (ProtoGrammar*) memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
1614  if(resultProtoGrammar == NULL)
1616 
1617  TRY(getTypeId(ctx, baseTypeId, &extEntry->entry->supertype, &typeId));
1618 
1619  // Extension from a simple type only
1620  TRY(createSimpleTypeGrammar(typeId, resultProtoGrammar));
1621  *ext = resultProtoGrammar;
1622 
1623  return EXIP_OK;
1624 }
1625 
1626 static errorCode getExtensionComplexProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* extEntry, ProtoGrammar** ext)
1627 {
1628  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
1629  QNameID baseTypeId;
1630  ProtoGrammar* contentTypeGrammarBase;
1631  ProtoGrammar* contentTypeGrammarExt;
1632  ProtoGrammar* resultProtoGrammar = NULL;
1633  ProtoGrammar* contGrArr[2];
1635 
1636 #if DEBUG_GRAMMAR_GEN == ON && EXIP_DEBUG_LEVEL == INFO
1637  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Handle ComplexContent Extension: "));
1639 #endif
1640 
1641  TRY(getTypeQName(ctx->schema, extEntry->treeT, extEntry->entry->attributePointers[ATTRIBUTE_BASE], &baseTypeId));
1642 
1643  resultProtoGrammar = (ProtoGrammar*) memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
1644  if(resultProtoGrammar == NULL)
1646 
1647  // Extension from a complex type only
1648  base = extEntry->entry->supertype;
1649  if(base.entry == NULL)
1650  return EXIP_UNEXPECTED_ERROR;
1651  else if(base.entry->element == ELEMENT_COMPLEX_TYPE)
1652  {
1653  TRY(handleComplexTypeEl(ctx, &base));
1654  TRY(getContentTypeProtoGrammar(ctx, &base, &contentTypeGrammarBase));
1655  }
1656  else if(base.entry->element == ELEMENT_SIMPLE_TYPE)
1657  {
1658  // When <complexContent> is used, the base type must be a complexType. Base simpleType is an error.
1659  return EXIP_UNEXPECTED_ERROR;
1660  }
1661  else
1662  {
1663  return EXIP_UNEXPECTED_ERROR;
1664  }
1665 
1666  TRY(getContentTypeProtoGrammar(ctx, extEntry, &contentTypeGrammarExt));
1667 
1668  contGrArr[0] = contentTypeGrammarBase;
1669  contGrArr[1] = contentTypeGrammarExt;
1670 
1671  TRY(createSequenceModelGroupsGrammar(contGrArr, 2, resultProtoGrammar));
1672  if(contentTypeGrammarBase != NULL)
1673  destroyProtoGrammar(contentTypeGrammarBase);
1674  if(contentTypeGrammarExt != NULL)
1675  destroyProtoGrammar(contentTypeGrammarExt);
1676 
1677  *ext = resultProtoGrammar;
1678 
1679  return EXIP_OK;
1680 }
1681 
1682 static errorCode getRestrictionSimpleProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* resEntry, ProtoGrammar** restr)
1683 {
1684  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
1685  ProtoGrammar* simpleRestrictedGrammar;
1686  QNameID baseTypeID;
1687  SimpleType newSimpleType;
1688  Index typeId;
1689  Index simpleTypeId;
1690  TreeTableEntry* tmpEntry;
1691  unsigned int enumCount = 0; // the number of <xs:enumeration in the restriction>
1692 
1694  {
1695  // No base type defined. There should be an anonymous simple type
1696  if(resEntry->entry->child.entry != NULL && resEntry->entry->child.entry->element == ELEMENT_SIMPLE_TYPE)
1697  {
1698  // Very weird use case of the XSD spec. Does not bring any useful features. Ignored for now.
1699  return EXIP_NOT_IMPLEMENTED_YET;
1700  }
1701  else
1702  return EXIP_UNEXPECTED_ERROR;
1703  }
1704  else
1705  {
1706  TRY(getTypeQName(ctx->schema, resEntry->treeT, resEntry->entry->attributePointers[ATTRIBUTE_BASE], &baseTypeID));
1707  TRY(getTypeId(ctx, baseTypeID, &resEntry->entry->supertype, &typeId));
1708  }
1709 
1710  newSimpleType.content = ctx->schema->simpleTypeTable.sType[typeId].content;
1711  // remove the presence of named subtype
1713  newSimpleType.max = ctx->schema->simpleTypeTable.sType[typeId].max;
1714  newSimpleType.min = ctx->schema->simpleTypeTable.sType[typeId].min;
1715  newSimpleType.length = ctx->schema->simpleTypeTable.sType[typeId].length;
1716 
1717  tmpEntry = resEntry->entry->child.entry;
1718 
1719  while(tmpEntry != NULL)
1720  {
1721  if(tmpEntry->element == ELEMENT_MIN_INCLUSIVE)
1722  {
1724  TRY(stringToInt64(&tmpEntry->attributePointers[ATTRIBUTE_VALUE], &newSimpleType.min));
1725  }
1726  else if(tmpEntry->element == ELEMENT_MIN_EXCLUSIVE)
1727  {
1729  TRY(stringToInt64(&tmpEntry->attributePointers[ATTRIBUTE_VALUE], &newSimpleType.min));
1730  }
1731  else if(tmpEntry->element == ELEMENT_MIN_LENGTH)
1732  {
1734  TRY(stringToInt64(&tmpEntry->attributePointers[ATTRIBUTE_VALUE], &newSimpleType.min));
1735  }
1736  else if(tmpEntry->element == ELEMENT_MAX_INCLUSIVE)
1737  {
1739  TRY(stringToInt64(&tmpEntry->attributePointers[ATTRIBUTE_VALUE], &newSimpleType.max));
1740  }
1741  else if(tmpEntry->element == ELEMENT_MAX_EXCLUSIVE)
1742  {
1744  TRY(stringToInt64(&tmpEntry->attributePointers[ATTRIBUTE_VALUE], &newSimpleType.max));
1745  }
1746  else if(tmpEntry->element == ELEMENT_MAX_LENGTH)
1747  {
1749  TRY(stringToInt64(&tmpEntry->attributePointers[ATTRIBUTE_VALUE], &newSimpleType.max));
1750  }
1751  else if(tmpEntry->element == ELEMENT_LENGTH)
1752  {
1753  int ml = 0;
1754  SET_TYPE_FACET(newSimpleType.content, TYPE_FACET_LENGTH);
1756  newSimpleType.length = (unsigned int) ml;
1757  }
1758  else if(tmpEntry->element == ELEMENT_TOTAL_DIGITS)
1759  {
1760  int totalDigits = 0;
1762  TRY(stringToInteger(&tmpEntry->attributePointers[ATTRIBUTE_VALUE], &totalDigits));
1763  newSimpleType.length = newSimpleType.length | (((uint32_t) totalDigits) << 16);
1764  }
1765  else if(tmpEntry->element == ELEMENT_FRACTION_DIGITS)
1766  {
1767  int fractionDigits = 0;
1769  TRY(stringToInteger(&tmpEntry->attributePointers[ATTRIBUTE_VALUE], &fractionDigits));
1770  newSimpleType.length = newSimpleType.length | ((uint16_t) fractionDigits);
1771  }
1772  else if(tmpEntry->element == ELEMENT_PATTERN)
1773  {
1774  SET_TYPE_FACET(newSimpleType.content, TYPE_FACET_PATTERN);
1775  // TODO: needs to be implemented. It is also needed for the XML Schema grammars
1776  // COMMENT #SCHEMA#: ignore for now
1777  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Type facet pattern is not implemented: at %s, line %d.", __FILE__, __LINE__));
1778 // return EXIP_NOT_IMPLEMENTED_YET;
1779  }
1780  else if(tmpEntry->element == ELEMENT_WHITE_SPACE)
1781  {
1783  return EXIP_NOT_IMPLEMENTED_YET;
1784  }
1785  else if(tmpEntry->element == ELEMENT_ENUMERATION)
1786  {
1787  enumCount += 1;
1788  }
1789  else
1790  return EXIP_UNEXPECTED_ERROR;
1791 
1792  tmpEntry = tmpEntry->next;
1793  }
1794 
1795  // check if the EXI type has changed after the restrictions
1796  // Possible transitions are from VALUE_TYPE_INTEGER to VALUE_TYPE_NON_NEGATIVE_INT or VALUE_TYPE_SMALL_INTEGER
1797  // OR from VALUE_TYPE_NON_NEGATIVE_INT to VALUE_TYPE_SMALL_INTEGER
1798  if(GET_EXI_TYPE(newSimpleType.content) == VALUE_TYPE_INTEGER || GET_EXI_TYPE(newSimpleType.content) == VALUE_TYPE_NON_NEGATIVE_INT)
1799  {
1800  if(HAS_TYPE_FACET(newSimpleType.content, TYPE_FACET_MIN_INCLUSIVE))
1801  {
1802  if(newSimpleType.min >= 0)
1804 
1805  if(HAS_TYPE_FACET(newSimpleType.content, TYPE_FACET_MAX_INCLUSIVE))
1806  {
1807  if(newSimpleType.max - newSimpleType.min + 1 <= 4096)
1809  }
1810  else if(HAS_TYPE_FACET(newSimpleType.content, TYPE_FACET_MAX_EXCLUSIVE))
1811  {
1812  if(newSimpleType.max - newSimpleType.min <= 4096)
1814  }
1815  }
1816  else if(HAS_TYPE_FACET(newSimpleType.content, TYPE_FACET_MIN_EXCLUSIVE))
1817  {
1818  if(newSimpleType.min >= -1)
1820 
1821  if(HAS_TYPE_FACET(newSimpleType.content, TYPE_FACET_MAX_EXCLUSIVE))
1822  {
1823  if(newSimpleType.max - newSimpleType.min - 1 <= 4096)
1825  }
1826  else if(HAS_TYPE_FACET(newSimpleType.content, TYPE_FACET_MAX_INCLUSIVE))
1827  {
1828  if(newSimpleType.max - newSimpleType.min <= 4096)
1830  }
1831 
1832  }
1833  }
1834 
1835  // Handling of enumerations
1836  if(enumCount > 0) // There are enumerations defined
1837  {
1838  struct TreeTableEntry* enumEntry;
1839  unsigned int enumIter = 0;
1840  size_t valSize = 0;
1841  EnumDefinition eDef;
1842  Index elId;
1843 
1844  eDef.count = enumCount;
1845  eDef.values = NULL;
1846  /* The next index in the simpleTypeTable will be assigned to the newly created simple type
1847  * containing the enumeration */
1848  eDef.typeId = ctx->schema->simpleTypeTable.count;
1849 
1851 
1852  switch(GET_EXI_TYPE(ctx->schema->simpleTypeTable.sType[typeId].content))
1853  {
1854  case VALUE_TYPE_STRING:
1855  valSize = sizeof(String);
1856  break;
1857  case VALUE_TYPE_BOOLEAN:
1858  valSize = sizeof(char);
1859  break;
1860  case VALUE_TYPE_DATE_TIME:
1861  case VALUE_TYPE_YEAR:
1862  case VALUE_TYPE_DATE:
1863  case VALUE_TYPE_MONTH:
1864  case VALUE_TYPE_TIME:
1865  valSize = sizeof(EXIPDateTime);
1866  break;
1867  case VALUE_TYPE_DECIMAL:
1868  valSize = sizeof(Decimal);
1869  break;
1870  case VALUE_TYPE_FLOAT:
1871  valSize = sizeof(Float);
1872  break;
1873  case VALUE_TYPE_INTEGER:
1874  valSize = sizeof(Integer);
1875  break;
1877  valSize = sizeof(uint16_t);
1878  break;
1880  valSize = sizeof(UnsignedInteger);
1881  break;
1882  }
1883 
1884  eDef.values = memManagedAllocate(&ctx->schema->memList, valSize*(eDef.count));
1885  if(eDef.values == NULL)
1887 
1888  enumEntry = resEntry->entry->child.entry;
1889  while(enumEntry != NULL)
1890  {
1891  if(enumEntry->element == ELEMENT_ENUMERATION)
1892  {
1893  switch(GET_EXI_TYPE(ctx->schema->simpleTypeTable.sType[typeId].content))
1894  {
1895  case VALUE_TYPE_STRING:
1896  {
1897  String tmpStr;
1898 
1899  TRY(cloneStringManaged(&enumEntry->attributePointers[ATTRIBUTE_VALUE], &tmpStr, &ctx->schema->memList));
1900 
1901  ((String*) eDef.values)[enumIter].length = tmpStr.length;
1902  ((String*) eDef.values)[enumIter].str = tmpStr.str;
1903  }
1904  break;
1905  case VALUE_TYPE_BOOLEAN:
1906  return EXIP_NOT_IMPLEMENTED_YET;
1907  break;
1908  case VALUE_TYPE_DATE_TIME:
1909  case VALUE_TYPE_YEAR:
1910  case VALUE_TYPE_DATE:
1911  case VALUE_TYPE_MONTH:
1912  case VALUE_TYPE_TIME:
1913  return EXIP_NOT_IMPLEMENTED_YET;
1914  break;
1915  case VALUE_TYPE_DECIMAL:
1916  return EXIP_NOT_IMPLEMENTED_YET;
1917  break;
1918  case VALUE_TYPE_FLOAT:
1919  return EXIP_NOT_IMPLEMENTED_YET;
1920  break;
1921  case VALUE_TYPE_INTEGER:
1922  return EXIP_NOT_IMPLEMENTED_YET;
1923  break;
1925  return EXIP_NOT_IMPLEMENTED_YET;
1926  break;
1928  {
1929  int64_t tmpInt;
1930 
1931  TRY(stringToInt64(&enumEntry->attributePointers[ATTRIBUTE_VALUE], &tmpInt));
1932  ((UnsignedInteger*) eDef.values)[enumIter] = (UnsignedInteger) tmpInt;
1933  }
1934  break;
1935  default:
1936  return EXIP_NOT_IMPLEMENTED_YET;
1937  }
1938  }
1939  enumEntry = enumEntry->next;
1940  enumIter++;
1941  }
1942 
1943  TRY(addDynEntry(&ctx->schema->enumTable.dynArray, &eDef, &elId));
1944  }
1945 
1946  TRY(addDynEntry(&ctx->schema->simpleTypeTable.dynArray, &newSimpleType, &simpleTypeId));
1947 
1948  simpleRestrictedGrammar = (ProtoGrammar*) memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
1949  if(simpleRestrictedGrammar == NULL)
1951 
1952  TRY(createSimpleTypeGrammar(simpleTypeId, simpleRestrictedGrammar));
1953  *restr = simpleRestrictedGrammar;
1954 
1955  return EXIP_OK;
1956 }
1957 
1958 static errorCode getRestrictionComplexProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* resEntry, ProtoGrammar** restr)
1959 {
1960  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
1961  QNameID baseTypeId;
1962 
1963 #if DEBUG_GRAMMAR_GEN == ON && EXIP_DEBUG_LEVEL == INFO
1964  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Handle ComplexContent Restriction: "));
1966 #endif
1967 
1968  TRY(getTypeQName(ctx->schema, resEntry->treeT, resEntry->entry->attributePointers[ATTRIBUTE_BASE], &baseTypeId));
1969 
1970  // Restriction from a complex type only
1971 
1972  if((baseTypeId.uriId == XML_SCHEMA_NAMESPACE_ID && baseTypeId.lnId == SIMPLE_TYPE_ANY_TYPE) || // "xs:anyType"
1973  (resEntry->entry->supertype.entry != NULL && resEntry->entry->supertype.entry->element == ELEMENT_COMPLEX_TYPE))
1974  {
1975  TRY(getContentTypeProtoGrammar(ctx, resEntry, restr));
1976  }
1977  else
1978  {
1979  /* When <complexContent> is used, the base type must
1980  be a complexType. Base simpleType is an error.*/
1981  return EXIP_UNEXPECTED_ERROR;
1982  }
1983 
1984  return EXIP_OK;
1985 }
1986 
1987 static errorCode getTypeId(BuildContext* ctx, const QNameID typeQnameId, QualifiedTreeTableEntry* typeEntry, Index* typeId)
1988 {
1989  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
1990 
1991  assert(typeEntry != NULL);
1992 
1993  if(typeQnameId.uriId == XML_SCHEMA_NAMESPACE_ID &&
1994  typeQnameId.lnId < SIMPLE_TYPE_COUNT) // == http://www.w3.org/2001/XMLSchema i.e. build-in type
1995  {
1996  *typeId = typeQnameId.lnId;
1997  }
1998  else
1999  {
2000  if(GET_LN_URI_QNAME(ctx->schema->uriTable, typeQnameId).typeGrammar == INDEX_MAX)
2001  {
2002  // The EXIP grammars are not yet created for that simple type
2003  if(typeEntry->entry == NULL)
2004  return EXIP_UNEXPECTED_ERROR;
2005  else if(typeEntry->entry->element == ELEMENT_SIMPLE_TYPE)
2006  {
2007  TRY(handleSimpleTypeEl(ctx, typeEntry));
2008  }
2009  else if(typeEntry->entry->element == ELEMENT_COMPLEX_TYPE)
2010  {
2011  // Only simple types should be passed and have a valid typeId
2012  return EXIP_UNEXPECTED_ERROR;
2013  }
2014  else
2015  {
2016  return EXIP_UNEXPECTED_ERROR;
2017  }
2018 
2019  }
2020 
2021  *typeId = (GET_TYPE_GRAMMAR_QNAMEID(ctx->schema, typeQnameId))->rule[0].production[0].typeId;
2022  if(*typeId == INDEX_MAX)
2023  return EXIP_UNEXPECTED_ERROR;
2024  }
2025 
2026  return EXIP_OK;
2027 }
2028 
2029 static errorCode getAnonymousTypeId(BuildContext* ctx, QualifiedTreeTableEntry* typeEntry, Index* typeId)
2030 {
2031  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
2032  ProtoGrammar* tmpGr = NULL;
2033 
2034  assert(typeEntry != NULL);
2035 
2036  if(typeEntry->entry == NULL)
2037  return EXIP_UNEXPECTED_ERROR;
2038  else if(typeEntry->entry->element == ELEMENT_SIMPLE_TYPE)
2039  {
2040  TRY(getSimpleTypeProtoGrammar(ctx, typeEntry, &tmpGr));
2041  }
2042  else
2043  {
2044  return EXIP_UNEXPECTED_ERROR;
2045  }
2046 
2047  if(tmpGr == NULL)
2048  return EXIP_UNEXPECTED_ERROR;
2049 
2050  *typeId = tmpGr->rule[0].prod[0].typeId;
2051 
2052  destroyProtoGrammar(tmpGr);
2053 
2054  return EXIP_OK;
2055 }
2056 
2057 static errorCode getListProtoGrammar(BuildContext* ctx, QualifiedTreeTableEntry* listEntry, ProtoGrammar** list)
2058 {
2059  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
2060  Index itemTypeId = INDEX_MAX;
2061  SimpleType listSimpleType;
2062  Index listEntrySimplID;
2063 
2064  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Handle list"));
2065 
2066  *list = (ProtoGrammar*) memManagedAllocate(&ctx->tmpMemList, sizeof(ProtoGrammar));
2067  if(*list == NULL)
2069 
2070  listSimpleType.content = 0;
2071  SET_EXI_TYPE(listSimpleType.content, VALUE_TYPE_LIST);
2072  listSimpleType.max = 0;
2073  listSimpleType.min = 0;
2074  listSimpleType.length = 0;
2075 
2077  {
2078  QNameID itemTypeQnameId;
2079 
2080  // The list has item type a global simple type. It should not have child entries
2081  if(listEntry->entry->child.entry != NULL)
2082  return EXIP_UNEXPECTED_ERROR;
2083 
2084  TRY(getTypeQName(ctx->schema, listEntry->treeT, listEntry->entry->attributePointers[ATTRIBUTE_ITEM_TYPE], &itemTypeQnameId));
2085  TRY(getTypeId(ctx, itemTypeQnameId, &listEntry->entry->supertype, &itemTypeId));
2086  }
2087  else
2088  {
2089  TRY(getAnonymousTypeId(ctx, &listEntry->entry->child, &itemTypeId));
2090  }
2091 
2092  listSimpleType.length = itemTypeId;
2093 
2094  TRY(addDynEntry(&ctx->schema->simpleTypeTable.dynArray, &listSimpleType, &listEntrySimplID));
2095  TRY(createSimpleTypeGrammar(listEntrySimplID, *list));
2096 
2097  return EXIP_OK;
2098 }
2099 
2100 static errorCode storeGrammar(BuildContext* ctx, QNameID qnameID, ProtoGrammar* pGrammar, boolean isNillable, Index* grIndex)
2101 {
2102  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
2103  EXIGrammar exiGr;
2104 
2105  if(pGrammar == NULL)
2106  {
2107  exiGr = static_grammar_empty;
2108  if(ctx->emptyGrIndex == INDEX_MAX)
2109  {
2110  TRY(addDynEntry(&ctx->schema->grammarTable.dynArray, &exiGr, &ctx->emptyGrIndex));
2111  }
2112 
2113  *grIndex = ctx->emptyGrIndex;
2114  }
2115  else
2116  {
2117  assignCodes(pGrammar);
2118 
2119  TRY(convertProtoGrammar(&ctx->schema->memList, pGrammar, &exiGr));
2120 
2121  if(isNillable)
2122  SET_NILLABLE_GR(exiGr.props);
2123 
2124  // The grammar has a content2 grammar if and only if there are AT
2125  // productions that point to the content grammar rule OR the content index is 0.
2126  if(GET_CONTENT_INDEX(exiGr.props) == 0)
2127  SET_HAS_CONTENT2(exiGr.props);
2128  else
2129  {
2130  Index r, p;
2131  boolean prodFound = FALSE;
2132  for(r = 0; r < GET_CONTENT_INDEX(exiGr.props); r++)
2133  {
2134  for(p = 0; p < RULE_GET_AT_COUNT(exiGr.rule[r].meta); p++)
2135  {
2136  if(GET_PROD_NON_TERM(exiGr.rule[r].production[exiGr.rule[r].pCount-1-p].content) == GET_CONTENT_INDEX(exiGr.props))
2137  {
2138  SET_HAS_CONTENT2(exiGr.props);
2139  prodFound = TRUE;
2140  break;
2141  }
2142  }
2143  if(prodFound)
2144  break;
2145  }
2146  }
2147 
2148  TRY(addDynEntry(&ctx->schema->grammarTable.dynArray, &exiGr, grIndex));
2149  destroyProtoGrammar(pGrammar);
2150  }
2151 
2152 #if DEBUG_GRAMMAR_GEN == ON && EXIP_DEBUG_LEVEL == INFO
2153  {
2154  SmallIndex t = 0;
2155 
2156  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Stored grammar ["));
2157  printString(&ctx->schema->uriTable.uri[qnameID.uriId].uriStr);
2158  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, (":"));
2159  printString(&GET_LN_URI_QNAME(ctx->schema->uriTable, qnameID).lnStr);
2160  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("]:"));
2161  for(t = 0; t < exiGr.count; t++)
2162  {
2163  TRY(printGrammarRule(t, &(exiGr.rule[t]), ctx->schema));
2164  }
2165  }
2166 #endif
2167 
2168  return EXIP_OK;
2169 }
2170 
2171 static int compareGlobalElemQName(const void* QNameId1, const void* QNameId2)
2172 {
2173  QNameID* q1 = (QNameID*) QNameId1;
2174  QNameID* q2 = (QNameID*) QNameId2;
2175 
2176  return compareQNameID(q1, q2, &globalSchemaPtr->uriTable);
2177 }
2178 
2179 static void sortGlobalElemQnameTable(GlobalElemQNameTable *gElTbl)
2180 {
2181  qsort(gElTbl->qname, gElTbl->count, sizeof(QNameID), compareGlobalElemQName);
2182 }
2183 
2184 static void sortEnumTable(EXIPSchema *schema)
2185 {
2186  qsort(schema->enumTable.enumDef, schema->enumTable.count, sizeof(EnumDefinition), compareEnumDefs);
2187 }
2188 
2189 static char isAttrAlreadyPresent(String aName, struct localAttrNames* lAttrTbl)
2190 {
2191  Index i;
2192 
2193  for(i = 0; i < lAttrTbl->count; i++)
2194  {
2195  if(stringEqual(aName, lAttrTbl->attrNames[i]))
2196  return TRUE;
2197  }
2198 
2199  return FALSE;
2200 }
2201 
2202 void assignCodes(ProtoGrammar* grammar)
2203 {
2204  Index i = 0;
2205 
2206  for (i = 0; i < grammar->count; i++)
2207  {
2208  qsort(grammar->rule[i].prod, grammar->rule[i].count, sizeof(Production), compareProductions);
2209  }
2210 }
2211 
2212 static int compareProductions(const void* prod1, const void* prod2)
2213 {
2214  Production* p1 = (Production*) prod1;
2215  Production* p2 = (Production*) prod2;
2216 
2218  return 1;
2220  return -1;
2221  else // the same event Type
2222  {
2224  {
2225  return -compareQNameID(&(p1->qnameId), &(p2->qnameId), &globalSchemaPtr->uriTable);
2226  }
2227  else if(GET_PROD_EXI_EVENT(p1->content) == EVENT_AT_URI)
2228  {
2229  if(p1->qnameId.uriId < p2->qnameId.uriId)
2230  {
2231  return 1;
2232  }
2233  else if(p1->qnameId.uriId > p2->qnameId.uriId)
2234  {
2235  return -1;
2236  }
2237  else
2238  return 0;
2239  }
2240  else if(GET_PROD_EXI_EVENT(p1->content) == EVENT_SE_QNAME)
2241  {
2242  // TODO: figure out how it works??? if this really works for all cases. Seems very unlikely that it does!
2244  return 1;
2245  else
2246  return -1;
2247  }
2248  else if(GET_PROD_EXI_EVENT(p1->content) == EVENT_SE_URI)
2249  {
2250  // TODO: figure out how it should be done
2251  }
2252  return 0;
2253  }
2254 }
2255 
2256 static errorCode recursiveSubsitutionGroupAdd(BuildContext* ctx, QNameIDGrIndx headQGrIndex, struct subsGroupElTbl* subsElGrTbl)
2257 {
2258  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
2259  Index s, i;
2260  boolean isHeadFound = FALSE;
2261  QNameIDGrIndx subsEl;
2262 
2263  assert(subsElGrTbl != NULL);
2264  assert(subsElGrTbl->sGroupSet != NULL);
2265 
2266  /* Add the element itself to the set of element declaration avlb. through the chain of {substitution group affiliation} */
2267  TRY(addDynEntry(&subsElGrTbl->dynArray, (void*) &headQGrIndex, &s));
2268 
2269  /* I> check if the substitution head exists in subsTbl*/
2270  for(s = 0; s < ctx->subsTbl->count; s++)
2271  {
2272  if(ctx->subsTbl->head[s].headId.uriId == headQGrIndex.qnameId.uriId && ctx->subsTbl->head[s].headId.lnId == headQGrIndex.qnameId.lnId)
2273  {
2274  isHeadFound = TRUE;
2275  break;
2276  }
2277  }
2278  if(isHeadFound)
2279  {
2280  for(i = 0; i < ctx->subsTbl->head[s].count; i++)
2281  {
2282  TRY(handleElementEl(ctx, &ctx->subsTbl->head[s].substitutes[i], FALSE, &subsEl));
2283  /* First add the substitute itself then check if the substitute is head and if head itself add its substitute too*/
2284  TRY(recursiveSubsitutionGroupAdd(ctx, subsEl, subsElGrTbl));
2285  }
2286  }
2287 
2288  return EXIP_OK;
2289 }
2290 
2291 static int compareSubsitutionGroupMembers(const void* elem1, const void* elem2)
2292 {
2293  QNameIDGrIndx* a1 = (QNameIDGrIndx*) elem1;
2294  QNameIDGrIndx* a2 = (QNameIDGrIndx*) elem2;
2295 
2296  return -compareQNameID(&a1->qnameId, &a2->qnameId, &globalSchemaPtr->uriTable);
2297 }
2298 
2299 static void sortSubsitutionGroup(struct subsGroupElTbl* subsElGrTbl)
2300 {
2301  assert(subsElGrTbl->sGroupSet != NULL);
2302  qsort(subsElGrTbl->sGroupSet, subsElGrTbl->count, sizeof(QNameIDGrIndx), compareSubsitutionGroupMembers);
2303 }