1 /*****************************************************************************/
2 /* Software Testing Automation Framework (STAF)                              */
3 /* (C) Copyright IBM Corp. 2001                                              */
4 /*                                                                           */
5 /* This software is licensed under the Eclipse Public License (EPL) V1.0.    */
6 /*****************************************************************************/
7 
8 #include "STAF.h"
9 #include "STAFUtil.h"
10 #include "STAFRefPtr.h"
11 #include "STAFException.h"
12 #include <deque>
13 #include <map>
14 
15 typedef std::deque<STAFObject_t> STAFObjectList;
16 typedef std::map<STAFString, STAFObject_t> STAFObjectMap;
17 
18 enum STAFObjectIteratorType_t
19 {
20     kSTAFObjectListIterator     = 0,
21     kSTAFObjectMapKeyIterator   = 1,
22     kSTAFObjectMapValueIterator = 2
23 };
24 
25 struct STAFObjectListIterator
26 {
27     STAFObjectList::iterator iter;
28     STAFObjectList *listObject;
29 };
30 
31 struct STAFObjectMapIterator
32 {
33     STAFObjectMap::iterator iter;
34     STAFObjectMap *mapObject;
35 };
36 
37 struct STAFObjectIteratorImpl
38 {
39     STAFObjectIteratorType_t type;
40 
41     union
42     {
43         STAFObjectListIterator *listIterator;
44         STAFObjectMapIterator *mapIterator;
45     };
46 };
47 
48 
49 struct STAFObjectMarshallingContext
50 {
51     STAFObject_t mapClassMap;
52     STAFObject_t rootObject;
53 };
54 
55 
56 struct STAFObjectImpl
57 {
58     STAFObjectType_t type;
59     bool isRef;
60 
61     union
62     {
63         STAFObjectList               *listValue;
64         STAFObjectMap                *mapValue;
65         STAFObjectMarshallingContext *contextValue;
66         STAFString                   *scalarStringValue;
67     };
68 };
69 
70 
71 static STAFObjectImpl sNoneObj = { kSTAFNoneObject, true };
72 static STAFObject_t sNoneObjT = &sNoneObj;
73 static STAFString sColon(kUTF8_COLON);
74 
incrementNChars(const STAFString & theString,const unsigned int beginIndex,const unsigned int incrementLength)75 inline unsigned int incrementNChars(const STAFString &theString,
76                                     const unsigned int beginIndex,
77                                     const unsigned int incrementLength)
78 {
79     // This is the only viable way to increment characters as we have a length
80     // in  "chars", but we really want to be working in bytes.
81 
82     unsigned int endOfString = beginIndex;
83 
84     for (unsigned int i = 0; i < incrementLength; ++i)
85         endOfString += theString.sizeOfChar(endOfString);
86 
87     return endOfString;
88 }
89 
90 
getCLCLength(const STAFString & theString,unsigned int & index)91 inline unsigned int getCLCLength(const STAFString &theString, unsigned int &index)
92 {
93     unsigned int colonIndex1 = theString.find(sColon, index);
94 
95     if (colonIndex1 == STAFString::kNPos)
96         throw STAFException("No first colon found");
97 
98     unsigned int colonIndex2 = theString.find(sColon, colonIndex1 + 1);
99 
100     if (colonIndex2 == STAFString::kNPos)
101         throw STAFException("No second colon found");
102 
103     index = colonIndex2 + 1;
104 
105     return theString.subString(
106         colonIndex1 + 1, colonIndex2 - colonIndex1 - 1).asUInt();
107 }
108 
109 
getCLCString(const STAFString & theString,unsigned int & index)110 inline STAFString getCLCString(const STAFString &theString, unsigned int &index)
111 {
112     unsigned int colonIndex1 = theString.find(sColon, index);
113 
114     if (colonIndex1 == STAFString::kNPos)
115         throw STAFException("No first colon found");
116 
117     unsigned int colonIndex2 = theString.find(sColon, colonIndex1 + 1);
118 
119     if (colonIndex2 == STAFString::kNPos)
120         throw STAFException("No second colon found");
121 
122     unsigned int stringLength = theString.subString(
123         colonIndex1 + 1, colonIndex2 - colonIndex1 - 1).asUInt();
124 
125     index = incrementNChars(theString, colonIndex2 + 1, stringLength);
126 
127     return theString.subString(colonIndex2 + 1, index - colonIndex2 - 1);
128 }
129 
130 
adoptPrimaryObject(STAFObject_t & context)131 inline STAFObject_t adoptPrimaryObject(STAFObject_t &context)
132 {
133     // Initialize the output object to be the context itself.  If the context
134     // doesn't have any map classes, then we set the output object to be the
135     // adopted root object and then destruct the context itself.
136 
137     STAFObject_t obj = context;
138 
139     if (context->contextValue->mapClassMap->mapValue->size() == 0)
140     {
141         STAFObjectMarshallingContextAdoptRootObject(context, &obj);
142         STAFObjectDestruct(&context);
143     }
144 
145     return obj;
146 }
147 
unmarshallToPrimaryObject(STAFString & theString,STAFObject_t context,unsigned int beginIndex,unsigned int endIndex,unsigned int flags)148 inline STAFObject_t unmarshallToPrimaryObject(STAFString &theString,
149                                               STAFObject_t context,
150                                               unsigned int beginIndex,
151                                               unsigned int endIndex,
152                                               unsigned int flags)
153 {
154 
155     STAFObject_t newContext = 0;
156 
157     STAFObjectUnmarshallFromString(
158         &newContext,
159         theString.subString(beginIndex, endIndex - beginIndex).getImpl(),
160         context,
161         flags);
162 
163     return adoptPrimaryObject(newContext);
164 }
165 
unmarshallObject(STAFString & theString,STAFObject_t context,unsigned int & index,unsigned int flags)166 inline STAFObject_t unmarshallObject(STAFString &theString, STAFObject_t context,
167                                      unsigned int &index, unsigned int flags)
168 {
169     unsigned int beginIndex = index;
170     unsigned int colonIndex1 = theString.find(sColon, beginIndex);
171     unsigned int colonIndex2 = theString.find(sColon, colonIndex1 + 1);
172     unsigned int objectLength = theString.subString(colonIndex1 + 1,
173                                                     colonIndex2 - colonIndex1 -
174                                                     1).asUInt();
175     index = incrementNChars(theString, colonIndex2 + 1, objectLength);
176 
177     return unmarshallToPrimaryObject(theString, context, beginIndex, index,
178                                      flags);
179 }
180 
181 
STAFObjectConstructReference(STAFObject_t * pObject,STAFObject_t source)182 STAFRC_t STAFObjectConstructReference(STAFObject_t *pObject, STAFObject_t source)
183 {
184     if (pObject == 0) return kSTAFInvalidObject;
185     if (source  == 0) return kSTAFInvalidObject;
186 
187     *pObject = new STAFObjectImpl;
188     STAFObjectImpl &obj = **pObject;
189 
190     obj = *source;
191     obj.isRef = true;
192 
193     return kSTAFOk;
194 }
195 
196 
STAFObjectConstructNone(STAFObject_t * pObject)197 STAFRC_t STAFObjectConstructNone(STAFObject_t *pObject)
198 {
199     if (pObject == 0) return kSTAFInvalidObject;
200 
201     *pObject = new STAFObjectImpl;
202     STAFObjectImpl &obj = **pObject;
203 
204     obj.type = kSTAFNoneObject;
205     obj.isRef = false;
206 
207     return kSTAFOk;
208 }
209 
210 
STAFObjectConstructScalarString(STAFObject_t * pObject,STAFStringConst_t aString)211 STAFRC_t STAFObjectConstructScalarString(STAFObject_t *pObject,
212                                          STAFStringConst_t aString)
213 {
214     if (pObject == 0) return kSTAFInvalidObject;
215 
216     *pObject = new STAFObjectImpl;
217     STAFObjectImpl &obj = **pObject;
218 
219     obj.type = kSTAFScalarStringObject;
220     obj.isRef = false;
221 
222     // XXX: Used to be this
223     // STAFStringConstructCopy(&obj.scalarStringValue, aString, 0);
224     obj.scalarStringValue = new STAFString(aString);
225 
226     return kSTAFOk;
227 }
228 
229 
STAFObjectConstructList(STAFObject_t * pObject)230 STAFRC_t STAFObjectConstructList(STAFObject_t *pObject)
231 {
232     if (pObject == 0) return kSTAFInvalidObject;
233 
234     *pObject = new STAFObjectImpl;
235     STAFObjectImpl &obj = **pObject;
236 
237     obj.type = kSTAFListObject;
238     obj.isRef = false;
239 
240     obj.listValue = new STAFObjectList;
241 
242     return kSTAFOk;
243 }
244 
245 
STAFObjectConstructListIterator(STAFObjectIterator_t * pIter,STAFObject_t list)246 STAFRC_t STAFObjectConstructListIterator(STAFObjectIterator_t *pIter,
247                                          STAFObject_t list)
248 {
249     if (pIter == 0) return kSTAFInvalidObject;
250     // XXX: Might this want to be a new kSTAFInvalidOperation ?
251     if (list->type != kSTAFListObject) return kSTAFInvalidObject;
252 
253     *pIter = new STAFObjectIteratorImpl;
254     STAFObjectIteratorImpl &iter = **pIter;
255 
256     iter.type = kSTAFObjectListIterator;
257 
258     iter.listIterator = new STAFObjectListIterator;
259     iter.listIterator->iter = list->listValue->begin();
260     iter.listIterator->listObject = list->listValue;
261 
262     return kSTAFOk;
263 }
264 
265 
STAFObjectConstructMap(STAFObject_t * pObject)266 STAFRC_t STAFObjectConstructMap(STAFObject_t *pObject)
267 {
268     if (pObject == 0) return kSTAFInvalidObject;
269 
270     *pObject = new STAFObjectImpl;
271     STAFObjectImpl &obj = **pObject;
272 
273     obj.type = kSTAFMapObject;
274     obj.isRef = false;
275 
276     obj.mapValue = new STAFObjectMap;
277 
278     return kSTAFOk;
279 }
280 
281 
STAFObjectConstructMapKeyIterator(STAFObjectIterator_t * pIter,STAFObject_t map)282 STAFRC_t STAFObjectConstructMapKeyIterator(STAFObjectIterator_t *pIter,
283                                            STAFObject_t map)
284 {
285     if (pIter == 0) return kSTAFInvalidObject;
286     // XXX: Might this want to be a new kSTAFInvalidOperation ?
287     if (map->type != kSTAFMapObject) return kSTAFInvalidObject;
288 
289     *pIter = new STAFObjectIteratorImpl;
290     STAFObjectIteratorImpl &iter = **pIter;
291 
292     iter.type = kSTAFObjectMapKeyIterator;
293 
294     iter.mapIterator = new STAFObjectMapIterator;
295     iter.mapIterator->iter = map->mapValue->begin();
296     iter.mapIterator->mapObject = map->mapValue;
297 
298     return kSTAFOk;
299 }
300 
301 
STAFObjectConstructMapValueIterator(STAFObjectIterator_t * pIter,STAFObject_t map)302 STAFRC_t STAFObjectConstructMapValueIterator(STAFObjectIterator_t *pIter,
303                                              STAFObject_t map)
304 {
305     if (pIter == 0) return kSTAFInvalidObject;
306     // XXX: Might this want to be a new kSTAFInvalidOperation ?
307     if (map->type != kSTAFMapObject) return kSTAFInvalidObject;
308 
309     *pIter = new STAFObjectIteratorImpl;
310     STAFObjectIteratorImpl &iter = **pIter;
311 
312     iter.type = kSTAFObjectMapValueIterator;
313 
314     iter.mapIterator = new STAFObjectMapIterator;
315     iter.mapIterator->iter = map->mapValue->begin();
316     iter.mapIterator->mapObject = map->mapValue;
317 
318     return kSTAFOk;
319 }
320 
321 
STAFObjectConstructMapClassDefinitionIterator(STAFObjectIterator_t * pIter,STAFObject_t context)322 STAFRC_t STAFObjectConstructMapClassDefinitionIterator(
323     STAFObjectIterator_t *pIter, STAFObject_t context)
324 {
325     if (pIter == 0) return kSTAFInvalidObject;
326     // XXX: Might this want to be a new kSTAFInvalidOperation ?
327     if (context->type != kSTAFMarshallingContextObject)
328         return kSTAFInvalidObject;
329 
330     return STAFObjectConstructMapKeyIterator(
331                pIter, context->contextValue->mapClassMap);
332 }
333 
334 
STAFObjectConstructMarshallingContext(STAFObject_t * pObject)335 STAFRC_t STAFObjectConstructMarshallingContext(STAFObject_t *pObject)
336 {
337     if (pObject == 0) return kSTAFInvalidObject;
338 
339     *pObject = new STAFObjectImpl;
340     STAFObjectImpl &obj = **pObject;
341 
342     obj.type = kSTAFMarshallingContextObject;
343     obj.isRef = false;
344 
345     obj.contextValue = new STAFObjectMarshallingContext;
346     STAFObjectConstructNone(&obj.contextValue->rootObject);
347     STAFObjectConstructMap(&obj.contextValue->mapClassMap);
348 
349     return kSTAFOk;
350 }
351 
STAFObjectDestruct(STAFObject_t * pObject)352 STAFRC_t STAFObjectDestruct(STAFObject_t *pObject)
353 {
354     if (pObject  == 0) return kSTAFInvalidObject;
355     if (*pObject == 0) return kSTAFInvalidObject;
356 
357     STAFObjectImpl &obj = **pObject;
358 
359     if (!obj.isRef)
360     {
361         if (obj.type == kSTAFScalarStringObject)
362         {
363             delete obj.scalarStringValue;
364         }
365         else if (obj.type == kSTAFListObject)
366         {
367             // First destruct everything in the list
368 
369             for (STAFObjectList::iterator iter = obj.listValue->begin();
370                  iter != obj.listValue->end();
371                  ++iter)
372             {
373                 STAFObjectDestruct(&(*iter));
374             }
375 
376             // Then, get rid of the list
377 
378             delete obj.listValue;
379         }
380         else if (obj.type == kSTAFMapObject)
381         {
382             // First get rid of all the object values in the map.
383             // The keys will be deleted automatically.
384 
385             for (STAFObjectMap::iterator iter = obj.mapValue->begin();
386                  iter != obj.mapValue->end();
387                  ++iter)
388             {
389                 STAFObjectDestruct(&iter->second);
390             }
391 
392             // Then, get rid of the map
393 
394             delete obj.mapValue;
395         }
396         else if (obj.type == kSTAFMarshallingContextObject)
397         {
398             STAFObjectDestruct(&obj.contextValue->mapClassMap);
399             STAFObjectDestruct(&obj.contextValue->rootObject);
400 
401             delete obj.contextValue;
402         }
403     }
404 
405     delete *pObject;
406 
407     *pObject = 0;
408 
409     return kSTAFOk;
410 }
411 
412 
STAFObjectIsStringMarshalledData(STAFStringConst_t string,unsigned int * isMarshalledData)413 STAFRC_t STAFObjectIsStringMarshalledData(STAFStringConst_t string,
414                                           unsigned int *isMarshalledData)
415 {
416     if (string == 0) return kSTAFInvalidObject;
417     if (isMarshalledData == 0) return kSTAFInvalidParm;
418 
419     static STAFString marshalledDataMarker("@SDT/");
420 
421     return STAFStringStartsWith(string, marshalledDataMarker.getImpl(),
422                                 isMarshalledData, 0);
423 }
424 
425 
426 
STAFObjectGetType(STAFObject_t object,STAFObjectType_t * type)427 STAFRC_t STAFObjectGetType(STAFObject_t object, STAFObjectType_t *type)
428 {
429     if (object == 0) return kSTAFInvalidObject;
430     if (type   == 0) return kSTAFInvalidParm;
431 
432     *type = object->type;
433 
434     return kSTAFOk;
435 }
436 
437 
STAFObjectGetSize(STAFObject_t object,unsigned int * size)438 STAFRC_t STAFObjectGetSize(STAFObject_t object, unsigned int *size)
439 {
440     if (object == 0) return kSTAFInvalidObject;
441     if (size   == 0) return kSTAFInvalidParm;
442 
443     if (object->type == kSTAFNoneObject)
444         *size = 0;
445     else if (object->type == kSTAFScalarStringObject)
446         *size = object->scalarStringValue->length();
447     else if (object->type == kSTAFMapObject)
448         *size = object->mapValue->size();
449     else if (object->type == kSTAFListObject)
450         *size = object->listValue->size();
451     else if (object->type == kSTAFMarshallingContextObject)
452         return STAFObjectGetSize(object->contextValue->mapClassMap, size);
453     else
454       *size = 0;
455 
456     return kSTAFOk;
457 }
458 
459 
STAFObjectIsReference(STAFObject_t object,unsigned int * isRef)460 STAFRC_t STAFObjectIsReference(STAFObject_t object, unsigned int *isRef)
461 {
462     if (object == 0) return kSTAFInvalidObject;
463     if (isRef  == 0) return kSTAFInvalidParm;
464 
465     *isRef = object->isRef ? 1 : 0;
466 
467     return kSTAFOk;
468 }
469 
470 
STAFObjectGetStringValue(STAFObject_t object,STAFString_t * pString)471 STAFRC_t STAFObjectGetStringValue(STAFObject_t object, STAFString_t *pString)
472 {
473     if (object  == 0) return kSTAFInvalidObject;
474     if (pString == 0) return kSTAFInvalidParm;
475 
476     if (object->type == kSTAFNoneObject)
477     {
478         static STAFString sNoneString("<None>");
479         STAFStringConstructCopy(pString, sNoneString.getImpl(), 0);
480     }
481     else if (object->type == kSTAFScalarStringObject)
482     {
483         STAFStringConstructCopy(pString,
484                                 object->scalarStringValue->getImpl(), 0);
485     }
486     else if (object->type == kSTAFListObject)
487     {
488         unsigned int size = 0;
489 
490         STAFObjectGetSize(object, &size);
491 
492         STAFString sListString = STAFString("<List>[") + size + "]";
493         STAFStringConstructCopy(pString, sListString.getImpl(), 0);
494     }
495     else if (object->type == kSTAFMapObject)
496     {
497         static STAFString sMapClassKey("staf-map-class-name");
498         unsigned int size = 0;
499 
500         STAFObjectGetSize(object, &size);
501 
502         STAFObjectMap::iterator iter =
503             object->mapValue->find(sMapClassKey);
504 
505         if (iter != object->mapValue->end())
506         {
507             STAFString_t mapClassNameT = 0;
508 
509             STAFObjectGetStringValue(iter->second, &mapClassNameT);
510 
511             STAFString sMapString = STAFString("<Map:") +
512                 STAFString(mapClassNameT, STAFString::kShallow) +
513                 ">[" + size + "]";
514 
515             STAFStringConstructCopy(pString, sMapString.getImpl(), 0);
516         }
517         else
518         {
519             STAFString sMapString = STAFString("<Map>[") + size + "]";
520             STAFStringConstructCopy(pString, sMapString.getImpl(), 0);
521         }
522     }
523     else if (object->type == kSTAFMarshallingContextObject)
524     {
525         unsigned int size = 0;
526 
527         STAFObjectGetSize(object, &size);
528 
529         STAFString sContextString =
530             STAFString("<MarshalingContext>[") + size + "]";
531         STAFStringConstructCopy(pString, sContextString.getImpl(), 0);
532     }
533     else *pString = STAFString("<Unknown>").adoptImpl();
534 
535     return kSTAFOk;
536 }
537 
538 
ISTAFQuoteString(const STAFString & input)539 STAFString ISTAFQuoteString(const STAFString &input)
540 {
541     static STAFString sSingleQuote(kUTF8_SQUOTE);
542     static STAFString sDoubleQuote(kUTF8_DQUOTE);
543     static STAFString sEscapedSingleQuote("\\'");
544 
545     if (input.find(sSingleQuote) == STAFString::kNPos)
546         return STAFString(sSingleQuote) + input + STAFString(sSingleQuote);
547 
548     if (input.find(sDoubleQuote) == STAFString::kNPos)
549         return STAFString(sDoubleQuote) + input + STAFString(sDoubleQuote);
550 
551     return STAFString(sSingleQuote) +
552            input.replace(sSingleQuote, sEscapedSingleQuote) +
553            STAFString(sSingleQuote);
554 }
555 
556 
ISTAFGetLineSep()557 STAFString ISTAFGetLineSep()
558 {
559     struct STAFConfigInfo configInfo = { 0 };
560 
561     STAFUtilGetConfigInfo(&configInfo, 0, 0);
562 
563     return configInfo.lineSeparator;
564 }
565 
566 
ISTAFObjectGetFormattedStringValue(STAFString & output,STAFObjectPtr & objPtr,STAFObjectPtr & context,unsigned int indentLevel)567 void ISTAFObjectGetFormattedStringValue(STAFString &output,
568                                         STAFObjectPtr &objPtr,
569                                         STAFObjectPtr &context,
570                                         unsigned int indentLevel)
571 {
572     static unsigned int sIndentDelta = 2;
573     static STAFString sSpaces("                                        "
574                               "                                        ");
575     static STAFString sListIndent("[");
576     static STAFString sListOutdent("]");
577     static STAFString sMapIndent("{");
578     static STAFString sMapOutdent("}");
579     static STAFString sEntrySeparator("");
580     static STAFString sMapKeySeparator(": ");
581     static STAFString sKey("key");
582     static STAFString sMapClassKey("staf-map-class-name");
583     static STAFString sDisplayName("display-name");
584     static STAFString sLineSep = ISTAFGetLineSep();
585 
586     switch (objPtr->type())
587     {
588         case kSTAFListObject:
589         {
590             output += sListIndent;
591 
592             ++indentLevel;
593 
594             if (objPtr->size() > 0) output += sLineSep;
595 
596             // Print out each object
597 
598             // Get the size of the list and create an array with that size.
599             // Add a string representing each element in the list to the array
600             // and then join the strings in the array.
601             // Using an array and then doing a join is done for performance
602             // reasons as it's faster than concatenating strings using +=.
603 
604             unsigned int size = objPtr->size();
605             STAFString *stringArray = new STAFString[size];
606             unsigned int i = 0;
607 
608             for (STAFObjectIteratorPtr iterPtr = objPtr->iterate();
609                  iterPtr->hasNext();)
610             {
611                 STAFString entryOutput;
612                 STAFObjectPtr thisObj = iterPtr->next();
613 
614                 if ((thisObj->type() == kSTAFListObject) ||
615                     (thisObj->type() == kSTAFMapObject) ||
616                     (thisObj->type() == kSTAFMarshallingContextObject))
617                 {
618                     entryOutput += sSpaces.subString(0, indentLevel * sIndentDelta);
619 
620                     ISTAFObjectGetFormattedStringValue(
621                         entryOutput, thisObj, context, indentLevel);
622                 }
623                 else
624                 {
625                     entryOutput += sSpaces.subString(0, indentLevel * sIndentDelta);
626 
627                     if (thisObj->type() == kSTAFNoneObject)
628                         entryOutput += thisObj->asString();
629                     else
630                         entryOutput += thisObj->asString();
631                 }
632 
633                 if (iterPtr->hasNext()) entryOutput += sEntrySeparator;
634 
635                 entryOutput += sLineSep;
636 
637                 stringArray[i++].replaceImpl(entryOutput.adoptImpl());
638             }
639 
640             output.join(stringArray, size);
641 
642             delete [] stringArray;
643 
644             --indentLevel;
645 
646             if (objPtr->size() > 0)
647                 output += sSpaces.subString(0, indentLevel * sIndentDelta);
648 
649             output += sListOutdent;
650 
651             break;
652         }
653         case kSTAFMapObject:
654         {
655             output += sMapIndent;
656 
657             ++indentLevel;
658 
659             if (objPtr->size() > 0) output += sLineSep;
660 
661             // Check if the map object has a map class key and if the context
662             // is valid and contains a map class definition for this map class.
663             // If not, treat as a plain map class.
664 
665             if (objPtr->hasKey(sMapClassKey) &&
666                 context && (context->type() == kSTAFMarshallingContextObject) &&
667                 context->hasMapClassDefinition(objPtr->get(sMapClassKey)->asString()))
668             {
669                 // Map object has a map class definition in the context
670 
671                 STAFMapClassDefinitionPtr mapClass =
672                     context->getMapClassDefinition(
673                         objPtr->get(sMapClassKey)->asString());
674 
675                 // Determine maximum key length
676 
677                 STAFObjectIteratorPtr iterPtr;
678                 unsigned int maxKeyLength = 0;
679                 unsigned int size = 0;  // Number of keys
680 
681                 for (iterPtr = mapClass->keyIterator(); iterPtr->hasNext();)
682                 {
683                     size++;
684                     STAFObjectPtr theKey = iterPtr->next();
685                     STAFString theKeyString;
686 
687                     if (theKey->hasKey(sDisplayName))
688                         theKeyString = theKey->get(sDisplayName)->asString();
689                     else
690                         theKeyString = theKey->get(sKey)->asString();
691 
692                     if (theKeyString.length(STAFString::kChar) > maxKeyLength)
693                         maxKeyLength = theKeyString.length(STAFString::kChar);
694                 }
695 
696                 // Now print each object in the map
697 
698                 // Get the size of the map and create an array with that size.
699                 // Add a string representing each element in the map to the array
700                 // and then join the strings in the array.
701                 // Using an array and then doing a join is done for performance
702                 // reasons as it's faster than concatenating strings using +=.
703 
704                 STAFString *stringArray = new STAFString[size];
705                 unsigned int i = 0;
706 
707                 for (iterPtr = mapClass->keyIterator(); iterPtr->hasNext();)
708                 {
709                     STAFObjectPtr theKey = iterPtr->next();
710                     STAFString theKeyString;
711 
712                     if (theKey->hasKey(sDisplayName))
713                         theKeyString = theKey->get(sDisplayName)->asString();
714                     else
715                         theKeyString = theKey->get(sKey)->asString();
716 
717                     STAFString entryOutput = sSpaces.subString(
718                         0, indentLevel * sIndentDelta);
719                     entryOutput += theKeyString;
720                     entryOutput += sSpaces.subString(0, maxKeyLength -
721                                    theKeyString.length(STAFString::kChar));
722                     entryOutput += sMapKeySeparator;
723 
724                     STAFObjectPtr thisObj =
725                         objPtr->get(theKey->get(sKey)->asString());
726 
727                     if ((thisObj->type() == kSTAFListObject) ||
728                         (thisObj->type() == kSTAFMapObject) ||
729                         (thisObj->type() == kSTAFMarshallingContextObject))
730                     {
731                         ISTAFObjectGetFormattedStringValue(
732                             entryOutput, thisObj, context, indentLevel);
733                     }
734                     else if (thisObj->type() == kSTAFNoneObject)
735                     {
736                         entryOutput += thisObj->asString();
737                     }
738                     else
739                     {
740                         entryOutput += thisObj->asString();
741                     }
742 
743                     if (iterPtr->hasNext()) entryOutput += sEntrySeparator;
744 
745                     entryOutput += sLineSep;
746 
747                     stringArray[i++].replaceImpl(entryOutput.adoptImpl());
748                 }
749 
750                 output.join(stringArray, size);
751 
752                 delete [] stringArray;
753             }
754             else
755             {
756                 // The map does not have a map class key or the map class
757                 // definition is not provided in the context
758 
759                 // Determine maximum key length
760 
761                 STAFObjectIteratorPtr iterPtr;
762                 unsigned int maxKeyLength = 0;
763 
764                 for (iterPtr = objPtr->keyIterator(); iterPtr->hasNext();)
765                 {
766                     STAFString theKeyString = iterPtr->next()->asString();
767 
768                     if (theKeyString.length(STAFString::kChar) > maxKeyLength)
769                         maxKeyLength = theKeyString.length(STAFString::kChar);
770                 }
771 
772                 // Now print each object in the map
773 
774                 // Get the size of the map and create an array with that size.
775                 // Add a string representing each element in the map to the array
776                 // and then join the strings in the array.
777                 // Using an array and then doing a join is done for performance
778                 // reasons as it's faster than concatenating strings using +=.
779 
780                 unsigned int size = objPtr->size();
781                 STAFString *stringArray = new STAFString[size];
782                 unsigned int i = 0;
783 
784                 for (iterPtr = objPtr->keyIterator(); iterPtr->hasNext();)
785                 {
786                     STAFString theKeyString = iterPtr->next()->asString();
787 
788                     STAFString entryOutput = sSpaces.subString(
789                         0, indentLevel * sIndentDelta);
790                     entryOutput += theKeyString;
791                     entryOutput += sSpaces.subString(
792                         0, maxKeyLength - theKeyString.length(STAFString::kChar));
793                     entryOutput += sMapKeySeparator;
794 
795                     STAFObjectPtr thisObj = objPtr->get(theKeyString);
796 
797                     if ((thisObj->type() == kSTAFListObject) ||
798                         (thisObj->type() == kSTAFMapObject) ||
799                         (thisObj->type() == kSTAFMarshallingContextObject))
800                     {
801                         ISTAFObjectGetFormattedStringValue(
802                             entryOutput, thisObj, context, indentLevel);
803                     }
804                     else if (thisObj->type() == kSTAFNoneObject)
805                     {
806                         entryOutput += thisObj->asString();
807                     }
808                     else
809                     {
810                         entryOutput += thisObj->asString();
811                     }
812 
813                     if (iterPtr->hasNext()) entryOutput += sEntrySeparator;
814 
815                     entryOutput += sLineSep;
816 
817                     stringArray[i++].replaceImpl(entryOutput.adoptImpl());
818                 }
819 
820 
821                 output.join(stringArray, size);
822 
823                 delete [] stringArray;
824             }
825 
826             --indentLevel;
827 
828             if (objPtr->size() > 0)
829                 output += sSpaces.subString(0, indentLevel * sIndentDelta);
830 
831             output += sMapOutdent;
832 
833             break;
834         }
835         case kSTAFMarshallingContextObject:
836         {
837             STAFObjectPtr thisObj = objPtr->getRootObject();
838 
839             ISTAFObjectGetFormattedStringValue(output, thisObj, objPtr,
840                                                indentLevel);
841             break;
842         }
843         default:
844         {
845             output += sSpaces.subString(0, indentLevel * sIndentDelta);
846             output += objPtr->asString();
847             break;
848         }
849     }
850 }
851 
852 
STAFObjectGetFormattedStringValue(STAFObject_t object,STAFString_t * pString,unsigned int flags)853 STAFRC_t STAFObjectGetFormattedStringValue(STAFObject_t object,
854                                            STAFString_t *pString,
855                                            unsigned int flags)
856 {
857     if (object  == 0) return kSTAFInvalidObject;
858     if (pString == 0) return kSTAFInvalidParm;
859 
860     if (object->type == kSTAFNoneObject)
861     {
862         static STAFString sNoneString("<None>");
863         STAFStringConstructCopy(pString, sNoneString.getImpl(), 0);
864     }
865     else if (object->type == kSTAFScalarStringObject)
866     {
867         STAFStringConstructCopy(pString,
868                                 object->scalarStringValue->getImpl(), 0);
869     }
870     else
871     {
872         STAFObjectPtr theObj = STAFObject::createReference(object);
873         STAFObjectPtr context = STAFObject::createNone();
874         STAFString output;
875 
876         ISTAFObjectGetFormattedStringValue(output, theObj, context, 0);
877 
878         *pString = output.adoptImpl();
879     }
880 
881     return kSTAFOk;
882 }
883 
884 
STAFObjectFreeSTAFStringTArray(STAFString_t * theArray,unsigned int size)885 void STAFObjectFreeSTAFStringTArray(STAFString_t *theArray, unsigned int size)
886 {
887     for (unsigned int i = 0; i < size; ++i)
888         STAFStringDestruct(&theArray[i], 0);
889 
890     delete [] theArray;
891 }
892 
893 
STAFObjectMarshallToString(STAFObject_t object,STAFObject_t context,STAFString_t * pString,unsigned int flags)894 STAFRC_t STAFObjectMarshallToString(STAFObject_t object, STAFObject_t context,
895                                     STAFString_t *pString, unsigned int flags)
896 {
897     if (object  == 0) return kSTAFInvalidObject;
898     if (pString == 0) return kSTAFInvalidParm;
899     // XXX: Might this want to be a new kSTAFInvalidOperation ?
900     if ((context != 0) && (context->type != kSTAFMarshallingContextObject))
901         return kSTAFInvalidParm;
902 
903     static STAFString sMapClassKey("staf-map-class-name");
904 
905     STAFString outString;
906 
907     if (object->type == kSTAFScalarStringObject)
908     {
909         outString += "@SDT/$S:";
910         outString += object->scalarStringValue->length(STAFString::kChar);
911         outString += sColon;
912         outString += *object->scalarStringValue;
913     }
914     else if (object->type == kSTAFNoneObject)
915     {
916         outString += "@SDT/$0:0:";
917     }
918     else if (object->type == kSTAFListObject)
919     {
920         // Get the size of the list and create an array with that size.
921         // Instead of creating an array using:
922         //   STAFString_t *stringArray = new STAFString_t[size];
923         // we're using a STAFRefPtr<STAFString_t> custom array type so that
924         // the array and it's contents will get destructed (even if an
925         // exception occurs).
926         // For each entry in the list, add a string representation of the entry
927         // to the array and then join the strings in the array.
928         // Using an array and then doing a join is done for performance
929         // reasons as it's faster than concatenating strings using +=.
930 
931         unsigned int size = 0;
932         STAFObjectGetSize(object, &size);
933 
934         STAFRefPtr<STAFString_t> stringArray = STAFRefPtr<STAFString_t>
935             (new STAFString_t[size],
936              STAFRefPtr<STAFString_t>::INIT,
937              size, STAFObjectFreeSTAFStringTArray);
938 
939         unsigned int i = 0;
940 
941         for (STAFObjectList::iterator iter = object->listValue->begin();
942              iter != object->listValue->end();
943              ++iter)
944         {
945             STAFString_t thisItemStringT = 0;
946             // XXX: Check RC?
947             STAFObjectMarshallToString(*iter, context, &thisItemStringT, flags);
948             stringArray[i++] = thisItemStringT;
949         }
950 
951         STAFString_t joinedStringT = 0;
952         unsigned int osRC;
953 
954         // XXX: Check RC from STAFStringConstructJoin?
955         STAFStringConstructJoin(&joinedStringT, stringArray, size, &osRC);
956 
957         STAFString dataString = STAFString(joinedStringT, STAFString::kShallow);
958 
959         outString += "@SDT/[";
960         outString += object->listValue->size();
961         outString += sColon;
962         outString += dataString.length(STAFString::kChar);
963         outString += sColon;
964         outString += dataString;
965     }
966     else if (object->type == kSTAFMapObject)
967     {
968         // If a staf-map-class-name key exists in the map, make sure that it's
969         // map class definition is provided in the marshalling context.
970         // If it's not, then treat the map as a plain map object.
971 
972         bool isMapClass = false;
973         STAFString mapClassName;
974 
975         if (context &&
976             (object->mapValue->find(sMapClassKey) != object->mapValue->end()))
977         {
978             mapClassName = *(*object->mapValue)[sMapClassKey]->
979                 scalarStringValue;
980 
981             unsigned int hasMapClassDefinition = 0;
982 
983             STAFRC_t rc = STAFObjectMarshallingContextHasMapClassDefinition(
984                 context, mapClassName.getImpl(), &hasMapClassDefinition);
985 
986             if ((rc == kSTAFOk) && (hasMapClassDefinition)) isMapClass = true;
987         }
988 
989         if (isMapClass)
990         {
991             // Note: Not much checking is done here as all the checking is done
992             //       in STAFObjectMarshallingContextSetMapClassDefinition
993 
994             // XXX: This whole block could use some rework to simplify all
995             //      the dereferences
996 
997             STAFString dataString;
998             dataString += sColon;
999             dataString += mapClassName.length(STAFString::kChar);
1000             dataString += sColon;
1001             dataString += mapClassName;
1002 
1003             STAFObject_t keyList = (*(*context->contextValue->
1004                                     mapClassMap->mapValue)[mapClassName]->
1005                                     mapValue)["keys"];
1006 
1007             // Get the number of keys in the map class definition and create an
1008             // array with that size.
1009             // Instead of creating an array using:
1010             //   STAFString_t *stringArray = new STAFString_t[size];
1011             // we're using a STAFRefPtr<STAFString_t> custom array type so that
1012             // the array and it's contents will get destructed (even if an
1013             // exception occurs).
1014             // For each key in the map class, add a string representation to
1015             // the array and then join the strings in the array.
1016             // Using an array and then doing a join is done for performance
1017             // reasons as it's faster than concatenating strings using +=.
1018 
1019             unsigned int size = 0;
1020             STAFObjectGetSize(keyList, &size);
1021 
1022             STAFRefPtr<STAFString_t> stringArray = STAFRefPtr<STAFString_t>
1023                 (new STAFString_t[size],
1024                  STAFRefPtr<STAFString_t>::INIT,
1025                  size, STAFObjectFreeSTAFStringTArray);
1026 
1027             unsigned int i = 0;
1028 
1029             for (STAFObjectList::iterator iter = keyList->listValue->begin();
1030                  iter != keyList->listValue->end();
1031                  ++iter)
1032             {
1033                 STAFString &keyName =
1034                     *(*(*iter)->mapValue)["key"]->scalarStringValue;
1035                 STAFString_t thisItemStringT = 0;
1036                 STAFObject_t thisItem = (*object->mapValue)[keyName];
1037 
1038                 if (thisItem == 0) thisItem = sNoneObjT;
1039 
1040                 STAFObjectMarshallToString(thisItem, context, &thisItemStringT,
1041                                            flags);
1042 
1043                 stringArray[i++] = thisItemStringT;
1044             }
1045 
1046             STAFString_t joinedStringT = 0;
1047             unsigned int osRC;
1048 
1049             STAFStringConstructJoin(&joinedStringT, stringArray, size, &osRC);
1050 
1051             dataString += STAFString(joinedStringT, STAFString::kShallow);
1052 
1053             outString += "@SDT/%:";
1054             outString += dataString.length(STAFString::kChar);
1055             outString += sColon;
1056             outString += dataString;
1057         }
1058         else
1059         {
1060             // Get the size of the map and create an array with that size.
1061             // Instead of creating an array using:
1062             //   STAFString_t *stringArray = new STAFString_t[size];
1063             // we're using a STAFRefPtr<STAFString_t> custom array type so that
1064             // the array and it's contents will get destructed (even if an
1065             // exception occurs).
1066             // For each key/value in the map, add a string representation to
1067             // the array and then join the strings in the array.
1068             // Using an array and then doing a join is done for performance
1069             // reasons as it's faster than concatenating strings using +=.
1070 
1071             unsigned int size = 0;
1072             STAFObjectGetSize(object, &size);
1073 
1074             STAFRefPtr<STAFString_t> stringArray = STAFRefPtr<STAFString_t>
1075                 (new STAFString_t[size],
1076                  STAFRefPtr<STAFString_t>::INIT,
1077                  size, STAFObjectFreeSTAFStringTArray);
1078 
1079             unsigned int i = 0;
1080 
1081             for (STAFObjectMap::iterator iter = object->mapValue->begin();
1082                  iter != object->mapValue->end(); ++iter)
1083             {
1084                 // First add the key
1085 
1086                 STAFString entryString = sColon;
1087                 entryString += iter->first.length(STAFString::kChar);
1088                 entryString += sColon;
1089                 entryString += iter->first;
1090 
1091                 // Next add the value
1092 
1093                 STAFString_t thisItemStringT = 0;
1094                 // XXX: Check RC?
1095                 STAFObjectMarshallToString(iter->second, context,
1096                                            &thisItemStringT, flags);
1097 
1098                 entryString += STAFString(thisItemStringT, STAFString::kShallow);
1099 
1100                 stringArray[i++] = entryString.adoptImpl();
1101             }
1102 
1103             STAFString_t joinedStringT = 0;
1104             unsigned int osRC;
1105 
1106             STAFStringConstructJoin(&joinedStringT, stringArray, size, &osRC);
1107 
1108             STAFString dataString = STAFString(joinedStringT, STAFString::kShallow);
1109 
1110             outString += "@SDT/{:";
1111             outString += dataString.length(STAFString::kChar);
1112             outString += sColon;
1113             outString += dataString;
1114         }
1115     }
1116     else if (object->type == kSTAFMarshallingContextObject)
1117     {
1118         STAFString dataString;
1119         unsigned int size = 0;
1120         STAFObjectGetSize(object->contextValue->mapClassMap, &size);
1121 
1122         if (size != 0)
1123         {
1124             // Get a reference to the context's map class map
1125 
1126             STAFObject_t mapClassMap = 0;
1127 
1128             STAFObjectConstructReference(&mapClassMap,
1129                                          object->contextValue->mapClassMap);
1130 
1131             // Now create the context map for marshalling and add the context's
1132             // map class map as the "map-class-map" object
1133 
1134             STAFObject_t contextMap = 0;
1135 
1136             STAFObjectConstructMap(&contextMap);
1137             STAFObjectMapPut(contextMap, STAFString("map-class-map").getImpl(),
1138                              mapClassMap);
1139             STAFObjectDestruct(&mapClassMap);
1140 
1141             // Marshall the context map itself and then destruct it
1142             //
1143             // Note, the context map is not marshalled within any context.  If it
1144             // were, we run the risk of recursive map class definitions, which
1145             // wouldn't work when unmarshalling.
1146 
1147             STAFString_t mapClassMapStringT = 0;
1148 
1149             STAFObjectMarshallToString(contextMap, 0, &mapClassMapStringT, flags);
1150 
1151             STAFObjectDestruct(&contextMap);
1152 
1153             // Generate the marshalled string, and destruct the string
1154             // containing the intermediate value
1155 
1156             STAFStringConcatenate(dataString.getImpl(), mapClassMapStringT, 0);
1157             STAFStringDestruct(&mapClassMapStringT, 0);
1158         }
1159 
1160         // Marshall the root object
1161         //
1162         // Note: We marshall the root object in the context of the context
1163         //       we are marshalling (not the context that was passed in, which
1164         //       might be different.
1165 
1166         STAFString_t rootObjectStringT = 0;
1167 
1168         STAFObjectMarshallToString(object->contextValue->rootObject, object,
1169                                    &rootObjectStringT, flags);
1170 
1171         // Finally, generate the marshalled string, and destruct the string
1172         // containing the intermediate value
1173 
1174         STAFStringConcatenate(dataString.getImpl(), rootObjectStringT, 0);
1175         STAFStringDestruct(&rootObjectStringT, 0);
1176 
1177         if (size != 0)
1178         {
1179             outString += "@SDT/*";
1180             outString += sColon;
1181             outString += dataString.length(STAFString::kChar);
1182             outString += sColon;
1183         }
1184 
1185         outString += dataString;
1186     }
1187     else
1188     {
1189         // Do what?
1190     }
1191 
1192     *pString = outString.adoptImpl();
1193 
1194     return kSTAFOk;
1195 }
1196 
1197 
STAFObjectUnmarshallFromString(STAFObject_t * newContext,STAFStringConst_t marshalledObject,STAFObject_t context,unsigned int flags)1198 STAFRC_t STAFObjectUnmarshallFromString(STAFObject_t *newContext,
1199                                         STAFStringConst_t marshalledObject,
1200                                         STAFObject_t context,
1201                                         unsigned int flags)
1202 {
1203     if (newContext       == 0) return kSTAFInvalidObject;
1204     if (marshalledObject == 0) return kSTAFInvalidParm;
1205 
1206     // XXX: Might this want to be a new kSTAFInvalidOperation ?
1207     if ((context != 0) && (context->type != kSTAFMarshallingContextObject))
1208         return kSTAFInvalidParm;
1209 
1210     static STAFString marshalledDataMarker("@SDT/");
1211     static STAFString noneMarker("@SDT/$0:0:");
1212     static STAFString scalarMarker("@SDT/$");
1213     static STAFString mapMarker("@SDT/{");
1214     static STAFString mcInstanceMarker("@SDT/%");
1215     static STAFString listMarker("@SDT/[");
1216     static STAFString contextMarker("@SDT/*");
1217     static STAFString sMapClassKey("staf-map-class-name");
1218 
1219     STAFObjectConstructMarshallingContext(newContext);
1220 
1221     // XXX: Probably shouldn't make a copy of the string like this, but I'm
1222     //      going to make sure things work first, and then I'll optimize
1223 
1224     STAFString data(marshalledObject);
1225 
1226     try
1227     {
1228         if (data.startsWith(noneMarker))
1229         {
1230             // XXX: This is all probably redundant since the marshalling
1231             // context already has a None in it.
1232 
1233             STAFObject_t noneObj = 0;
1234 
1235             STAFObjectConstructNone(&noneObj);
1236             STAFObjectMarshallingContextSetRootObject(*newContext, noneObj);
1237             STAFObjectDestruct(&noneObj);
1238         }
1239         else if (data.startsWith(scalarMarker))
1240         {
1241             // @SDT/$S:<string-length>:<String>
1242 
1243             unsigned int dataIndex = scalarMarker.length(STAFString::kChar);
1244 
1245             // Get String length
1246 
1247             unsigned int stringLength = getCLCLength(data, dataIndex);
1248 
1249             if (stringLength != (data.length(STAFString::kChar) - dataIndex))
1250                 throw STAFException("Invalid marshalled scalar data");
1251 
1252             STAFObject_t stringObj = 0;
1253             STAFObjectConstructScalarString(
1254                 &stringObj, data.subString(dataIndex).getImpl());
1255 
1256             // Unless told otherwise we will try to unmarshall a nested object
1257             // reference
1258 
1259             if ((flags & kSTAFIgnoreIndirectObjects) ||
1260                 !stringObj->scalarStringValue->startsWith(
1261                     marshalledDataMarker))
1262             {
1263                 STAFObjectMarshallingContextSetRootObject(
1264                     *newContext, stringObj);
1265             }
1266             else
1267             {
1268                 STAFObject_t nestedContext = 0;
1269 
1270                 STAFObjectUnmarshallFromString(
1271                     &nestedContext, stringObj->scalarStringValue->getImpl(),
1272                     context, flags);
1273 
1274                 STAFObject_t primaryObject = adoptPrimaryObject(
1275                     nestedContext);
1276 
1277                 STAFObjectMarshallingContextSetRootObject(
1278                     *newContext, primaryObject);
1279                 STAFObjectDestruct(&primaryObject);
1280             }
1281 
1282             STAFObjectDestruct(&stringObj);
1283         }
1284         else if (data.startsWith(listMarker))
1285         {
1286             // @SDT/[<number-of-items>:<array-length>:<SDT-Any-1>...<SDT-Any-n>
1287 
1288             // Get the number of items in the list
1289 
1290             unsigned int colonIndex = data.find(sColon);
1291 
1292             if (colonIndex == STAFString::kNPos)
1293                 throw STAFException("Invalid marshalled list data");
1294 
1295             unsigned int numItems = data.subString(6, colonIndex - 6).asUInt();
1296 
1297             unsigned int dataIndex = colonIndex;
1298 
1299             // Get the array length
1300 
1301             unsigned int arrayLength = getCLCLength(data, dataIndex);
1302 
1303             if (arrayLength != (data.length(STAFString::kChar) - dataIndex))
1304                 throw STAFException("Invalid marshalled list data");
1305 
1306             STAFObject_t listObj = 0;
1307 
1308             STAFObjectConstructList(&listObj);
1309 
1310             for (unsigned int i = 0; i < numItems; ++i)
1311             {
1312                 STAFObject_t obj = unmarshallObject(
1313                     data, context, dataIndex, flags);
1314 
1315                 STAFObjectListAppend(listObj, obj);
1316                 STAFObjectDestruct(&obj);
1317             }
1318 
1319             STAFObjectMarshallingContextSetRootObject(*newContext, listObj);
1320             STAFObjectDestruct(&listObj);
1321         }
1322         else if (data.startsWith(mapMarker))
1323         {
1324             // @SDT/{:<map-length>::<key-1-length>:<key-1><SDT-Any>
1325             //                     ...
1326             //                     :<key-n-length>:<key-1><SDT-Any>
1327 
1328             unsigned int dataIndex = mapMarker.length(STAFString::kChar);
1329 
1330             // Get the map-length and increment dataIndex
1331 
1332             unsigned int mapLength = getCLCLength(data, dataIndex);
1333 
1334             if (mapLength != (data.length(STAFString::kChar) - dataIndex))
1335                 throw STAFException("Invalid marshalled map data");
1336 
1337             STAFObject_t mapObj = 0;
1338 
1339             STAFObjectConstructMap(&mapObj);
1340 
1341             while (dataIndex < data.length(STAFString::kChar))
1342             {
1343                 STAFString key = getCLCString(data, dataIndex);
1344                 STAFObject_t obj = unmarshallObject(
1345                     data, context, dataIndex, flags);
1346 
1347                 STAFObjectMapPut(mapObj, key.getImpl(), obj);
1348                 STAFObjectDestruct(&obj);
1349             }
1350 
1351             STAFObjectMarshallingContextSetRootObject(*newContext, mapObj);
1352             STAFObjectDestruct(&mapObj);
1353         }
1354         else if (data.startsWith(mcInstanceMarker))
1355         {
1356             // @SDT/%:<map-class-instance-length>::<map-class-name-length>:<map-class-name>
1357             //    <SDT-Any-value-1>
1358             //    ...
1359             //    <SDT-Any-value-n>
1360 
1361             STAFObject_t mapObj = 0;
1362 
1363             STAFObjectConstructMap(&mapObj);
1364 
1365             unsigned int dataIndex = mcInstanceMarker.length(
1366                 STAFString::kChar);
1367 
1368             // Get the map-class-instance-length and increment dataIndex
1369 
1370             unsigned int mapClassInstanceLength = getCLCLength(
1371                 data, dataIndex);
1372 
1373             if (mapClassInstanceLength != (data.length(STAFString::kChar) -
1374                                            dataIndex))
1375                 throw STAFException("Invalid marshalled map data");
1376 
1377             // Get the map-class-name
1378 
1379             STAFString mapClassName = getCLCString(data, dataIndex);
1380 
1381             // Now add the map class name to the map
1382 
1383             STAFObject_t mapClassNameObj = 0;
1384 
1385             STAFObjectConstructScalarString(&mapClassNameObj,
1386                                             mapClassName.getImpl());
1387 
1388             STAFObjectMapPut(mapObj, sMapClassKey.getImpl(), mapClassNameObj);
1389             STAFObjectDestruct(&mapClassNameObj);
1390 
1391             // Now unmarshall all the actual keys
1392 
1393             STAFObject_t mapClassObj =
1394                 (*context->contextValue->mapClassMap->mapValue)[mapClassName];
1395             STAFObject_t keyList = (*mapClassObj->mapValue)["keys"];
1396             STAFObjectList::iterator iter = keyList->listValue->begin();
1397 
1398             while (dataIndex < data.length(STAFString::kChar))
1399             {
1400                 STAFObject_t keyStringObj =  (*(*iter)->mapValue)["key"];
1401                 STAFString_t keyImpl = keyStringObj->scalarStringValue->
1402                     getImpl();
1403                 STAFObject_t obj = unmarshallObject(
1404                     data, context, dataIndex, flags);
1405 
1406                 STAFObjectMapPut(mapObj, keyImpl, obj);
1407                 STAFObjectDestruct(&obj);
1408 
1409                 ++iter;
1410             }
1411 
1412             STAFObjectMarshallingContextSetRootObject(*newContext, mapObj);
1413             STAFObjectDestruct(&mapObj);
1414         }
1415         else if (data.startsWith(contextMarker))
1416         {
1417             // @SDT/*:<context-length>:@SDT/{:<mapClassLength>:<mapClassData>
1418             //                         <rootObject>
1419 
1420             // Get context-length
1421 
1422             unsigned int dataIndex = contextMarker.length(STAFString::kChar);
1423 
1424             unsigned int contextLength = getCLCLength(data, dataIndex);
1425 
1426             if (contextLength != (data.length(STAFString::kChar) - dataIndex))
1427                 throw STAFException("Invalid marshalled context");
1428 
1429             STAFObject_t contextMap = unmarshallObject(
1430                 data, 0, dataIndex, flags);
1431 
1432             // Now we need to take ownership of the underlying map class map.
1433             // 1) Destruct the existing map class map in the new context
1434             // 2) "Adopt" the map class map from the context map
1435             // 3) Construct a None in the place of the "adopted" map class map
1436             //    in the context map
1437             // 4) Destruct the context map since we don't need it any more
1438 
1439             STAFObjectDestruct(&(*newContext)->contextValue->mapClassMap);
1440 
1441             (*newContext)->contextValue->mapClassMap =
1442                 (*contextMap->mapValue)["map-class-map"];
1443 
1444             STAFObjectConstructNone(
1445                 &(*contextMap->mapValue)["map-class-map"]);
1446 
1447             STAFObjectDestruct(&contextMap);
1448 
1449             // Now, get and set the root object
1450 
1451             STAFObject_t rootObject = unmarshallObject(
1452                 data, *newContext, dataIndex, flags);
1453 
1454             STAFObjectMarshallingContextSetRootObject(
1455                 *newContext, rootObject);
1456             STAFObjectDestruct(&rootObject);
1457         }
1458         else
1459         {
1460             // We don't know what this data is, so just return a Scalar String
1461             // object containing the whole string
1462 
1463             STAFObject_t stringObj = 0;
1464 
1465             STAFObjectConstructScalarString(&stringObj, data.getImpl());
1466             STAFObjectMarshallingContextSetRootObject(*newContext, stringObj);
1467             STAFObjectDestruct(&stringObj);
1468         }
1469     }
1470     catch (...)
1471     {
1472         // An exception occurred processing the marshalling data.
1473         // This means its probably invalid marshalled data, so just return
1474         // a Scalar String object containing the invalid marshalled data.
1475 
1476         STAFObject_t stringObj = 0;
1477 
1478         STAFObjectConstructScalarString(&stringObj, data.getImpl());
1479         STAFObjectMarshallingContextSetRootObject(*newContext, stringObj);
1480         STAFObjectDestruct(&stringObj);
1481     }
1482 
1483     return kSTAFOk;
1484 }
1485 
1486 
STAFObjectListAppend(STAFObject_t list,STAFObject_t obj)1487 STAFRC_t STAFObjectListAppend(STAFObject_t list, STAFObject_t obj)
1488 {
1489     if (list == 0) return kSTAFInvalidObject;
1490     if (obj  == 0) return kSTAFInvalidParm;
1491     // XXX: Might this want to be a new kSTAFInvalidOperation ?
1492     if (list->type != kSTAFListObject) return kSTAFInvalidObject;
1493 
1494     // Note: The object being passed in gets turned into a reference
1495 
1496     STAFObject_t newObj = new STAFObjectImpl(*obj);
1497 
1498     obj->isRef = true;
1499 
1500     list->listValue->push_back(newObj);
1501 
1502     return kSTAFOk;
1503 }
1504 
1505 
STAFObjectIteratorHasNext(STAFObjectIterator_t iter,unsigned int * hasNext)1506 STAFRC_t STAFObjectIteratorHasNext(STAFObjectIterator_t iter,
1507                                    unsigned int *hasNext)
1508 {
1509     if (iter    == 0) return kSTAFInvalidObject;
1510     if (hasNext == 0) return kSTAFInvalidParm;
1511 
1512     if (iter->type == kSTAFObjectListIterator)
1513     {
1514         *hasNext = (iter->listIterator->iter ==
1515                     iter->listIterator->listObject->end()) ? 0 : 1;
1516     }
1517     else if ((iter->type == kSTAFObjectMapKeyIterator) ||
1518              (iter->type == kSTAFObjectMapValueIterator))
1519     {
1520         *hasNext = (iter->mapIterator->iter ==
1521                     iter->mapIterator->mapObject->end()) ? 0 : 1;
1522     }
1523     else
1524     {
1525         // XXX: Return an error?
1526         *hasNext = 0;
1527     }
1528 
1529     return kSTAFOk;
1530 }
1531 
1532 
STAFObjectIteratorGetNext(STAFObjectIterator_t iter,STAFObject_t * pObject)1533 STAFRC_t STAFObjectIteratorGetNext(STAFObjectIterator_t iter,
1534                                    STAFObject_t *pObject)
1535 {
1536     if (iter    == 0) return kSTAFInvalidObject;
1537     if (pObject == 0) return kSTAFInvalidParm;
1538 
1539     if (iter->type == kSTAFObjectListIterator)
1540     {
1541         STAFObjectConstructReference(pObject, *iter->listIterator->iter);
1542         ++iter->listIterator->iter;
1543     }
1544     else if (iter->type == kSTAFObjectMapKeyIterator)
1545     {
1546         STAFObjectConstructScalarString(
1547             pObject, iter->mapIterator->iter->first.getImpl());
1548         ++iter->mapIterator->iter;
1549     }
1550     else if (iter->type == kSTAFObjectMapValueIterator)
1551     {
1552         STAFObjectConstructReference(pObject, iter->mapIterator->iter->second);
1553         ++iter->mapIterator->iter;
1554     }
1555     else return kSTAFInvalidObject;
1556 
1557     return kSTAFOk;
1558 }
1559 
1560 
STAFObjectIteratorDestruct(STAFObjectIterator_t * iter)1561 STAFRC_t STAFObjectIteratorDestruct(STAFObjectIterator_t *iter)
1562 {
1563     if (iter  == 0) return kSTAFInvalidObject;
1564     if (*iter == 0) return kSTAFInvalidObject;
1565 
1566     if ((*iter)->type == kSTAFObjectListIterator)
1567         delete (*iter)->listIterator;
1568     else
1569         delete (*iter)->mapIterator;
1570 
1571     delete *iter;
1572 
1573     *iter = 0;
1574 
1575     return kSTAFOk;
1576 }
1577 
1578 
STAFObjectMapHasKey(STAFObject_t map,STAFStringConst_t key,unsigned int * pHasKey)1579 STAFRC_t STAFObjectMapHasKey(STAFObject_t map, STAFStringConst_t key,
1580                              unsigned int *pHasKey)
1581 {
1582     if (map     == 0) return kSTAFInvalidObject;
1583     if (key     == 0) return kSTAFInvalidParm;
1584     if (pHasKey == 0) return kSTAFInvalidParm;
1585     // XXX: Might this want to be a new kSTAFInvalidOperation ?
1586     if (map->type != kSTAFMapObject) return kSTAFInvalidObject;
1587 
1588     STAFObjectMap::iterator iter = map->mapValue->find(key);
1589 
1590     if (iter == map->mapValue->end())
1591         *pHasKey = 0;
1592     else
1593         *pHasKey = 1;
1594 
1595     return kSTAFOk;
1596 }
1597 
1598 
STAFObjectMapGet(STAFObject_t map,STAFStringConst_t key,STAFObject_t * pObject)1599 STAFRC_t STAFObjectMapGet(STAFObject_t map, STAFStringConst_t key,
1600                           STAFObject_t *pObject)
1601 {
1602     if (map     == 0) return kSTAFInvalidObject;
1603     if (key     == 0) return kSTAFInvalidParm;
1604     if (pObject == 0) return kSTAFInvalidParm;
1605     // XXX: Might this want to be a new kSTAFInvalidOperation ?
1606     if (map->type != kSTAFMapObject) return kSTAFInvalidObject;
1607 
1608     STAFObjectMap::iterator iter = map->mapValue->find(key);
1609 
1610     if (iter == map->mapValue->end())
1611         STAFObjectConstructNone(pObject);
1612     else
1613         STAFObjectConstructReference(pObject, iter->second);
1614 
1615     return kSTAFOk;
1616 }
1617 
1618 
STAFObjectMapPut(STAFObject_t map,STAFStringConst_t key,STAFObject_t obj)1619 STAFRC_t STAFObjectMapPut(STAFObject_t map, STAFStringConst_t key,
1620                           STAFObject_t obj)
1621 {
1622     if (map == 0) return kSTAFInvalidObject;
1623     if (key == 0) return kSTAFInvalidParm;
1624     if (obj == 0) return kSTAFInvalidParm;
1625     // XXX: Might this want to be a new kSTAFInvalidOperation ?
1626     if (map->type != kSTAFMapObject) return kSTAFInvalidObject;
1627 
1628     // If there is already something associated with this key, we have to
1629     // get rid of it first
1630 
1631     STAFObjectMap::iterator iter = map->mapValue->find(key);
1632 
1633     if (iter != map->mapValue->end())
1634     {
1635         STAFObjectDestruct(&iter->second);
1636     }
1637 
1638     // Now add the new object
1639     // Note: The object being passed in gets turned into a reference
1640 
1641     STAFObject_t newObj = new STAFObjectImpl(*obj);
1642 
1643     obj->isRef = true;
1644 
1645     (*map->mapValue)[key] = newObj;
1646 
1647     return kSTAFOk;
1648 }
1649 
1650 
STAFObjectMarshallingContextSetMapClassDefinition(STAFObject_t context,STAFStringConst_t name,STAFObject_t obj)1651 STAFRC_t STAFObjectMarshallingContextSetMapClassDefinition(
1652     STAFObject_t context,
1653     STAFStringConst_t name,
1654     STAFObject_t obj)
1655 {
1656     if (context == 0) return kSTAFInvalidObject;
1657     if (name    == 0) return kSTAFInvalidParm;
1658     if (obj     == 0) return kSTAFInvalidParm;
1659     // XXX: Might this want to be a new kSTAFInvalidOperation ?
1660     if (context->type != kSTAFMarshallingContextObject)
1661         return kSTAFInvalidObject;
1662 
1663     // XXX: We need to do a good bit of checking to ensure that the map class
1664     //      definition is valid
1665 
1666     // If there is already something associated with this key, we have to
1667     // get rid of it first
1668 
1669     STAFObjectMap::iterator iter =
1670         context->contextValue->mapClassMap->mapValue->find(name);
1671 
1672     if (iter != context->contextValue->mapClassMap->mapValue->end())
1673     {
1674         STAFObjectDestruct(&iter->second);
1675     }
1676 
1677     // Now add the new object
1678     // Note: The object being passed in gets turned into a reference
1679 
1680     STAFObject_t newObj = new STAFObjectImpl(*obj);
1681 
1682     obj->isRef = true;
1683 
1684     (*context->contextValue->mapClassMap->mapValue)[name] = newObj;
1685 
1686     return kSTAFOk;
1687 }
1688 
1689 
STAFObjectMarshallingContextGetMapClassDefinition(STAFObject_t context,STAFStringConst_t name,STAFObject_t * pObject)1690 STAFRC_t STAFObjectMarshallingContextGetMapClassDefinition(
1691     STAFObject_t context,
1692     STAFStringConst_t name,
1693     STAFObject_t *pObject)
1694 {
1695     if (context == 0) return kSTAFInvalidObject;
1696     if (name    == 0) return kSTAFInvalidParm;
1697     if (pObject == 0) return kSTAFInvalidParm;
1698     // XXX: Might this want to be a new kSTAFInvalidOperation ?
1699     if (context->type != kSTAFMarshallingContextObject)
1700         return kSTAFInvalidObject;
1701 
1702     STAFObjectMap::iterator iter =
1703         context->contextValue->mapClassMap->mapValue->find(name);
1704 
1705     if (iter == context->contextValue->mapClassMap->mapValue->end())
1706         STAFObjectConstructNone(pObject);
1707     else
1708         STAFObjectConstructReference(pObject, iter->second);
1709 
1710     return kSTAFOk;
1711 }
1712 
1713 
STAFObjectMarshallingContextHasMapClassDefinition(STAFObject_t context,STAFStringConst_t name,unsigned int * pHasMapClassDefinition)1714 STAFRC_t STAFObjectMarshallingContextHasMapClassDefinition(
1715     STAFObject_t context,
1716     STAFStringConst_t name,
1717     unsigned int *pHasMapClassDefinition)
1718 {
1719     if (context                == 0) return kSTAFInvalidObject;
1720     if (name                   == 0) return kSTAFInvalidParm;
1721     if (pHasMapClassDefinition == 0) return kSTAFInvalidParm;
1722     // XXX: Might this want to be a new kSTAFInvalidOperation ?
1723     if (context->type != kSTAFMarshallingContextObject)
1724         return kSTAFInvalidObject;
1725 
1726     return STAFObjectMapHasKey(context->contextValue->mapClassMap, name,
1727                                pHasMapClassDefinition);
1728 }
1729 
1730 
STAFObjectMarshallingContextSetRootObject(STAFObject_t context,STAFObject_t obj)1731 STAFRC_t STAFObjectMarshallingContextSetRootObject(STAFObject_t context,
1732                                                    STAFObject_t obj)
1733 {
1734     if (context == 0) return kSTAFInvalidObject;
1735     if (obj     == 0) return kSTAFInvalidParm;
1736     // XXX: Might this want to be a new kSTAFInvalidOperation ?
1737     if (context->type != kSTAFMarshallingContextObject)
1738         return kSTAFInvalidObject;
1739 
1740     // Get rid of the old root object
1741 
1742     STAFObjectDestruct(&context->contextValue->rootObject);
1743 
1744     // Now set the new root object
1745     // Note: The object being passed in gets turned into a reference
1746 
1747     context->contextValue->rootObject = new STAFObjectImpl(*obj);
1748 
1749     obj->isRef = true;
1750 
1751     return kSTAFOk;
1752 }
1753 
1754 
STAFObjectMarshallingContextGetRootObject(STAFObject_t context,STAFObject_t * pObject)1755 STAFRC_t STAFObjectMarshallingContextGetRootObject(STAFObject_t context,
1756                                                    STAFObject_t *pObject)
1757 {
1758     if (context == 0) return kSTAFInvalidObject;
1759     if (pObject == 0) return kSTAFInvalidParm;
1760     // XXX: Might this want to be a new kSTAFInvalidOperation ?
1761     if (context->type != kSTAFMarshallingContextObject)
1762         return kSTAFInvalidObject;
1763 
1764     STAFObjectConstructReference(pObject, context->contextValue->rootObject);
1765 
1766     return kSTAFOk;
1767 }
1768 
1769 
STAFObjectMarshallingContextAdoptRootObject(STAFObject_t context,STAFObject_t * pObject)1770 STAFRC_t STAFObjectMarshallingContextAdoptRootObject(STAFObject_t context,
1771                                                      STAFObject_t *pObject)
1772 {
1773     if (context == 0) return kSTAFInvalidObject;
1774     if (pObject == 0) return kSTAFInvalidParm;
1775     // XXX: Might this want to be a new kSTAFInvalidOperation ?
1776     if (context->type != kSTAFMarshallingContextObject)
1777         return kSTAFInvalidObject;
1778 
1779     // Copy our root object into the destination
1780     *pObject = new STAFObjectImpl(*context->contextValue->rootObject);
1781 
1782     // Note: The marshalling context root object is now a reference
1783     context->contextValue->rootObject->isRef = true;
1784 
1785     return kSTAFOk;
1786 }
1787 
1788 
STAFObjectMarshallingContextGetPrimaryObject(STAFObject_t context,STAFObject_t * pObject)1789 STAFRC_t STAFObjectMarshallingContextGetPrimaryObject(STAFObject_t context,
1790                                                       STAFObject_t *pObject)
1791 {
1792     if (context == 0) return kSTAFInvalidObject;
1793     if (pObject == 0) return kSTAFInvalidParm;
1794     // XXX: Might this want to be a new kSTAFInvalidOperation ?
1795     if (context->type != kSTAFMarshallingContextObject)
1796         return kSTAFInvalidObject;
1797 
1798     if (context->contextValue->mapClassMap->mapValue->size() != 0)
1799         STAFObjectConstructReference(pObject, context);
1800     else
1801         STAFObjectConstructReference(pObject, context->contextValue->rootObject);
1802 
1803     return kSTAFOk;
1804 }
1805