// May Trigger GC if get is false, str, if not NULL, needs to be rooted prior to calling Add()
HRESULT CLR_RT_HeapBlock_XmlNameTable::Add( LPCSTR key, CLR_UINT32 length, CLR_RT_HeapBlock_String*& str, bool get )
{
    TINYCLR_HEADER();

    CLR_RT_HeapBlock_XmlNameTable_Entry* entry;
    CLR_RT_HeapBlock_String*             match;

    CLR_INT32  hashCode;
    CLR_UINT32 i;

    if(length == 0)
    {
        // if length is 0, return String.Empty
        str = CLR_RT_HeapBlock_String::GetStringEmpty();
        TINYCLR_SET_AND_LEAVE(S_OK);
    }

    // Calculating the hash code
    hashCode = length + GetRandomizer();

    for(i = 0; i < length; i++)
    {
        hashCode += (hashCode << 7) ^ key[ i ];
    }

    hashCode -= hashCode >> 17;
    hashCode -= hashCode >> 11;
    hashCode -= hashCode >> 5;

    // Retrieve the entry (or entries) that hash to that bucket
    entry = (CLR_RT_HeapBlock_XmlNameTable_Entry*)(((CLR_RT_HeapBlock*)GetEntries()->GetElement( hashCode & GetMask() ))->Dereference());

    // Go through all the entries in the singly linked list to make sure there's no match
    while(entry != NULL)
    {
        if(entry->GetHashCode() == hashCode)
        {
            match = entry->GetStr();
            if((hal_strncmp_s( match->StringText(), key, length ) == 0) && (match->StringText()[ length ] == '\0'))
            {
                // if we find a match, we return the matched string
                str = match;
                TINYCLR_SET_AND_LEAVE(S_OK);
            }
        }

        entry = entry->GetNext();
    }

    if(get)
    {
        // we're only getting, so return null if no string is found
        str = NULL;
        TINYCLR_SET_AND_LEAVE(S_OK);
    }
    else
    {
        // we'll re-use the String object if we were given one, if not, we'll create it here
        if(str == NULL)
        {
            CLR_RT_HeapBlock strHB;
            
            TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance( strHB, key, length ));
            
            str = strHB.DereferenceString();

            // Attach the new string to the managed handle to prevent it from being GC when we allocate the Entry object in AddEntry()
            SetTmp( str );
        }

        TINYCLR_SET_AND_LEAVE(AddEntry( str, hashCode ));
    }

    TINYCLR_NOCLEANUP();
}