/*
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 *
 */
/*
    File:       QTSSDictionary.cpp

    Contains:   Implementation of object defined in QTSSDictionary.h
                    

*/


#include "QTSSDictionary.h"

#include <string.h>
#include <stdio.h>

#include "MyAssert.h"
#include "OSMemory.h"
#include "QTSSDataConverter.h"

#include <errno.h>



QTSSDictionary::QTSSDictionary(QTSSDictionaryMap* inMap, OSMutex* inMutex) 
:   fAttributes(NULL), fInstanceAttrs(NULL), fInstanceArraySize(0),
    fMap(inMap), fInstanceMap(NULL), fMutexP(inMutex), fMyMutex(false), fLocked(false)
{
    if (fMap != NULL)
        fAttributes = NEW DictValueElement[inMap->GetNumAttrs()];
	if (fMutexP == NULL)
	{
		fMyMutex = true;
		fMutexP = NEW OSMutex();
	}
}

QTSSDictionary::~QTSSDictionary()
{
    if (fMap != NULL)
        this->DeleteAttributeData(fAttributes, fMap->GetNumAttrs());
    if (fAttributes != NULL)
        delete [] fAttributes;
    delete fInstanceMap;
    this->DeleteAttributeData(fInstanceAttrs, fInstanceArraySize);
    delete [] fInstanceAttrs;
	if (fMyMutex)
		delete fMutexP;
}

QTSSDictionary* QTSSDictionary::CreateNewDictionary(QTSSDictionaryMap* inMap, OSMutex* inMutex)
{
    return NEW QTSSDictionary(inMap, inMutex);
}

QTSS_Error QTSSDictionary::GetValuePtr(QTSS_AttributeID inAttrID, UInt32 inIndex,
                                            void** outValueBuffer, UInt32* outValueLen,
                                            Bool16 isInternal)
{
    // Check first to see if this is a static attribute or an instance attribute
    QTSSDictionaryMap* theMap = fMap;
    DictValueElement* theAttrs = fAttributes;
    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))
    {
        theMap = fInstanceMap;
        theAttrs = fInstanceAttrs;
    }

    if (theMap == NULL)
        return QTSS_AttrDoesntExist;
    
    SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);

    if (theMapIndex < 0)
        return QTSS_AttrDoesntExist;
    if (theMap->IsRemoved(theMapIndex))
        return QTSS_AttrDoesntExist;
    if ((!isInternal) && (!theMap->IsPreemptiveSafe(theMapIndex)) && !this->IsLocked())
        return QTSS_NotPreemptiveSafe;
    // An iterated attribute cannot have a param retrieval function
    if ((inIndex > 0) && (theMap->GetAttrFunction(theMapIndex) != NULL))
        return QTSS_BadIndex;
    // Check to make sure the index parameter is legal
    if ((inIndex > 0) && (inIndex >= theAttrs[theMapIndex].fNumAttributes))
        return QTSS_BadIndex;
        
        
    // Retrieve the parameter
    char* theBuffer = theAttrs[theMapIndex].fAttributeData.Ptr;
    *outValueLen = theAttrs[theMapIndex].fAttributeData.Len;
    
	Bool16 cacheable = theMap->IsCacheable(theMapIndex);
	if ( (theMap->GetAttrFunction(theMapIndex) != NULL) && ((cacheable && (*outValueLen == 0)) || !cacheable) )
    {
        // If function is cacheable: 
		// If the parameter doesn't have a value assigned yet, and there is an attribute
        // retrieval function provided, invoke that function now.
		// If function is *not* cacheable:
		// always call the function
		
        theBuffer = (char*)theMap->GetAttrFunction(theMapIndex)(this, outValueLen);

        //If the param retrieval function didn't return an explicit value for this attribute,
        //refetch the parameter out of the array, in case the function modified it.
        
        if (theBuffer == NULL)
        {
            theBuffer = theAttrs[theMapIndex].fAttributeData.Ptr;
            *outValueLen = theAttrs[theMapIndex].fAttributeData.Len;
        }
        
    }
#if DEBUG
    else
        // Make sure we aren't outside the bounds of attribute memory
        Assert(theAttrs[theMapIndex].fAllocatedLen >=
            (theAttrs[theMapIndex].fAttributeData.Len * (theAttrs[theMapIndex].fNumAttributes)));
#endif

    // Return an error if there is no data for this attribute
    if (*outValueLen == 0)
        return QTSS_ValueNotFound;
            
    theBuffer += theAttrs[theMapIndex].fAttributeData.Len * inIndex;
    *outValueBuffer = theBuffer;
        
    // strings need an extra dereference - moved it up
    if ((theMap->GetAttrType(theMapIndex) == qtssAttrDataTypeCharArray) && (theAttrs[theMapIndex].fNumAttributes > 1))
        {
            char** string = (char**)theBuffer;
            *outValueBuffer = *string;
            //*outValueLen = strlen(*string) + 1;
            *outValueLen = strlen(*string);
    }
    
    return QTSS_NoErr;
}



QTSS_Error QTSSDictionary::GetValue(QTSS_AttributeID inAttrID, UInt32 inIndex,
                                            void* ioValueBuffer, UInt32* ioValueLen)
{
    // If there is a mutex, lock it and get a pointer to the proper attribute
    OSMutexLocker locker(fMutexP);

    void* tempValueBuffer = NULL;
    UInt32 tempValueLen = 0;
    QTSS_Error theErr = this->GetValuePtr(inAttrID, inIndex, &tempValueBuffer, &tempValueLen, true);
    if (theErr != QTSS_NoErr)
        return theErr;
        
    if (theErr == QTSS_NoErr)
    {
        // If caller provided a buffer that's too small for this attribute, report that error
        if (tempValueLen > *ioValueLen)
            theErr = QTSS_NotEnoughSpace;
            
        // Only copy out the attribute if the buffer is big enough
        if ((ioValueBuffer != NULL) && (theErr == QTSS_NoErr))
            ::memcpy(ioValueBuffer, tempValueBuffer, tempValueLen);
            
        // Always set the ioValueLen to be the actual length of the attribute.
        *ioValueLen = tempValueLen;
    }

    return QTSS_NoErr;
}

QTSS_Error QTSSDictionary::GetValueAsString(QTSS_AttributeID inAttrID, UInt32 inIndex, char** outString)
{
    void* tempValueBuffer;
    UInt32 tempValueLen = 0;

    if (outString == NULL)  
        return QTSS_BadArgument;
        
    OSMutexLocker locker(fMutexP);
    QTSS_Error theErr = this->GetValuePtr(inAttrID, inIndex, &tempValueBuffer,
                                            &tempValueLen, true);
    if (theErr != QTSS_NoErr)
        return theErr;
        
    QTSSDictionaryMap* theMap = fMap;
    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))
        theMap = fInstanceMap;

    if (theMap == NULL)
        return QTSS_AttrDoesntExist;
    
    SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);
    Assert(theMapIndex >= 0);
    
    *outString = QTSSDataConverter::ValueToString(tempValueBuffer, tempValueLen, theMap->GetAttrType(theMapIndex));
    return QTSS_NoErr;
}



QTSS_Error QTSSDictionary::CreateObjectValue(QTSS_AttributeID inAttrID, UInt32* outIndex,
                                        QTSSDictionary** newObject, QTSSDictionaryMap* inMap, UInt32 inFlags)
{
    // Check first to see if this is a static attribute or an instance attribute
    QTSSDictionaryMap* theMap = fMap;
    DictValueElement* theAttrs = fAttributes;
    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))
    {
        theMap = fInstanceMap;
        theAttrs = fInstanceAttrs;
    }
    
    if (theMap == NULL)
        return QTSS_AttrDoesntExist;
    
    SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);
    
    // If there is a mutex, make this action atomic.
    OSMutexLocker locker(fMutexP);
    
    if (theMapIndex < 0)
        return QTSS_AttrDoesntExist;
    if ((!(inFlags & kDontObeyReadOnly)) && (!theMap->IsWriteable(theMapIndex)))
        return QTSS_ReadOnly;
    if (theMap->IsRemoved(theMapIndex))
        return QTSS_AttrDoesntExist;
    if (theMap->GetAttrType(theMapIndex) != qtssAttrDataTypeQTSS_Object)
        return QTSS_BadArgument;
        
    UInt32 numValues = theAttrs[theMapIndex].fNumAttributes;

    // if normal QTSSObjects have been added, then we can't add a dynamic one
    if (!theAttrs[theMapIndex].fIsDynamicDictionary && (numValues > 0))
        return QTSS_ReadOnly;

    QTSSDictionary* oldDict = NULL;
    *outIndex = numValues;  // add the object into the next spot

    UInt32 len = sizeof(QTSSDictionary*);
    QTSSDictionary* dict = CreateNewDictionary(inMap, fMutexP);
    
    // kind of a hack to avoid the check in SetValue
    theAttrs[theMapIndex].fIsDynamicDictionary = false;
    QTSS_Error err = SetValue(inAttrID, *outIndex, &dict, len, inFlags);
    if (err != QTSS_NoErr)
    {
        delete dict;
        return err;
    }
    
    if (oldDict != NULL)
    {
        delete oldDict;
    }
    
    theAttrs[theMapIndex].fIsDynamicDictionary = true;
    *newObject = dict;
    
    return QTSS_NoErr;
}

QTSS_Error QTSSDictionary::SetValue(QTSS_AttributeID inAttrID, UInt32 inIndex,
                                        const void* inBuffer,  UInt32 inLen,
                                        UInt32 inFlags)
{
    // Check first to see if this is a static attribute or an instance attribute
    QTSSDictionaryMap* theMap = fMap;
    DictValueElement* theAttrs = fAttributes;
    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))
    {
        theMap = fInstanceMap;
        theAttrs = fInstanceAttrs;
    }
    
    if (theMap == NULL)
        return QTSS_AttrDoesntExist;
    
    SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);
    
    // If there is a mutex, make this action atomic.
    OSMutexLocker locker(fMutexP);
    
    if (theMapIndex < 0)
        return QTSS_AttrDoesntExist;
    if ((!(inFlags & kDontObeyReadOnly)) && (!theMap->IsWriteable(theMapIndex)))
        return QTSS_ReadOnly;
    if (theMap->IsRemoved(theMapIndex))
        return QTSS_AttrDoesntExist;
    if (theAttrs[theMapIndex].fIsDynamicDictionary)
        return QTSS_ReadOnly;
    
    UInt32 numValues = theAttrs[theMapIndex].fNumAttributes;

    QTSS_AttrDataType dataType = theMap->GetAttrType(theMapIndex);
    UInt32 attrLen = inLen;
    if (dataType == qtssAttrDataTypeCharArray)
    {
        if (inIndex > 0)
            attrLen = sizeof(char*);    // value just contains a pointer
        
        if ((numValues == 1) && (inIndex == 1))
        {
            // we're adding a second value, so we need to change the storage from directly
            // storing the string to an array of string pointers
          
                // creating new memory here just to create a null terminated string
                // instead of directly using the old storage as the old storage didn't 
                // have its string null terminated
                        UInt32 tempStringLen = theAttrs[theMapIndex].fAttributeData.Len;
                        char* temp = NEW char[tempStringLen + 1];
                        ::memcpy(temp, theAttrs[theMapIndex].fAttributeData.Ptr, tempStringLen);
                        temp[tempStringLen] = '\0';
                        delete [] theAttrs[theMapIndex].fAttributeData.Ptr;
                        
            //char* temp = theAttrs[theMapIndex].fAttributeData.Ptr;
            
            theAttrs[theMapIndex].fAllocatedLen = 16 * sizeof(char*);
            theAttrs[theMapIndex].fAttributeData.Ptr = NEW char[theAttrs[theMapIndex].fAllocatedLen];
            theAttrs[theMapIndex].fAttributeData.Len = sizeof(char*);
            // store off original string as first value in array
            *(char**)theAttrs[theMapIndex].fAttributeData.Ptr = temp;
                        // question: why isn't theAttrs[theMapIndex].fAllocatedInternally set to true?
        }
    }
    else
    {
        // If this attribute is iterated, this new value
        // must be the same size as all the others.
        if (((inIndex > 0) || (numValues > 1))
                 &&(theAttrs[theMapIndex].fAttributeData.Len != 0) && (inLen != theAttrs[theMapIndex].fAttributeData.Len))
            return QTSS_BadArgument;
    }
    
    //
    // Can't put empty space into the array of values
    if (inIndex > numValues)
        return QTSS_BadIndex;
        
    if ((attrLen * (inIndex + 1)) > theAttrs[theMapIndex].fAllocatedLen)
    {
        // We need to reallocate this buffer.
        UInt32 theLen;
        
        if (inIndex == 0)
            theLen = attrLen;   // most attributes are single valued, so allocate just enough space
        else
            theLen = 2 * (attrLen * (inIndex + 1));// Allocate twice as much as we need
        char* theNewBuffer = NEW char[theLen];
        if (inIndex > 0)
        {
            // Copy out the old attribute data
            ::memcpy(theNewBuffer, theAttrs[theMapIndex].fAttributeData.Ptr,
                        theAttrs[theMapIndex].fAllocatedLen);
        }
        
        // Now get rid of the old stuff. Delete the buffer
        // if it was already allocated internally
        if (theAttrs[theMapIndex].fAllocatedInternally)
            delete [] theAttrs[theMapIndex].fAttributeData.Ptr;
        
        // Finally, update this attribute structure with all the new values.
        theAttrs[theMapIndex].fAttributeData.Ptr = theNewBuffer;
        theAttrs[theMapIndex].fAllocatedLen = theLen;
        theAttrs[theMapIndex].fAllocatedInternally = true;
    }
        
    // At this point, we should always have enough space to write what we want
    Assert(theAttrs[theMapIndex].fAllocatedLen >= (attrLen * (inIndex + 1)));
    
    // Copy the new data to the right place in our data buffer
    void *attributeBufferPtr;
    if ((dataType != qtssAttrDataTypeCharArray) || ((numValues < 2) && (inIndex == 0)))
    {
        attributeBufferPtr = theAttrs[theMapIndex].fAttributeData.Ptr + (inLen * inIndex);
        theAttrs[theMapIndex].fAttributeData.Len = inLen;
    }
    else
    {
            //attributeBufferPtr = NEW char[inLen];
            // allocating one extra so that we can null terminate the string
            attributeBufferPtr = NEW char[inLen + 1];
                char* tempBuffer = (char*)attributeBufferPtr;
                tempBuffer[inLen] = '\0';
                
        //char** valuePtr = (char**)theAttrs[theMapIndex].fAttributeData.Ptr + (inLen * inIndex);
        // The offset should be (attrLen * inIndex) and not (inLen * inIndex) 
        char** valuePtr = (char**)(theAttrs[theMapIndex].fAttributeData.Ptr + (attrLen * inIndex));
        if (inIndex < numValues)    // we're replacing an existing string
            delete *valuePtr;
        *valuePtr = (char*)attributeBufferPtr;
    }
    
    ::memcpy(attributeBufferPtr, inBuffer, inLen);
    

    // Set the number of attributes to be proper
    if (inIndex >= theAttrs[theMapIndex].fNumAttributes)
    {
        //
        // We should never have to increment num attributes by more than 1
        Assert(theAttrs[theMapIndex].fNumAttributes == inIndex);
        theAttrs[theMapIndex].fNumAttributes++;
    }

    //
    // Call the completion routine
    if (((fMap == NULL) || fMap->CompleteFunctionsAllowed()) && !(inFlags & kDontCallCompletionRoutine))
        this->SetValueComplete(theMapIndex, theMap, inIndex, attributeBufferPtr, inLen);
    
    return QTSS_NoErr;
}


QTSS_Error QTSSDictionary::SetValuePtr(QTSS_AttributeID inAttrID,
                                        const void* inBuffer,  UInt32 inLen,
                                        UInt32 inFlags)
{
    // Check first to see if this is a static attribute or an instance attribute
    QTSSDictionaryMap* theMap = fMap;
    DictValueElement* theAttrs = fAttributes;
    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))
    {
        theMap = fInstanceMap;
        theAttrs = fInstanceAttrs;
    }
    
    if (theMap == NULL)
        return QTSS_AttrDoesntExist;
    
    SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);
    
    // If there is a mutex, make this action atomic.
    OSMutexLocker locker(fMutexP);
    
    if (theMapIndex < 0)
        return QTSS_AttrDoesntExist;
    if ((!(inFlags & kDontObeyReadOnly)) && (!theMap->IsWriteable(theMapIndex)))
        return QTSS_ReadOnly;
    if (theMap->IsRemoved(theMapIndex))
        return QTSS_AttrDoesntExist;
    if (theAttrs[theMapIndex].fIsDynamicDictionary)
        return QTSS_ReadOnly;
    
    UInt32 numValues = theAttrs[theMapIndex].fNumAttributes;
    if ((numValues > 0) || (theAttrs[theMapIndex].fAttributeData.Ptr != NULL))
        return QTSS_BadArgument;    // you can only set the pointer if you haven't done set value

    theAttrs[theMapIndex].fAttributeData.Ptr = (char*) inBuffer;
    theAttrs[theMapIndex].fAttributeData.Len = inLen;
    theAttrs[theMapIndex].fAllocatedLen = inLen;
    
    // This function assumes there is only one value and that it isn't allocated internally
    theAttrs[theMapIndex].fNumAttributes = 1;
        
        return QTSS_NoErr;
}

QTSS_Error QTSSDictionary::RemoveValue(QTSS_AttributeID inAttrID, UInt32 inIndex, UInt32 inFlags)
{
    // Check first to see if this is a static attribute or an instance attribute
    QTSSDictionaryMap* theMap = fMap;
    DictValueElement* theAttrs = fAttributes;
    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))
    {
        theMap = fInstanceMap;
        theAttrs = fInstanceAttrs;
    }
    
    if (theMap == NULL)
        return QTSS_AttrDoesntExist;
    
    SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);
    
    // If there is a mutex, make this action atomic.
    OSMutexLocker locker(fMutexP);
    
    if (theMapIndex < 0)
        return QTSS_AttrDoesntExist;
    if ((!(inFlags & kDontObeyReadOnly)) && (!theMap->IsWriteable(theMapIndex)))
        return QTSS_ReadOnly;
    if (theMap->IsRemoved(theMapIndex))
        return QTSS_AttrDoesntExist;
    if ((theMap->GetAttrFunction(theMapIndex) != NULL) && (inIndex > 0))
        return QTSS_BadIndex;
        
    UInt32 numValues = theAttrs[theMapIndex].fNumAttributes;

    UInt32 theValueLen = theAttrs[theMapIndex].fAttributeData.Len;

    if (theAttrs[theMapIndex].fIsDynamicDictionary)
    {
        // this is an internally allocated dictionary, so we need to desctruct it
        Assert(theMap->GetAttrType(theMapIndex) == qtssAttrDataTypeQTSS_Object);
        Assert(theValueLen == sizeof(QTSSDictionary*));
        QTSSDictionary* dict = *(QTSSDictionary**)(theAttrs[theMapIndex].fAttributeData.Ptr + (theValueLen * inIndex));
        delete dict;
    }
    
    QTSS_AttrDataType dataType = theMap->GetAttrType(theMapIndex);
    if ((dataType == qtssAttrDataTypeCharArray) && (numValues > 1))
    {
        // we need to delete the string
        char* str = *(char**)(theAttrs[theMapIndex].fAttributeData.Ptr + (theValueLen * inIndex));
        delete str;
    }

    //
    // If there are values after this one in the array, move them.
    if (inIndex + 1 < theAttrs[theMapIndex].fNumAttributes) 
    {	
        ::memmove(  theAttrs[theMapIndex].fAttributeData.Ptr + (theValueLen * inIndex),
                theAttrs[theMapIndex].fAttributeData.Ptr + (theValueLen * (inIndex + 1)),
                theValueLen * ( (theAttrs[theMapIndex].fNumAttributes) - inIndex - 1));
    } // else this is the last in the array so just truncate.
    //
    // Update our number of values
    theAttrs[theMapIndex].fNumAttributes--;
    if (theAttrs[theMapIndex].fNumAttributes == 0)
        theAttrs[theMapIndex].fAttributeData.Len = 0;

    if ((dataType == qtssAttrDataTypeCharArray) && (theAttrs[theMapIndex].fNumAttributes == 1))
    {
        // we only have one string left, so we don't need the extra pointer
        char* str = *(char**)(theAttrs[theMapIndex].fAttributeData.Ptr);
        delete theAttrs[theMapIndex].fAttributeData.Ptr;
        theAttrs[theMapIndex].fAttributeData.Ptr = str;
        theAttrs[theMapIndex].fAttributeData.Len = strlen(str);
        theAttrs[theMapIndex].fAllocatedLen = strlen(str);
    }

    //
    // Call the completion routine
    if (((fMap == NULL) || fMap->CompleteFunctionsAllowed()) && !(inFlags & kDontCallCompletionRoutine))
        this->RemoveValueComplete(theMapIndex, theMap, inIndex);
        
    return QTSS_NoErr;
}

UInt32  QTSSDictionary::GetNumValues(QTSS_AttributeID inAttrID)
{
    // Check first to see if this is a static attribute or an instance attribute
    QTSSDictionaryMap* theMap = fMap;
    DictValueElement* theAttrs = fAttributes;
    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))
    {
        theMap = fInstanceMap;
        theAttrs = fInstanceAttrs;
    }

    if (theMap == NULL)
        return 0;

    SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);
    if (theMapIndex < 0)
        return 0;

    return theAttrs[theMapIndex].fNumAttributes;
}

void    QTSSDictionary::SetNumValues(QTSS_AttributeID inAttrID, UInt32 inNumValues)
{
    // Check first to see if this is a static attribute or an instance attribute
    QTSSDictionaryMap* theMap = fMap;
    DictValueElement* theAttrs = fAttributes;
    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))
    {
        theMap = fInstanceMap;
        theAttrs = fInstanceAttrs;
    }

    if (theMap == NULL)
        return;

    SInt32 theMapIndex = theMap->ConvertAttrIDToArrayIndex(inAttrID);
    if (theMapIndex < 0)
        return;

    UInt32 numAttributes = theAttrs[theMapIndex].fNumAttributes;
    // this routine can only be ever used to reduce the number of values        
    if (inNumValues >= numAttributes || numAttributes == 0)
        return;

    QTSS_AttrDataType dataType = theMap->GetAttrType(theMapIndex);
    if (theAttrs[theMapIndex].fIsDynamicDictionary || (dataType == qtssAttrDataTypeCharArray))
    {         
        // getting rid of dictionaries or strings is tricky, so it's easier to call remove value
        for (UInt32 removeCount = numAttributes - inNumValues; removeCount > 0; removeCount--)
        {	// the delete index passed to RemoveValue is always the last in the array.
            this->RemoveValue(inAttrID, theAttrs[theMapIndex].fNumAttributes - 1, kDontObeyReadOnly);
        }
    }
    else
    {
        theAttrs[theMapIndex].fNumAttributes = inNumValues;
        if (inNumValues == 0)
            theAttrs[theMapIndex].fAttributeData.Len = 0;
    }
}

void    QTSSDictionary::SetVal( QTSS_AttributeID inAttrID,
                                    void* inValueBuffer,
                                    UInt32 inBufferLen)
{ 
    Assert(inAttrID >= 0);
    Assert(fMap);
    Assert((UInt32)inAttrID < fMap->GetNumAttrs());
    fAttributes[inAttrID].fAttributeData.Ptr = (char*)inValueBuffer;
    fAttributes[inAttrID].fAttributeData.Len = inBufferLen;
    fAttributes[inAttrID].fAllocatedLen = inBufferLen;
    
    // This function assumes there is only one value and that it isn't allocated internally
    fAttributes[inAttrID].fNumAttributes = 1;
}

void    QTSSDictionary::SetEmptyVal(QTSS_AttributeID inAttrID, void* inBuf, UInt32 inBufLen)
{
    Assert(inAttrID >= 0);
    Assert(fMap);
    Assert((UInt32)inAttrID < fMap->GetNumAttrs());
    fAttributes[inAttrID].fAttributeData.Ptr = (char*)inBuf;
    fAttributes[inAttrID].fAllocatedLen = inBufLen;

#if !ALLOW_NON_WORD_ALIGN_ACCESS
    //if (((UInt32) inBuf % 4) > 0)
    //  qtss_printf("bad align by %d\n",((UInt32) inBuf % 4) );
    Assert( ((PointerSizedInt) inBuf % 4) == 0 );
#endif
}


QTSS_Error  QTSSDictionary::AddInstanceAttribute(   const char* inAttrName,
                                                    QTSS_AttrFunctionPtr inFuncPtr,
                                                    QTSS_AttrDataType inDataType,
                                                    QTSS_AttrPermission inPermission )
{
    if ((fMap != NULL) && !fMap->InstanceAttrsAllowed())
        return QTSS_InstanceAttrsNotAllowed;
        
    OSMutexLocker locker(fMutexP);

    //
    // Check to see if this attribute exists in the static map. If it does,
    // we can't add it as an instance attribute, so return an error
    QTSSAttrInfoDict* throwAway = NULL;
    QTSS_Error theErr;
    if (fMap != NULL)
    {
        theErr = fMap->GetAttrInfoByName(inAttrName, &throwAway);
        if (theErr == QTSS_NoErr)
            return QTSS_AttrNameExists;
    }
    
    if (fInstanceMap == NULL)
    {
        UInt32 theFlags = QTSSDictionaryMap::kAllowRemoval | QTSSDictionaryMap::kIsInstanceMap;
        if ((fMap == NULL) || fMap->CompleteFunctionsAllowed())
            theFlags |= QTSSDictionaryMap::kCompleteFunctionsAllowed;
            
        fInstanceMap = new QTSSDictionaryMap( 0, theFlags );
    }
    
    //
    // Add the attribute into the Dictionary Map.
    theErr = fInstanceMap->AddAttribute(inAttrName, inFuncPtr, inDataType, inPermission);
    if (theErr != QTSS_NoErr)
        return theErr;
    
    //
    // Check to see if our DictValueElement array needs to be reallocated   
    if (fInstanceMap->GetNumAttrs() >= fInstanceArraySize)
    {
        UInt32 theNewArraySize = fInstanceArraySize * 2;
        if (theNewArraySize == 0)
            theNewArraySize = QTSSDictionaryMap::kMinArraySize;
        Assert(theNewArraySize > fInstanceMap->GetNumAttrs());
        
        DictValueElement* theNewArray = NEW DictValueElement[theNewArraySize];
        if (fInstanceAttrs != NULL)
        {
            ::memcpy(theNewArray, fInstanceAttrs, sizeof(DictValueElement) * fInstanceArraySize);

            //
            // Delete the old instance attr structs, this does not delete the actual attribute memory
            delete [] fInstanceAttrs;
        }
        fInstanceAttrs = theNewArray;
        fInstanceArraySize = theNewArraySize;
    }
    return QTSS_NoErr;
}
QTSS_Error  QTSSDictionary::RemoveInstanceAttribute(QTSS_AttributeID inAttr)
{
    OSMutexLocker locker(fMutexP);

    if (fInstanceMap != NULL)
    {   
        QTSS_Error theErr = fInstanceMap->CheckRemovePermission(inAttr);
        if (theErr != QTSS_NoErr)
            return theErr;

        this->SetNumValues(inAttr,(UInt32) 0); // make sure to set num values to 0 since it is a deleted attribute
        fInstanceMap->RemoveAttribute(inAttr);
    }
    else
        return QTSS_BadArgument;
    
    //
    // Call the completion routine
    SInt32 theMapIndex = fInstanceMap->ConvertAttrIDToArrayIndex(inAttr);
    this->RemoveInstanceAttrComplete(theMapIndex, fInstanceMap);
    
    return QTSS_NoErr;
}

QTSS_Error QTSSDictionary::GetAttrInfoByIndex(UInt32 inIndex, QTSSAttrInfoDict** outAttrInfoDict)
{
    if (outAttrInfoDict == NULL)
        return QTSS_BadArgument;
        
    OSMutexLocker locker(fMutexP);

    UInt32 numInstanceValues = 0;
    UInt32 numStaticValues = 0;
    
    if (fMap != NULL)
        numStaticValues = fMap->GetNumNonRemovedAttrs();
    
    if (fInstanceMap != NULL)
        numInstanceValues = fInstanceMap->GetNumNonRemovedAttrs();
    
    if (inIndex >= (numStaticValues + numInstanceValues))
        return QTSS_AttrDoesntExist;
    
    if ( (numStaticValues > 0)  && (inIndex < numStaticValues) )
        return fMap->GetAttrInfoByIndex(inIndex, outAttrInfoDict);
    else
    {
        Assert(fInstanceMap != NULL);
        return fInstanceMap->GetAttrInfoByIndex(inIndex - numStaticValues, outAttrInfoDict);
    }
}

QTSS_Error QTSSDictionary::GetAttrInfoByID(QTSS_AttributeID inAttrID, QTSSAttrInfoDict** outAttrInfoDict)
{
    if (outAttrInfoDict == NULL)
        return QTSS_BadArgument;
        
    if (QTSSDictionaryMap::IsInstanceAttrID(inAttrID))
    {
        OSMutexLocker locker(fMutexP);

        if (fInstanceMap != NULL)
            return fInstanceMap->GetAttrInfoByID(inAttrID, outAttrInfoDict);
    }
    else
        if (fMap != NULL) return fMap->GetAttrInfoByID(inAttrID, outAttrInfoDict);
            
    return QTSS_AttrDoesntExist;
}

QTSS_Error QTSSDictionary::GetAttrInfoByName(const char* inAttrName, QTSSAttrInfoDict** outAttrInfoDict)
{
    QTSS_Error theErr = QTSS_AttrDoesntExist;
    if (outAttrInfoDict == NULL)
        return QTSS_BadArgument;
        
    // Retrieve the Dictionary Map for this object type
    if (fMap != NULL)
        theErr = fMap->GetAttrInfoByName(inAttrName, outAttrInfoDict);
    
    if (theErr == QTSS_AttrDoesntExist)
    {
        OSMutexLocker locker(fMutexP);
        if (fInstanceMap != NULL)
            theErr = fInstanceMap->GetAttrInfoByName(inAttrName, outAttrInfoDict);
    }
    return theErr;
}

void QTSSDictionary::DeleteAttributeData(DictValueElement* inDictValues, UInt32 inNumValues)
{
    for (UInt32 x = 0; x < inNumValues; x++)
    {
        if (inDictValues[x].fAllocatedInternally)
            delete [] inDictValues[x].fAttributeData.Ptr;
    }
}



QTSSAttrInfoDict::AttrInfo  QTSSAttrInfoDict::sAttributes[] =
{
    /* 0 */ { "qtssAttrName",       NULL,       qtssAttrDataTypeCharArray,  qtssAttrModeRead | qtssAttrModePreempSafe },
    /* 1 */ { "qtssAttrID",         NULL,       qtssAttrDataTypeUInt32,     qtssAttrModeRead | qtssAttrModePreempSafe },
    /* 2 */ { "qtssAttrDataType",   NULL,       qtssAttrDataTypeUInt32,     qtssAttrModeRead | qtssAttrModePreempSafe },
    /* 3 */ { "qtssAttrPermissions",NULL,       qtssAttrDataTypeUInt32,     qtssAttrModeRead | qtssAttrModePreempSafe }
};

QTSSAttrInfoDict::QTSSAttrInfoDict()
: QTSSDictionary(QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kAttrInfoDictIndex)), fID(qtssIllegalAttrID)
{}

QTSSAttrInfoDict::~QTSSAttrInfoDict() {}



QTSSDictionaryMap*      QTSSDictionaryMap::sDictionaryMaps[kNumDictionaries + kNumDynamicDictionaryTypes];
UInt32                  QTSSDictionaryMap::sNextDynamicMap = kNumDictionaries;

void QTSSDictionaryMap::Initialize()
{
    //
    // Have to do this one first because this dict map is used by all the other
    // dict maps.
    sDictionaryMaps[kAttrInfoDictIndex]     = new QTSSDictionaryMap(qtssAttrInfoNumParams);

    // Setup the Attr Info attributes before constructing any other dictionaries
    for (UInt32 x = 0; x < qtssAttrInfoNumParams; x++)
        sDictionaryMaps[kAttrInfoDictIndex]->SetAttribute(x, QTSSAttrInfoDict::sAttributes[x].fAttrName,
                                                            QTSSAttrInfoDict::sAttributes[x].fFuncPtr,
                                                            QTSSAttrInfoDict::sAttributes[x].fAttrDataType,
                                                            QTSSAttrInfoDict::sAttributes[x].fAttrPermission);

    sDictionaryMaps[kServerDictIndex]       = new QTSSDictionaryMap(qtssSvrNumParams, QTSSDictionaryMap::kCompleteFunctionsAllowed);
    sDictionaryMaps[kPrefsDictIndex]        = new QTSSDictionaryMap(qtssPrefsNumParams, QTSSDictionaryMap::kInstanceAttrsAllowed | QTSSDictionaryMap::kCompleteFunctionsAllowed);
    sDictionaryMaps[kTextMessagesDictIndex] = new QTSSDictionaryMap(qtssMsgNumParams);
    sDictionaryMaps[kServiceDictIndex]      = new QTSSDictionaryMap(0);
    sDictionaryMaps[kRTPStreamDictIndex]    = new QTSSDictionaryMap(qtssRTPStrNumParams);
	sDictionaryMaps[kClientSessionDictIndex]= new QTSSDictionaryMap(qtssCliSesNumParams, QTSSDictionaryMap::kCompleteFunctionsAllowed);
    sDictionaryMaps[kRTSPSessionDictIndex]  = new QTSSDictionaryMap(qtssRTSPSesNumParams);
    sDictionaryMaps[kRTSPRequestDictIndex]  = new QTSSDictionaryMap(qtssRTSPReqNumParams);
    sDictionaryMaps[kRTSPHeaderDictIndex]   = new QTSSDictionaryMap(qtssNumHeaders);
    sDictionaryMaps[kFileDictIndex]         = new QTSSDictionaryMap(qtssFlObjNumParams);
    sDictionaryMaps[kModuleDictIndex]       = new QTSSDictionaryMap(qtssModNumParams);
    sDictionaryMaps[kModulePrefsDictIndex]  = new QTSSDictionaryMap(0, QTSSDictionaryMap::kInstanceAttrsAllowed | QTSSDictionaryMap::kCompleteFunctionsAllowed);
    sDictionaryMaps[kQTSSUserProfileDictIndex] = new QTSSDictionaryMap(qtssUserNumParams);
    sDictionaryMaps[kQTSSConnectedUserDictIndex] = new QTSSDictionaryMap(qtssConnectionNumParams);
}

QTSSDictionaryMap::QTSSDictionaryMap(UInt32 inNumReservedAttrs, UInt32 inFlags)
:   fNextAvailableID(inNumReservedAttrs), fNumValidAttrs(inNumReservedAttrs),fAttrArraySize(inNumReservedAttrs), fFlags(inFlags)
{
    if (fAttrArraySize < kMinArraySize)
        fAttrArraySize = kMinArraySize;
    fAttrArray = NEW QTSSAttrInfoDict*[fAttrArraySize];
    ::memset(fAttrArray, 0, sizeof(QTSSAttrInfoDict*) * fAttrArraySize);
}

QTSS_Error QTSSDictionaryMap::AddAttribute( const char* inAttrName,
                                            QTSS_AttrFunctionPtr inFuncPtr,
                                            QTSS_AttrDataType inDataType,
                                            QTSS_AttrPermission inPermission)
{
    if (inAttrName == NULL || ::strlen(inAttrName) > QTSS_MAX_ATTRIBUTE_NAME_SIZE)
        return QTSS_BadArgument;

    for (UInt32 count = 0; count < fNextAvailableID; count++)
    {
        if  (::strcmp(&fAttrArray[count]->fAttrInfo.fAttrName[0], inAttrName) == 0)
        {   // found the name in the dictionary
            if (fAttrArray[count]->fAttrInfo.fAttrPermission & qtssPrivateAttrModeRemoved )
            { // it is a previously removed attribute
                if (fAttrArray[count]->fAttrInfo.fAttrDataType == inDataType)
                { //same type so reuse the attribute
                    QTSS_AttributeID attrID = fAttrArray[count]->fID; 
                    this->UnRemoveAttribute(attrID); 
                    fAttrArray[count]->fAttrInfo.fFuncPtr = inFuncPtr; // reset
                    fAttrArray[count]->fAttrInfo.fAttrPermission = inPermission;// reset
                    return QTSS_NoErr; // nothing left to do. It is re-added.
                }
                
                // a removed attribute with the same name but different type--so keep checking 
                continue;
            }
            // an error, an active attribute with this name exists
            return QTSS_AttrNameExists;
        }
    }

    if (fAttrArraySize == fNextAvailableID)
    {
        // If there currently isn't an attribute array, or if the current array
        // is full, allocate a new array and copy all the old stuff over to the new array.
        
        UInt32 theNewArraySize = fAttrArraySize * 2;
        if (theNewArraySize == 0)
            theNewArraySize = kMinArraySize;
        
        QTSSAttrInfoDict** theNewArray = NEW QTSSAttrInfoDict*[theNewArraySize];
        ::memset(theNewArray, 0, sizeof(QTSSAttrInfoDict*) * theNewArraySize);
        if (fAttrArray != NULL)
        {
            ::memcpy(theNewArray, fAttrArray, sizeof(QTSSAttrInfoDict*) * fAttrArraySize);
            delete [] fAttrArray;
        }
        fAttrArray = theNewArray;
        fAttrArraySize = theNewArraySize;
    }
    
    QTSS_AttributeID theID = fNextAvailableID;
    fNextAvailableID++;
    fNumValidAttrs++;
    if (fFlags & kIsInstanceMap)
        theID |= 0x80000000; // Set the high order bit to indicate this is an instance attr

    // Copy the information into the first available element
    // Currently, all attributes added in this fashion are always writeable
    this->SetAttribute(theID, inAttrName, inFuncPtr, inDataType, inPermission); 
    return QTSS_NoErr;
}

void QTSSDictionaryMap::SetAttribute(   QTSS_AttributeID inID, 
                                        const char* inAttrName,
                                        QTSS_AttrFunctionPtr inFuncPtr,
                                        QTSS_AttrDataType inDataType,
                                        QTSS_AttrPermission inPermission )
{
    UInt32 theIndex = QTSSDictionaryMap::ConvertAttrIDToArrayIndex(inID);
    UInt32 theNameLen = ::strlen(inAttrName);
    Assert(theNameLen < QTSS_MAX_ATTRIBUTE_NAME_SIZE);
    Assert(fAttrArray[theIndex] == NULL);
    
    fAttrArray[theIndex] = NEW QTSSAttrInfoDict;
    
    //Copy the information into the first available element
    fAttrArray[theIndex]->fID = inID;
        
    ::strcpy(&fAttrArray[theIndex]->fAttrInfo.fAttrName[0], inAttrName);
    fAttrArray[theIndex]->fAttrInfo.fFuncPtr = inFuncPtr;
    fAttrArray[theIndex]->fAttrInfo.fAttrDataType = inDataType; 
    fAttrArray[theIndex]->fAttrInfo.fAttrPermission = inPermission;
    
    fAttrArray[theIndex]->SetVal(qtssAttrName, &fAttrArray[theIndex]->fAttrInfo.fAttrName[0], theNameLen);
    fAttrArray[theIndex]->SetVal(qtssAttrID, &fAttrArray[theIndex]->fID, sizeof(fAttrArray[theIndex]->fID));
    fAttrArray[theIndex]->SetVal(qtssAttrDataType, &fAttrArray[theIndex]->fAttrInfo.fAttrDataType, sizeof(fAttrArray[theIndex]->fAttrInfo.fAttrDataType));
    fAttrArray[theIndex]->SetVal(qtssAttrPermissions, &fAttrArray[theIndex]->fAttrInfo.fAttrPermission, sizeof(fAttrArray[theIndex]->fAttrInfo.fAttrPermission));
}

QTSS_Error  QTSSDictionaryMap::CheckRemovePermission(QTSS_AttributeID inAttrID)
{
    SInt32 theIndex = this->ConvertAttrIDToArrayIndex(inAttrID);
    if (theIndex < 0)
        return QTSS_AttrDoesntExist;
    
    if (0 == (fAttrArray[theIndex]->fAttrInfo.fAttrPermission & qtssAttrModeDelete))
         return QTSS_BadArgument;

    if (!(fFlags & kAllowRemoval))
        return QTSS_BadArgument;
    
    return QTSS_NoErr;
}

QTSS_Error  QTSSDictionaryMap::RemoveAttribute(QTSS_AttributeID inAttrID)
{
    SInt32 theIndex = this->ConvertAttrIDToArrayIndex(inAttrID);
    if (theIndex < 0)
        return QTSS_AttrDoesntExist;
    
    Assert(fFlags & kAllowRemoval);
    if (!(fFlags & kAllowRemoval))
        return QTSS_BadArgument;
    
    //qtss_printf("QTSSDictionaryMap::RemoveAttribute arraySize=%lu numNonRemove= %lu fAttrArray[%lu]->fAttrInfo.fAttrName=%s\n",this->GetNumAttrs(), this->GetNumNonRemovedAttrs(), theIndex,fAttrArray[theIndex]->fAttrInfo.fAttrName);
    //
    // Don't actually touch the attribute or anything. Just flag the
    // it as removed.
    fAttrArray[theIndex]->fAttrInfo.fAttrPermission |= qtssPrivateAttrModeRemoved;
    fNumValidAttrs--;
    Assert(fNumValidAttrs < 1000000);
    return QTSS_NoErr;
}

QTSS_Error  QTSSDictionaryMap::UnRemoveAttribute(QTSS_AttributeID inAttrID)
{
    if (this->ConvertAttrIDToArrayIndex(inAttrID) == -1)
        return QTSS_AttrDoesntExist;
    
    SInt32 theIndex = this->ConvertAttrIDToArrayIndex(inAttrID);
    if (theIndex < 0)
        return QTSS_AttrDoesntExist;
        
    fAttrArray[theIndex]->fAttrInfo.fAttrPermission &= ~qtssPrivateAttrModeRemoved;
    
    fNumValidAttrs++;
    return QTSS_NoErr;
}

QTSS_Error  QTSSDictionaryMap::GetAttrInfoByName(const char* inAttrName, QTSSAttrInfoDict** outAttrInfoObject,
                                                    Bool16 returnRemovedAttr)
{
    if (outAttrInfoObject == NULL)
        return QTSS_BadArgument;

    for (UInt32 count = 0; count < fNextAvailableID; count++)
    {
        if (::strcmp(&fAttrArray[count]->fAttrInfo.fAttrName[0], inAttrName) == 0)
        {
            if ((fAttrArray[count]->fAttrInfo.fAttrPermission & qtssPrivateAttrModeRemoved) && (!returnRemovedAttr))
                continue;
                
            *outAttrInfoObject = fAttrArray[count];
            return QTSS_NoErr;
        }   
    }
    return QTSS_AttrDoesntExist;
}

QTSS_Error  QTSSDictionaryMap::GetAttrInfoByID(QTSS_AttributeID inID, QTSSAttrInfoDict** outAttrInfoObject)
{
    if (outAttrInfoObject == NULL)
        return QTSS_BadArgument;

    SInt32 theIndex = this->ConvertAttrIDToArrayIndex(inID);
    if (theIndex < 0)
        return QTSS_AttrDoesntExist;
    
    if (fAttrArray[theIndex]->fAttrInfo.fAttrPermission & qtssPrivateAttrModeRemoved)
        return QTSS_AttrDoesntExist;
        
    *outAttrInfoObject = fAttrArray[theIndex];
    return QTSS_NoErr;
}

QTSS_Error  QTSSDictionaryMap::GetAttrInfoByIndex(UInt32 inIndex, QTSSAttrInfoDict** outAttrInfoObject)
{
    if (outAttrInfoObject == NULL)
        return QTSS_BadArgument;
    if (inIndex >= this->GetNumNonRemovedAttrs())
        return QTSS_AttrDoesntExist;
        
    UInt32 actualIndex = inIndex;
    UInt32 max = this->GetNumAttrs();
    if (fFlags & kAllowRemoval)
    {
        // If this dictionary map allows attributes to be removed, then
        // the iteration index and array indexes won't line up exactly, so
        // we have to iterate over the whole map all the time
        actualIndex = 0;
        for (UInt32 x = 0; x < max; x++)
        {   if (fAttrArray[x] && (fAttrArray[x]->fAttrInfo.fAttrPermission & qtssPrivateAttrModeRemoved) )
            {   continue;
            }
                
            if (actualIndex == inIndex)
            {   actualIndex = x;
                break;
            }
            actualIndex++;
        }
    }
    //qtss_printf("QTSSDictionaryMap::GetAttrInfoByIndex arraySize=%lu numNonRemove= %lu fAttrArray[%lu]->fAttrInfo.fAttrName=%s\n",this->GetNumAttrs(), this->GetNumNonRemovedAttrs(), actualIndex,fAttrArray[actualIndex]->fAttrInfo.fAttrName);
    Assert(actualIndex < fNextAvailableID);
    Assert(!(fAttrArray[actualIndex]->fAttrInfo.fAttrPermission & qtssPrivateAttrModeRemoved));
    *outAttrInfoObject = fAttrArray[actualIndex];
    return QTSS_NoErr;
}

QTSS_Error  QTSSDictionaryMap::GetAttrID(const char* inAttrName, QTSS_AttributeID* outID)
{
    if (outID == NULL)
        return QTSS_BadArgument;

    QTSSAttrInfoDict* theAttrInfo = NULL;
    QTSS_Error theErr = this->GetAttrInfoByName(inAttrName, &theAttrInfo);
    if (theErr == QTSS_NoErr)
        *outID = theAttrInfo->fID;

    return theErr;
}

UInt32  QTSSDictionaryMap::GetMapIndex(QTSS_ObjectType inType)
{
     if (inType < sNextDynamicMap)
        return inType;
     
     switch (inType)
     {
        case qtssRTPStreamObjectType:       return kRTPStreamDictIndex;
        case qtssClientSessionObjectType:   return kClientSessionDictIndex;
        case qtssRTSPSessionObjectType:     return kRTSPSessionDictIndex;
        case qtssRTSPRequestObjectType:     return kRTSPRequestDictIndex;
        case qtssRTSPHeaderObjectType:      return kRTSPHeaderDictIndex;
        case qtssServerObjectType:          return kServerDictIndex;
        case qtssPrefsObjectType:           return kPrefsDictIndex;
        case qtssTextMessagesObjectType:    return kTextMessagesDictIndex;
        case qtssFileObjectType:            return kFileDictIndex;
        case qtssModuleObjectType:          return kModuleDictIndex;
        case qtssModulePrefsObjectType:     return kModulePrefsDictIndex;
        case qtssAttrInfoObjectType:        return kAttrInfoDictIndex;
        case qtssUserProfileObjectType:     return kQTSSUserProfileDictIndex;
        case qtssConnectedUserObjectType:   return kQTSSConnectedUserDictIndex;
        default:                            return kIllegalDictionary;
     }
     return kIllegalDictionary;
}

QTSS_ObjectType QTSSDictionaryMap::CreateNewMap()
{
    if (sNextDynamicMap == kNumDictionaries + kNumDynamicDictionaryTypes)
        return 0;
        
    sDictionaryMaps[sNextDynamicMap] = new QTSSDictionaryMap(0);
    QTSS_ObjectType result = (QTSS_ObjectType)sNextDynamicMap;
    sNextDynamicMap++;
    
    return result;
}
