exip  Alpha 0.5.4
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
treeTableManipulate.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 "memManagement.h"
20 #include "stringManipulate.h"
21 #include "sTables.h"
22 
23 #define TREE_TABLE_ENTRY_COUNT 200
24 
25 #define LOOKUP_TYPE 0
26 #define LOOKUP_REF 1
27 #define LOOKUP_SUPER_TYPE 2
28 #define LOOKUP_SUBSTITUTION 3
29 
30 extern const String XML_NAMESPACE;
31 extern const String XML_SCHEMA_INSTANCE;
32 extern const String XML_SCHEMA_NAMESPACE;
33 
34 extern const String URI_1_PFX; // The 'xml' prefix string
35 
36 #define MAX_INCLUDE_COUNT 50
37 
42 static errorCode lookupGlobalDefinition(EXIPSchema* schema, TreeTable* treeT, unsigned int count, unsigned int currTreeT, String* eName, unsigned char elType, TreeTableEntry* entry, SubstituteTable* subsTbl);
43 
47 static boolean checkForImportWithNs(TreeTable* treeT, String ns);
48 
50  errorCode (*loadSchemaHandler) (String* namespace, String* schemaLocation, BinaryBuffer** buffers, unsigned int* bufCount, SchemaFormat* schemaFormat, EXIOptions** opt))
51 {
52  // check if all <include> & <import> are refering to treeTable instances. If not call loadSchemaHandler
53  // for each unresolved referece. Build new corresponding treeTable incstance and add it to treeT array
54  // Use realloc and update the array count argument
55 
56  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
57  unsigned int i, j;
58  boolean treeTfound = FALSE;
59  Index g;
60  BinaryBuffer* newBuffers;
61  unsigned int bufCount = 0;
62  SchemaFormat schemaFormat;
63  EXIOptions* options;
64  unsigned int includeTblIndex[MAX_INCLUDE_COUNT];
65  unsigned int includeCnt, tmpInclCnt;
66 
67 
68  for(i = 0; i < *count; i++)
69  {
70  includeCnt = 0;
71  for (g = 0; g < (*treeT)[i].count; ++g)
72  {
73  if((*treeT)[i].tree[g].element == ELEMENT_REDEFINE ||
74  (*treeT)[i].tree[g].element == ELEMENT_ANNOTATION)
75  {
76  continue;
77  }
78  else if((*treeT)[i].tree[g].element == ELEMENT_INCLUDE)
79  {
80  if(includeCnt >= MAX_INCLUDE_COUNT)
82  includeTblIndex[includeCnt] = g;
83  includeCnt++;
84  }
85  else if((*treeT)[i].tree[g].element == ELEMENT_IMPORT)
86  {
87  treeTfound = FALSE;
88  for(j = 0; j < *count; j++)
89  {
90  if(j != i && stringEqual((*treeT)[i].tree[g].attributePointers[ATTRIBUTE_NAMESPACE], (*treeT)[j].globalDefs.targetNs))
91  {
92  treeTfound = TRUE;
93  break;
94  }
95  }
96 
97  if(treeTfound == FALSE)
98  {
99  if(loadSchemaHandler != NULL)
100  {
101  TRY(loadSchemaHandler(&(*treeT)[i].tree[g].attributePointers[ATTRIBUTE_NAMESPACE], &(*treeT)[i].tree[g].attributePointers[ATTRIBUTE_SCHEMA_LOCATION], &newBuffers,
102  &bufCount, &schemaFormat, &options));
103 
104  if(bufCount > 0)
105  {
106  void *tmpPtr;
107  unsigned int n;
108 
109  tmpPtr = EXIP_REALLOC(*treeT, sizeof(TreeTable)*(*count + bufCount));
110  if(tmpPtr == NULL)
112 
113  *treeT = tmpPtr;
114 
115  for(n = *count; n < *count + bufCount; n++)
116  {
117  TRY(initTreeTable(&(*treeT[n])));
118  }
119 
120  for(n = *count; n < *count + bufCount; n++)
121  {
122  TRY(generateTreeTable(newBuffers[n-*count], schemaFormat, options, &(*treeT[n]), schema));
123  }
124 
125  *count = (*count + bufCount);
126  }
127  else
128  {
129  DEBUG_MSG(WARNING, DEBUG_GRAMMAR_GEN, ("> loadSchemaHandler returns an empty list of BinaryBuffers"));
130  }
131  }
132  else
133  {
134  DEBUG_MSG(ERROR, DEBUG_GRAMMAR_GEN, ("> An <import> statement in schema cannot be resolved"));
136  }
137  }
138  }
139  else
140  {
141  break;
142  }
143  }
144 
145  if(includeCnt > 0)
146  {
147  treeTfound = FALSE;
148  tmpInclCnt = 0;
149  for(j = 0; j < *count; j++)
150  {
151  if(j != i && stringEqual((*treeT)[i].globalDefs.targetNs, (*treeT)[j].globalDefs.targetNs))
152  {
153  tmpInclCnt++;
154  if(tmpInclCnt < includeCnt)
155  continue;
156  else
157  {
158  treeTfound = TRUE;
159  break;
160  }
161  }
162  }
163 
164  if(treeTfound == FALSE)
165  {
166  if(loadSchemaHandler != NULL)
167  {
168  for(j = tmpInclCnt; j < includeCnt; j++)
169  {
170  TRY(loadSchemaHandler(NULL, &(*treeT)[i].tree[includeTblIndex[j]].attributePointers[ATTRIBUTE_SCHEMA_LOCATION], &newBuffers,
171  &bufCount, &schemaFormat, &options));
172 
173  if(bufCount > 0)
174  {
175  void *tmpPtr;
176  unsigned int n;
177 
178  tmpPtr = EXIP_REALLOC(*treeT, sizeof(TreeTable)*(*count + bufCount));
179  if(tmpPtr == NULL)
181 
182  *treeT = tmpPtr;
183 
184  for(n = *count; n < *count + bufCount; n++)
185  {
186  TRY(initTreeTable(&(*treeT[n])));
187  }
188 
189  for(n = *count; n < *count + bufCount; n++)
190  {
191  TRY(generateTreeTable(newBuffers[n-*count], schemaFormat, options, &(*treeT[n]), schema));
192  }
193 
194  *count = (*count + bufCount);
195  }
196  else
197  {
198  DEBUG_MSG(WARNING, DEBUG_GRAMMAR_GEN, ("> loadSchemaHandler returns an empty list of BinaryBuffers"));
199  }
200  }
201  }
202  else
203  {
204  DEBUG_MSG(ERROR, DEBUG_GRAMMAR_GEN, ("> An <include> statement in schema cannot be resolved"));
206  }
207  }
208  }
209  }
210 
211  return EXIP_OK;
212 }
213 
214 
226 static errorCode resolveEntry(EXIPSchema* schema, TreeTable* treeT, unsigned int count, unsigned int currTreeT, TreeTableEntry* entry);
227 
229 {
230  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
231 
232  TRY(initAllocList(&treeT->memList));
233 
236 
239  treeT->count = 0;
240  treeT->globalDefs.targetNsId = 0;
241 
242 #if HASH_TABLE_USE
243  // TODO: conditionally create the table, only if the schema is big.
244  // How to determine when the schema is big?
246  if(treeT->typeTbl == NULL)
247  return EXIP_HASH_TABLE_ERROR;
248 
250  if(treeT->elemTbl == NULL)
251  return EXIP_HASH_TABLE_ERROR;
252 
254  if(treeT->attrTbl == NULL)
255  return EXIP_HASH_TABLE_ERROR;
256 
258  if(treeT->groupTbl == NULL)
259  return EXIP_HASH_TABLE_ERROR;
260 
262  if(treeT->attrGroupTbl == NULL)
263  return EXIP_HASH_TABLE_ERROR;
264 #endif
265 
266  return EXIP_OK;
267 }
268 
270 {
271  destroyDynArray(&treeT->dynArray);
273 
274 #if HASH_TABLE_USE
275  if(treeT->typeTbl != NULL)
276  hashtable_destroy(treeT->typeTbl);
277 
278  if(treeT->elemTbl != NULL)
279  hashtable_destroy(treeT->elemTbl);
280 
281  if(treeT->attrTbl != NULL)
282  hashtable_destroy(treeT->attrTbl);
283 
284  if(treeT->groupTbl != NULL)
285  hashtable_destroy(treeT->groupTbl);
286 
287  if(treeT->attrGroupTbl != NULL)
288  hashtable_destroy(treeT->attrGroupTbl);
289 #endif
290  freeAllocList(&treeT->memList);
291 }
292 
293 errorCode resolveTypeHierarchy(EXIPSchema* schema, TreeTable* treeT, unsigned int count, SubstituteTable* subsTbl)
294 {
295  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
296  Index j;
297  unsigned int i;
298 
299  /* For every tree table (XSD file) */
300  for(i = 0; i < count; i++)
301  {
302  /* For every three table global entry */
303  for(j = 0; j < treeT[i].count; j++)
304  {
305  /* If element and substitution group defined -> add the substitute to the head in SubstituteTable.
306  * This check is here as the substitution group elements are only global elements by definition */
307  if(treeT[i].tree[j].element == ELEMENT_ELEMENT && !isStringEmpty(&treeT[i].tree[j].attributePointers[ATTRIBUTE_SUBSTITUTION_GROUP]))
308  {
309  #if DEBUG_GRAMMAR_GEN == ON && EXIP_DEBUG_LEVEL == INFO
310  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, ("\n>Substitution group "));
311  printString(&treeT[i].tree[j].attributePointers[ATTRIBUTE_SUBSTITUTION_GROUP]);
312  DEBUG_MSG(INFO, DEBUG_GRAMMAR_GEN, (" added: "));
313  printString(&treeT[i].tree[j].attributePointers[ATTRIBUTE_NAME]);
314  #endif
315 
316  TRY(lookupGlobalDefinition(schema, treeT, count, i, &treeT[i].tree[j].attributePointers[ATTRIBUTE_SUBSTITUTION_GROUP], LOOKUP_SUBSTITUTION, &treeT[i].tree[j], subsTbl));
317  }
318 
319  TRY(resolveEntry(schema, treeT, count, i, &treeT[i].tree[j]));
320  }
321  }
322  return EXIP_OK;
323 }
324 
325 static errorCode resolveEntry(EXIPSchema* schema, TreeTable* treeT, unsigned int count, unsigned int currTreeT, TreeTableEntry* entry)
326 {
327  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
328 
329  /* Recursively resolve entries through children first */
330  if(entry->child.entry != NULL)
331  {
332  TRY(resolveEntry(schema, treeT, count, currTreeT, entry->child.entry));
333  }
334 
335  /* Then through groups (linked by next pointer) */
336  if(entry->next != NULL)
337  {
338  TRY(resolveEntry(schema, treeT, count, currTreeT, entry->next));
339  }
340 
341  /* If elements, attributes, groups or attributeGroups -> link type to global types or
342  * link ref to global definitions. */
343  if((entry->element == ELEMENT_ELEMENT) ||
344  (entry->element == ELEMENT_ATTRIBUTE) ||
345  (entry->element == ELEMENT_GROUP) ||
346  (entry->element == ELEMENT_ATTRIBUTE_GROUP))
347  {
349  {
350  if(entry->child.entry != NULL) // TODO: add debug info
351  return EXIP_UNEXPECTED_ERROR;
352 
353  TRY(lookupGlobalDefinition(schema, treeT, count, currTreeT, &entry->attributePointers[ATTRIBUTE_TYPE], LOOKUP_TYPE, entry, NULL));
354  }
355  else if(!isStringEmpty(&entry->attributePointers[ATTRIBUTE_REF]))
356  {
357  if(entry->child.entry != NULL) // TODO: add debug info
358  return EXIP_UNEXPECTED_ERROR;
359 
360  TRY(lookupGlobalDefinition(schema, treeT, count, currTreeT, &entry->attributePointers[ATTRIBUTE_REF], LOOKUP_REF, entry, NULL));
361  }
362  }
363  /* If there are extensions or restrictions, link their base type to the supertype pointer */
364  else if(entry->element == ELEMENT_EXTENSION || entry->element == ELEMENT_RESTRICTION)
365  {
367  {
368  if(entry->supertype.entry != NULL) // TODO: add debug info
369  return EXIP_UNEXPECTED_ERROR;
370 
371  TRY(lookupGlobalDefinition(schema, treeT, count, currTreeT, &entry->attributePointers[ATTRIBUTE_BASE], LOOKUP_SUPER_TYPE, entry, NULL));
372  }
373  }
374  /* If there is a list, link its itemType to the supertype pointer */
375  else if(entry->element == ELEMENT_LIST)
376  {
378  {
379  if(entry->supertype.entry != NULL) // TODO: add debug info
380  return EXIP_UNEXPECTED_ERROR;
381 
382  TRY(lookupGlobalDefinition(schema, treeT, count, currTreeT, &entry->attributePointers[ATTRIBUTE_ITEM_TYPE], LOOKUP_SUPER_TYPE, entry, NULL));
383  }
384  }
385 
386  return EXIP_OK;
387 }
388 
389 static errorCode lookupGlobalDefinition(EXIPSchema* schema, TreeTable* treeT, unsigned int count, unsigned int currTreeT, String* eName, unsigned char elType, TreeTableEntry* entry, SubstituteTable* subsTbl)
390 {
391  Index i;
392  Index globalIndex = INDEX_MAX;
393  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
394  QNameID typeQnameID;
395  unsigned int j;
396 
397  TRY(getTypeQName(schema, &treeT[currTreeT], *eName, &typeQnameID));
398 
399  for(i = 0; i < count; i++)
400  {
401  if(treeT[i].globalDefs.targetNsId == typeQnameID.uriId)
402  {
403 #if HASH_TABLE_USE
404  /* Use the hash table to do a fast lookup of the tree table index matching the global name */
405  if(treeT[i].typeTbl != NULL && treeT[i].elemTbl != NULL && treeT[i].attrTbl != NULL &&
406  treeT[i].groupTbl != NULL && treeT[i].attrGroupTbl != NULL)
407  {
408  if(elType == LOOKUP_TYPE || elType == LOOKUP_SUPER_TYPE)
409  globalIndex = hashtable_search(treeT[i].typeTbl, GET_LN_URI_QNAME(schema->uriTable, typeQnameID).lnStr);
410  else if(entry->element == ELEMENT_ELEMENT) // LOOKUP_REF ELEMENT
411  globalIndex = hashtable_search(treeT[i].elemTbl, GET_LN_URI_QNAME(schema->uriTable, typeQnameID).lnStr);
412  else if(entry->element == ELEMENT_ATTRIBUTE) // LOOKUP_REF ATTRIBUTE
413  globalIndex = hashtable_search(treeT[i].attrTbl, GET_LN_URI_QNAME(schema->uriTable, typeQnameID).lnStr);
414  else if(entry->element == ELEMENT_GROUP) // LOOKUP_REF GROUP
415  globalIndex = hashtable_search(treeT[i].groupTbl, GET_LN_URI_QNAME(schema->uriTable, typeQnameID).lnStr);
416  else if(entry->element == ELEMENT_ATTRIBUTE_GROUP) // LOOKUP_REF ATTRIBUTE_GROUP
417  globalIndex = hashtable_search(treeT[i].attrGroupTbl, GET_LN_URI_QNAME(schema->uriTable, typeQnameID).lnStr);
418 
419  }
420  else
421 #endif
422  {
423  /* Do a linear search through the tree table entry until we find it */
424  for(j = 0; j < treeT[i].count; j++)
425  {
426  if(stringEqual(treeT[i].tree[j].attributePointers[ATTRIBUTE_NAME], GET_LN_URI_QNAME(schema->uriTable, typeQnameID).lnStr))
427  {
428  /* If search for global type and the found entry is indeed a simple or complex type */
429  if((elType == LOOKUP_TYPE || elType == LOOKUP_SUPER_TYPE) && (treeT[i].tree[j].element == ELEMENT_SIMPLE_TYPE || treeT[i].tree[j].element == ELEMENT_COMPLEX_TYPE))
430  {
431  globalIndex = j;
432  break;
433  }
434  /* Or if search for REF to element/attr/group/groupAttr or substitutionHead => the entry type must be the same as the one we found*/
435  else if((elType == LOOKUP_REF || elType == LOOKUP_SUBSTITUTION) || (treeT[i].tree[j].element == entry->element))
436  {
437  globalIndex = j;
438  break;
439  }
440  }
441  }
442  }
443  if(globalIndex != INDEX_MAX)
444  break;
445  }
446  }
447 
449  if(i == count)
450  {
451  if(typeQnameID.uriId == 0 || typeQnameID.uriId > 3)
452  {
453  // The requested target namespace is not a built-in type namespace
454  return EXIP_UNEXPECTED_ERROR;
455  }
456  }
457 
458  if(globalIndex == INDEX_MAX)
459  {
460  // For types search: The type must be build-in or the schema is buggy - do nothing here; it will be checked later
461  if(elType == LOOKUP_REF || elType == LOOKUP_SUBSTITUTION)
462  return EXIP_UNEXPECTED_ERROR; // TODO: add debug info
463  }
464  else
465  {
466  if(elType == LOOKUP_SUPER_TYPE)
467  {
468  entry->supertype.treeT = &treeT[i];
469  entry->supertype.entry = &treeT[i].tree[globalIndex];
470  }
471  else if (elType == LOOKUP_SUBSTITUTION)
472  {
473  Index s;
474  boolean isHeadFound = FALSE;
476 
477  assert(subsTbl != NULL);
478 
479  /* I> check if the head already exists in subsTbl*/
480  for(s = 0; s < subsTbl->count; s++)
481  {
482  if(subsTbl->head[s].headId.uriId == typeQnameID.uriId && subsTbl->head[s].headId.lnId == typeQnameID.lnId)
483  {
484  isHeadFound = TRUE;
485  break;
486  }
487  }
488 
489  /* II> if no such head exists create one */
490  if(!isHeadFound)
491  {
492  SubtGroupHead newHead;
493  newHead.headId = typeQnameID;
494  TRY(createDynArray(&newHead.dynArray, sizeof(QualifiedTreeTableEntry), 5));
495 
496  TRY(addDynEntry(&subsTbl->dynArray, (void*) &newHead, &s));
497  }
498 
499  /* III> add the substitute to the head */
500  qEntry.treeT = &treeT[currTreeT];
501  qEntry.entry = entry;
502  TRY(addDynEntry(&subsTbl->head[s].dynArray, (void*) &qEntry, &s));
503  }
504  else
505  {
506  entry->child.treeT = &treeT[i];
507  entry->child.entry = &treeT[i].tree[globalIndex];
508  }
509  }
510 
511  return EXIP_OK;
512 }
513 
514 errorCode getTypeQName(EXIPSchema* schema, TreeTable* treeT, const String typeLiteral, QNameID* qNameID)
515 {
516  Index indx;
517  String lnStr;
518  String uriStr;
519  Index i;
520  boolean pfxFound = FALSE;
521 
522  /*
523  * The type literal string passed in will be in the form of either:
524  * <prefix>:<type name>
525  * or
526  * <type name>
527  * See if there is a prefix to separate out
528  */
529  indx = getIndexOfChar(&typeLiteral, ':');
530 
531  if(indx != INDEX_MAX)
532  {
533  /* There is a prefix defined. Search the table for a namespace URI which matches the prefix */
534  /* 'Borrow' the uriStr for search use */
535  uriStr.length = indx;
536  uriStr.str = typeLiteral.str;
537 
538  for(i = 0; i < treeT->globalDefs.pfxNsTable.count; i++)
539  {
540  if(stringEqual(uriStr, treeT->globalDefs.pfxNsTable.pfxNs[i].pfx))
541  {
542  pfxFound = TRUE;
543  break;
544  }
545  }
546 
547  if(pfxFound)
548  {
549  /* Replace with URI of actual namespace */
550  uriStr = treeT->globalDefs.pfxNsTable.pfxNs[i].ns;
551  }
552  else
553  {
554  // see http://www.w3.org/XML/1998/namespace
555  if(stringEqual(uriStr, URI_1_PFX))
556  {
557  uriStr = XML_NAMESPACE;
558  }
559  else
560  {
561  DEBUG_MSG(ERROR, DEBUG_GRAMMAR_GEN, (">Invalid schema base type definition\n"));
562  return EXIP_INVALID_EXI_INPUT;
563  }
564  }
565 
566  /* Adjust the length of the remaining type name and assign the string */
567  lnStr.length = typeLiteral.length - indx - 1;
568  lnStr.str = typeLiteral.str + indx + 1;
569  }
570  else
571  {
572  /* There is no prefix defined. Search the table for a namespace URI with a void prefix */
573  for(i = 0; i < treeT->globalDefs.pfxNsTable.count; i++)
574  {
576  {
577  pfxFound = TRUE;
578  break;
579  }
580  }
581 
582  if(pfxFound)
583  {
584  /* Replace with URI of actual namespace (void in this case) */
585  uriStr = treeT->globalDefs.pfxNsTable.pfxNs[i].ns;
586  }
587  else
588  {
589  /* Replace with URI with empty string */
590  getEmptyString(&uriStr);
591  }
592 
593  /* The type name is the whole string */
594  lnStr.length = typeLiteral.length;
595  lnStr.str = typeLiteral.str;
596  }
597 
598  if(!lookupUri(&schema->uriTable, uriStr, &qNameID->uriId))
599  return EXIP_INVALID_EXI_INPUT;
600  if(!lookupLn(&schema->uriTable.uri[qNameID->uriId].lnTable, lnStr, &qNameID->lnId))
601  return EXIP_INVALID_EXI_INPUT;
602 
603  // http://www.w3.org/TR/xmlschema11-1/#sec-src-resolve
604  // Validation checks:
605  // The appropriate case among the following must be true:
606  // 4.1 If the namespace name of the QName is absent, then one of the following must be true:
607  // 4.1.1 The <schema> element information item of the schema document containing the QName has no targetNamespace [attribute].
608  // 4.1.2 The <schema> element information item of the that schema document contains an <import> element information item with no namespace [attribute].
609  // 4.2 otherwise the namespace name of the QName is the same as one of the following:
610  // 4.2.1 The actual value of the targetNamespace [attribute] of the <schema> element information item of the schema document containing the QName.
611  // 4.2.2 The actual value of the namespace [attribute] of some <import> element information item contained in the <schema> element information item of that schema document.
612  // 4.2.3 http://www.w3.org/2001/XMLSchema.
613  // 4.2.4 http://www.w3.org/2001/XMLSchema-instance.
614 
615  if(isStringEmpty(&uriStr)) // 4.1
616  {
617  // Check 4.1.1 and 4.1.2
618  if(treeT->globalDefs.targetNsId != 0 && !checkForImportWithNs(treeT, uriStr))
619  {
620  return EXIP_INVALID_EXI_INPUT;
621  }
622  }
623  else if(!stringEqual(uriStr, XML_SCHEMA_NAMESPACE) && !stringEqual(uriStr, XML_SCHEMA_INSTANCE)) // 4.2
624  {
625  // Check 4.2.1 and 4.2.2
626  if(treeT->globalDefs.targetNsId != qNameID->uriId && !checkForImportWithNs(treeT, uriStr))
627  {
628  return EXIP_INVALID_EXI_INPUT;
629  }
630  }
631 
632  return EXIP_OK;
633 }
634 
635 static boolean checkForImportWithNs(TreeTable* treeT, String ns)
636 {
637  Index i;
638 
639  for (i = 0; i < treeT->count; ++i)
640  {
641  if(treeT->tree[i].element == ELEMENT_INCLUDE ||
642  treeT->tree[i].element == ELEMENT_REDEFINE ||
643  treeT->tree[i].element == ELEMENT_ANNOTATION)
644  {
645  continue;
646  }
647  else if(treeT->tree[i].element == ELEMENT_IMPORT)
648  {
650  {
651  return TRUE;
652  }
653  }
654  else
655  {
656  break;
657  }
658  }
659 
660  return FALSE;
661 }
662 
663 errorCode getNsList(TreeTable* treeT, String nsList, NsTable* nsTable)
664 {
665  errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
666  Index dummy_elemID;
667 
668  if(isStringEmpty(&nsList))
669  return EXIP_OK;
670  else
671  {
672  Index sChIndex;
673  String attrNamespece;
674 
675  attrNamespece.length = nsList.length;
676  attrNamespece.str = nsList.str;
677  sChIndex = getIndexOfChar(&attrNamespece, ' ');
678 
679  while(sChIndex != INDEX_MAX)
680  {
681  String tmpNS;
682  tmpNS.length = sChIndex;
683  tmpNS.str = attrNamespece.str;
684 
685  if(stringEqualToAscii(tmpNS, "##targetNamespace"))
686  {
687  tmpNS = treeT->globalDefs.targetNs;
688  }
689  if(stringEqualToAscii(tmpNS, "##local"))
690  {
691  getEmptyString(&tmpNS);
692  }
693 
694  TRY(addDynEntry(&nsTable->dynArray, &tmpNS, &dummy_elemID));
695 
696  attrNamespece.length = attrNamespece.length - sChIndex - 1;
697  attrNamespece.str = attrNamespece.str + sChIndex + 1;
698 
699  sChIndex = getIndexOfChar(&attrNamespece, ' ');
700  }
701 
702  TRY(addDynEntry(&nsTable->dynArray, &attrNamespece, &dummy_elemID));
703  }
704  return EXIP_OK;
705 }