git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@458 0109f412-320b-0410-ab79-c3e0c5ffbbe6
1899 lines
41 KiB
C++
1899 lines
41 KiB
C++
//------------------------------------------------------------------------------
|
|
// Desc: Class for managing a name table.
|
|
//
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1992, 1994-2006 Novell, Inc. All Rights Reserved.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of version 2 of the GNU General Public
|
|
// License as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, contact Novell, Inc.
|
|
//
|
|
// To contact Novell about this file by physical or electronic mail,
|
|
// you may find current contact information at www.novell.com
|
|
//
|
|
// $Id: fntable.cpp 3114 2006-01-19 13:22:45 -0700 (Thu, 19 Jan 2006) dsanders $
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "ftksys.h"
|
|
#if 0
|
|
|
|
#define MAX_ELEMENTS_TO_LOAD 0xFFFF
|
|
#define MAX_ATTRIBUTES_TO_LOAD 0xFFFF
|
|
|
|
typedef struct
|
|
{
|
|
FLMUINT uiType;
|
|
FLMUNICODE * puzTagName;
|
|
FLMUINT uiTagNum;
|
|
FLMUINT uiDataType;
|
|
FLMUNICODE * puzNamespace;
|
|
} FLM_TAG_INFO;
|
|
|
|
typedef FLMINT (* TAG_COMPARE_FUNC)(
|
|
FLM_TAG_INFO * pTagInfo1,
|
|
FLM_TAG_INFO * pTagInfo2);
|
|
|
|
FSTATIC FLMINT tagNameCompare(
|
|
const FLMUNICODE * puzName1,
|
|
const char * pszName1,
|
|
const FLMUNICODE * puzName2);
|
|
|
|
FSTATIC FLMINT compareTagTypeAndName(
|
|
FLM_TAG_INFO * pTagInfo1,
|
|
FLM_TAG_INFO * pTagInfo2);
|
|
|
|
FSTATIC FLMINT compareTagTypeAndNum(
|
|
FLM_TAG_INFO * pTagInfo1,
|
|
FLM_TAG_INFO * pTagInfo2);
|
|
|
|
FSTATIC void sortTagTbl(
|
|
FLM_TAG_INFO ** ppTagInfoTbl,
|
|
FLMUINT uiLowerBounds,
|
|
FLMUINT uiUpperBounds,
|
|
TAG_COMPARE_FUNC fnTagCompare);
|
|
|
|
/****************************************************************************
|
|
Desc: Class for name/number lookup.
|
|
****************************************************************************/
|
|
class F_NameTable : public IF_NameTable
|
|
{
|
|
public:
|
|
|
|
F_NameTable();
|
|
|
|
virtual ~F_NameTable();
|
|
|
|
void FLMAPI clearTable(
|
|
FLMUINT uiPoolBlkSize);
|
|
|
|
RCODE FLMAPI getNextTagTypeAndNumOrder(
|
|
FLMUINT uiType,
|
|
FLMUINT * puiNextPos,
|
|
FLMUNICODE * puzTagName = NULL,
|
|
char * pszTagName = NULL,
|
|
FLMUINT uiNameBufSize = 0,
|
|
FLMUINT * puiTagNum = NULL,
|
|
FLMUINT * puiDataType = NULL,
|
|
FLMUNICODE * puzNamespace = NULL,
|
|
FLMUINT uiNamespaceBufSize = 0,
|
|
FLMBOOL bTruncatedNamesOk = TRUE);
|
|
|
|
RCODE FLMAPI getNextTagTypeAndNameOrder(
|
|
FLMUINT uiType,
|
|
FLMUINT * puiNextPos,
|
|
FLMUNICODE * puzTagName = NULL,
|
|
char * pszTagName = NULL,
|
|
FLMUINT uiNameBufSize = 0,
|
|
FLMUINT * puiTagNum = NULL,
|
|
FLMUINT * puiDataType = NULL,
|
|
FLMUNICODE * puzNamespace = NULL,
|
|
FLMUINT uiNamespaceBufSize = 0,
|
|
FLMBOOL bTruncatedNamesOk = TRUE);
|
|
|
|
RCODE FLMAPI getFromTagTypeAndName(
|
|
FLMUINT uiType,
|
|
const FLMUNICODE * puzTagName,
|
|
const char * pszTagName,
|
|
FLMBOOL bMatchNamespace,
|
|
const FLMUNICODE * puzNamespace = NULL,
|
|
FLMUINT * puiTagNum = NULL,
|
|
FLMUINT * puiDataType = NULL);
|
|
|
|
RCODE FLMAPI getFromTagTypeAndNum(
|
|
FLMUINT uiType,
|
|
FLMUINT uiTagNum,
|
|
FLMUNICODE * puzTagName = NULL,
|
|
char * pszTagName = NULL,
|
|
FLMUINT * puiNameBufSize = NULL,
|
|
FLMUINT * puiDataType = NULL,
|
|
FLMUNICODE * puzNamespace = NULL,
|
|
char * pszNamespace = NULL,
|
|
FLMUINT * puiNamespaceBufSize = NULL,
|
|
FLMBOOL bTruncatedNamesOk = TRUE);
|
|
|
|
RCODE FLMAPI addTag(
|
|
FLMUINT uiType,
|
|
FLMUNICODE * puzTagName,
|
|
const char * pszTagName,
|
|
FLMUINT uiTagNum,
|
|
FLMUINT uiDataType = 0,
|
|
FLMUNICODE * puzNamespace = NULL,
|
|
FLMBOOL bCheckDuplicates = TRUE);
|
|
|
|
void FLMAPI removeTag(
|
|
FLMUINT uiType,
|
|
FLMUINT uiTagNum);
|
|
|
|
RCODE FLMAPI cloneNameTable(
|
|
IF_NameTable ** ppNewNameTable);
|
|
|
|
FLMINT FLMAPI AddRef( void);
|
|
|
|
FLMINT FLMAPI Release( void);
|
|
|
|
private:
|
|
|
|
void sortTags( void);
|
|
|
|
RCODE allocTag(
|
|
FLMUINT uiType,
|
|
FLMUNICODE * puzTagName,
|
|
const char * pszTagName,
|
|
FLMUINT uiTagNum,
|
|
FLMUINT uiDataType,
|
|
FLMUNICODE * puzNamespace,
|
|
FLM_TAG_INFO ** ppTagInfo);
|
|
|
|
RCODE reallocSortTables(
|
|
FLMUINT uiNewTblSize);
|
|
|
|
RCODE copyTagName(
|
|
FLMUNICODE * puzDestTagName,
|
|
char * pszDestTagName,
|
|
FLMUINT * puiDestBufSize,
|
|
FLMUNICODE * puzSrcTagName,
|
|
FLMBOOL bTruncatedNamesOk);
|
|
|
|
FLM_TAG_INFO * findTagByTypeAndNum(
|
|
FLMUINT uiType,
|
|
FLMUINT uiTagNum,
|
|
FLMUINT * puiInsertPos = NULL);
|
|
|
|
FLM_TAG_INFO * findTagByTypeAndName(
|
|
FLMUINT uiType,
|
|
const FLMUNICODE * puzTagName,
|
|
const char * pszTagName,
|
|
FLMBOOL bMatchNamespace,
|
|
const FLMUNICODE * puzNamespace,
|
|
FLMBOOL * pbAmbiguous,
|
|
FLMUINT * puiInsertPos = NULL);
|
|
|
|
RCODE insertTagInTables(
|
|
FLM_TAG_INFO * pTagInfo,
|
|
FLMUINT uiTagTypeAndNameTblInsertPos,
|
|
FLMUINT uiTagTypeAndNumTblInsertPos);
|
|
|
|
FLMUNICODE * findNamespace(
|
|
FLMUNICODE * puzNamespace,
|
|
FLMUINT * puiInsertPos);
|
|
|
|
RCODE insertNamespace(
|
|
FLMUNICODE * puzNamespace,
|
|
FLMUINT uiInsertPos);
|
|
|
|
F_Pool m_pool;
|
|
FLMUINT m_uiMemoryAllocated;
|
|
FLM_TAG_INFO ** m_ppSortedByTagTypeAndName;
|
|
FLM_TAG_INFO ** m_ppSortedByTagTypeAndNum;
|
|
FLMUINT m_uiTblSize;
|
|
FLMUINT m_uiNumTags;
|
|
FLMBOOL m_bTablesSorted;
|
|
FLMUNICODE ** m_ppuzNamespaces;
|
|
FLMUINT m_uiNamespaceTblSize;
|
|
FLMUINT m_uiNumNamespaces;
|
|
F_MUTEX m_hRefMutex;
|
|
};
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
F_NameTable::F_NameTable()
|
|
{
|
|
m_pool.poolInit( 1024);
|
|
m_uiMemoryAllocated = 0;
|
|
m_ppSortedByTagTypeAndName = NULL;
|
|
m_ppSortedByTagTypeAndNum = NULL;
|
|
m_uiTblSize = 0;
|
|
m_uiNumTags = 0;
|
|
m_bTablesSorted = FALSE;
|
|
m_ppuzNamespaces = NULL;
|
|
m_uiNamespaceTblSize = 0;
|
|
m_uiNumNamespaces = 0;
|
|
m_hRefMutex = F_MUTEX_NULL;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
F_NameTable::~F_NameTable()
|
|
{
|
|
clearTable( 0);
|
|
if( m_hRefMutex)
|
|
{
|
|
f_mutexDestroy( &m_hRefMutex);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Free everything in the table
|
|
****************************************************************************/
|
|
void FLMAPI F_NameTable::clearTable(
|
|
FLMUINT uiPoolBlkSize)
|
|
{
|
|
m_pool.poolFree();
|
|
|
|
if (uiPoolBlkSize)
|
|
{
|
|
m_pool.poolInit( uiPoolBlkSize);
|
|
}
|
|
|
|
m_uiMemoryAllocated = 0;
|
|
|
|
// NOTE: Only one allocation is used for m_ppSortedByTagTypeAndName and
|
|
// m_ppSortedByTagTypeAndNum - there is no
|
|
// need to free m_ppSortedByTagTypeAndNum
|
|
|
|
if (m_ppSortedByTagTypeAndName)
|
|
{
|
|
f_free( &m_ppSortedByTagTypeAndName);
|
|
m_ppSortedByTagTypeAndNum = NULL;
|
|
m_uiTblSize = 0;
|
|
m_uiNumTags = 0;
|
|
}
|
|
|
|
if (m_ppuzNamespaces)
|
|
{
|
|
f_free( &m_ppuzNamespaces);
|
|
m_ppuzNamespaces = NULL;
|
|
m_uiNamespaceTblSize = 0;
|
|
m_uiNumNamespaces = 0;
|
|
}
|
|
|
|
m_bTablesSorted = FALSE;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Compare two tag names. Name1 can be NATIVE or UNICODE. If a non-NULL
|
|
UNICODE string is passed, it will be used. Otherwise, the NATIVE
|
|
string will be used.
|
|
Note: Comparison is case sensitive. Either or both names may be NULL.
|
|
Empty strings and NULL pointers are considered to be equal.
|
|
****************************************************************************/
|
|
FSTATIC FLMINT tagNameCompare(
|
|
const FLMUNICODE * puzName1, // If NULL, use pszName1 for comparison
|
|
const char * pszName1,
|
|
const FLMUNICODE * puzName2)
|
|
{
|
|
FLMUNICODE uzChar1;
|
|
FLMUNICODE uzChar2;
|
|
FLMUNICODE uzLowerChar1;
|
|
FLMUNICODE uzLowerChar2;
|
|
|
|
if (puzName1)
|
|
{
|
|
if (!puzName2)
|
|
{
|
|
if (*puzName1)
|
|
{
|
|
return( 1);
|
|
}
|
|
else
|
|
{
|
|
return( 0);
|
|
}
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
uzChar1 = *puzName1;
|
|
uzChar2 = *puzName2;
|
|
|
|
if (!uzChar1)
|
|
{
|
|
if (!uzChar2)
|
|
{
|
|
return( 0);
|
|
}
|
|
else
|
|
{
|
|
return( -1);
|
|
}
|
|
}
|
|
else if (!uzChar2)
|
|
{
|
|
return( 1);
|
|
}
|
|
else if (uzChar1 != uzChar2)
|
|
{
|
|
Test_Case:
|
|
uzLowerChar1 = f_unitolower( uzChar1);
|
|
uzLowerChar2 = f_unitolower( uzChar2);
|
|
|
|
if (uzLowerChar1 < uzLowerChar2)
|
|
{
|
|
return( -1);
|
|
}
|
|
else if (uzLowerChar1 > uzLowerChar2)
|
|
{
|
|
return( 1);
|
|
}
|
|
else if (uzLowerChar1 != uzChar1)
|
|
{
|
|
|
|
// Char1 is uppercase, char2 is lowercase
|
|
// Uppercase sorts before lowercase
|
|
|
|
return( -1);
|
|
}
|
|
else
|
|
{
|
|
|
|
// Char1 is lowercase, char2 is uppercase
|
|
// Lowercase sorts after uppercase
|
|
|
|
return( 1);
|
|
}
|
|
}
|
|
puzName1++;
|
|
puzName2++;
|
|
}
|
|
}
|
|
else if (pszName1)
|
|
{
|
|
if (!puzName2)
|
|
{
|
|
if (*pszName1)
|
|
{
|
|
return( 1);
|
|
}
|
|
else
|
|
{
|
|
return( 0);
|
|
}
|
|
}
|
|
for (;;)
|
|
{
|
|
uzChar1 = (FLMUNICODE)*pszName1;
|
|
uzChar2 = *puzName2;
|
|
if (!uzChar1)
|
|
{
|
|
if (!uzChar2)
|
|
{
|
|
return( 0);
|
|
}
|
|
else
|
|
{
|
|
return( -1);
|
|
}
|
|
}
|
|
else if (!uzChar2)
|
|
{
|
|
return( 1);
|
|
}
|
|
else if (uzChar1 != uzChar2)
|
|
{
|
|
goto Test_Case;
|
|
}
|
|
pszName1++;
|
|
puzName2++;
|
|
}
|
|
}
|
|
else if (puzName2)
|
|
{
|
|
|
|
// Both name1's are NULL.
|
|
|
|
if (*puzName2)
|
|
{
|
|
return( -1);
|
|
}
|
|
else
|
|
{
|
|
return( 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// Both name1 and name2 are NULL.
|
|
|
|
return( 0);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Lookup a tag by type and tag number.
|
|
****************************************************************************/
|
|
FLM_TAG_INFO * F_NameTable::findTagByTypeAndNum(
|
|
FLMUINT uiType,
|
|
FLMUINT uiTagNum,
|
|
FLMUINT * puiInsertPos)
|
|
{
|
|
FLM_TAG_INFO * pTagInfo = NULL;
|
|
FLMUINT uiTblSize;
|
|
FLMUINT uiLow;
|
|
FLMUINT uiMid;
|
|
FLMUINT uiHigh;
|
|
FLMUINT uiTblTagNum;
|
|
FLMUINT uiTblType;
|
|
|
|
if (!m_bTablesSorted)
|
|
{
|
|
sortTags();
|
|
}
|
|
|
|
// Do binary search in the table
|
|
|
|
if ((uiTblSize = m_uiNumTags) == 0)
|
|
{
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
uiHigh = --uiTblSize;
|
|
uiLow = 0;
|
|
for (;;)
|
|
{
|
|
uiMid = (uiLow + uiHigh) / 2;
|
|
|
|
uiTblType = m_ppSortedByTagTypeAndNum [uiMid]->uiType;
|
|
uiTblTagNum = m_ppSortedByTagTypeAndNum [uiMid]->uiTagNum;
|
|
if (uiTblType == uiType && uiTagNum == uiTblTagNum)
|
|
{
|
|
|
|
// Found Match
|
|
|
|
pTagInfo = m_ppSortedByTagTypeAndNum [uiMid];
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = uiMid;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
// Check if we are done
|
|
|
|
if (uiLow >= uiHigh)
|
|
{
|
|
|
|
// Done, item not found
|
|
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = (uiType < uiTblType ||
|
|
(uiType == uiTblType && uiTagNum < uiTblTagNum))
|
|
? uiMid
|
|
: uiMid + 1;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if (uiType < uiTblType ||
|
|
(uiType == uiTblType && uiTagNum < uiTblTagNum))
|
|
{
|
|
if (uiMid == 0)
|
|
{
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
uiHigh = uiMid - 1;
|
|
}
|
|
else
|
|
{
|
|
if (uiMid == uiTblSize)
|
|
{
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = uiMid + 1;
|
|
}
|
|
goto Exit;
|
|
}
|
|
uiLow = uiMid + 1;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( pTagInfo);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Lookup a tag by tag type and tag name. Tag name is passed in as a
|
|
UNICODE string or a NATIVE string. If a non-NULL UNICODE string is
|
|
passed in, it will be used. Otherwise, the NATIVE string will be used.
|
|
****************************************************************************/
|
|
FLM_TAG_INFO * F_NameTable::findTagByTypeAndName(
|
|
FLMUINT uiType,
|
|
const FLMUNICODE * puzTagName,
|
|
const char * pszTagName,
|
|
FLMBOOL bMatchNamespace,
|
|
const FLMUNICODE * puzNamespace,
|
|
FLMBOOL * pbAmbiguous,
|
|
FLMUINT * puiInsertPos)
|
|
{
|
|
FLM_TAG_INFO * pTagInfo = NULL;
|
|
FLMUINT uiTblType;
|
|
FLMUINT uiTblSize;
|
|
FLMUINT uiLow;
|
|
FLMUINT uiMid;
|
|
FLMUINT uiHigh;
|
|
FLMINT iCmp;
|
|
|
|
if (!m_bTablesSorted)
|
|
{
|
|
sortTags();
|
|
}
|
|
|
|
// Do binary search in the table
|
|
|
|
*pbAmbiguous = FALSE;
|
|
if ((uiTblSize = m_uiNumTags) == 0)
|
|
{
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
uiHigh = --uiTblSize;
|
|
uiLow = 0;
|
|
for (;;)
|
|
{
|
|
uiMid = (uiLow + uiHigh) / 2;
|
|
uiTblType = m_ppSortedByTagTypeAndName [uiMid]->uiType;
|
|
if (uiType < uiTblType)
|
|
{
|
|
iCmp = -1;
|
|
}
|
|
else if (uiType > uiTblType)
|
|
{
|
|
iCmp = 1;
|
|
}
|
|
else if ((iCmp = tagNameCompare( puzTagName, pszTagName,
|
|
m_ppSortedByTagTypeAndName [uiMid]->puzTagName)) == 0)
|
|
{
|
|
if (!bMatchNamespace)
|
|
{
|
|
|
|
// Better not be trying to insert a new one in this case!
|
|
|
|
f_assert( puiInsertPos == NULL);
|
|
|
|
if ((uiMid &&
|
|
tagNameCompare( puzTagName, pszTagName,
|
|
m_ppSortedByTagTypeAndName [uiMid-1]->puzTagName) == 0) ||
|
|
(uiMid < m_uiNumTags - 1 &&
|
|
tagNameCompare( puzTagName, pszTagName,
|
|
m_ppSortedByTagTypeAndName [uiMid+1]->puzTagName) == 0))
|
|
{
|
|
*pbAmbiguous = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
iCmp = tagNameCompare( puzNamespace, NULL,
|
|
m_ppSortedByTagTypeAndName [uiMid]->puzNamespace);
|
|
}
|
|
|
|
if (iCmp == 0)
|
|
{
|
|
// Found Match
|
|
|
|
pTagInfo = m_ppSortedByTagTypeAndName [uiMid];
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = uiMid;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Check if we are done
|
|
|
|
if (uiLow >= uiHigh)
|
|
{
|
|
|
|
// Done, item not found
|
|
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = (iCmp < 0)
|
|
? uiMid
|
|
: uiMid + 1;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if (iCmp < 0)
|
|
{
|
|
if (uiMid == 0)
|
|
{
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
uiHigh = uiMid - 1;
|
|
}
|
|
else
|
|
{
|
|
if (uiMid == uiTblSize)
|
|
{
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = uiMid + 1;
|
|
}
|
|
goto Exit;
|
|
}
|
|
uiLow = uiMid + 1;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( pTagInfo);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Copy a tag name to a UNICODE or NATIVE buffer. Truncate if necessary.
|
|
If a non-NULL UNICODE string is passed in, it will be populated.
|
|
Otherwise, the NATIVE string will be populated.
|
|
****************************************************************************/
|
|
RCODE F_NameTable::copyTagName(
|
|
FLMUNICODE * puzDestTagName,
|
|
char * pszDestTagName,
|
|
FLMUINT * puiDestBufSize, // Bytes, must be enough for null terminator
|
|
FLMUNICODE * puzSrcTagName, // May be NULL
|
|
FLMBOOL bTruncatedNamesOk)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLMUINT uiDestCharCnt = *puiDestBufSize;
|
|
FLMUINT uiCharCnt;
|
|
|
|
if (puzDestTagName)
|
|
{
|
|
|
|
// Decrement name buffer size by sizeof( FLMUNICODE) to allow for a
|
|
// terminating NULL character. uiDestChars better be at least big
|
|
// enough for a null terminating character.
|
|
|
|
f_assert( uiDestCharCnt >= sizeof( FLMUNICODE));
|
|
uiDestCharCnt /= sizeof( FLMUNICODE);
|
|
uiDestCharCnt--;
|
|
|
|
if (puzSrcTagName)
|
|
{
|
|
|
|
// Copy the name to the UNICODE buffer.
|
|
|
|
uiCharCnt = 0;
|
|
while (uiCharCnt < uiDestCharCnt && *puzSrcTagName)
|
|
{
|
|
*puzDestTagName++ = *puzSrcTagName;
|
|
uiCharCnt++;
|
|
puzSrcTagName++;
|
|
}
|
|
*puzDestTagName = 0;
|
|
*puiDestBufSize = uiCharCnt;
|
|
if (!bTruncatedNamesOk && *puzSrcTagName)
|
|
{
|
|
rc = RC_SET( NE_FLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*puzDestTagName = 0;
|
|
*puiDestBufSize = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// Decrement name buffer size by one to allow for a terminating
|
|
// 0 character. uiDestCharCnt better be at list big
|
|
// enough for a 0 terminating character.
|
|
|
|
f_assert( uiDestCharCnt);
|
|
uiDestCharCnt--;
|
|
|
|
if (puzSrcTagName)
|
|
{
|
|
// Copy the name to the NATIVE buffer. Non-Ascii UNICODE characters
|
|
// will cause NE_FLM_CONV_ILLEGAL to be returned.
|
|
|
|
uiCharCnt = 0;
|
|
while (uiCharCnt < uiDestCharCnt && *puzSrcTagName)
|
|
{
|
|
if (*puzSrcTagName <= 0xFF)
|
|
{
|
|
*pszDestTagName++ =
|
|
(char)f_tonative( (FLMBYTE)*puzSrcTagName);
|
|
uiCharCnt++;
|
|
puzSrcTagName++;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( NE_FLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
|
|
}
|
|
*pszDestTagName = 0;
|
|
*puiDestBufSize = uiCharCnt;
|
|
if (!bTruncatedNamesOk && *puzSrcTagName)
|
|
{
|
|
rc = RC_SET( NE_FLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pszDestTagName = 0;
|
|
*puiDestBufSize = 0;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Swap two entries in tag info table during sort.
|
|
*****************************************************************************/
|
|
FINLINE void tagInfoSwap(
|
|
FLM_TAG_INFO * * ppTagInfoTbl,
|
|
FLMUINT uiPos1,
|
|
FLMUINT uiPos2
|
|
)
|
|
{
|
|
FLM_TAG_INFO * pTmpTagInfo = ppTagInfoTbl [uiPos1];
|
|
ppTagInfoTbl [uiPos1] = ppTagInfoTbl [uiPos2];
|
|
ppTagInfoTbl [uiPos2] = pTmpTagInfo;
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Comparison function for sorting by tag type and name.
|
|
****************************************************************************/
|
|
FSTATIC FLMINT compareTagTypeAndName(
|
|
FLM_TAG_INFO * pTagInfo1,
|
|
FLM_TAG_INFO * pTagInfo2)
|
|
{
|
|
FLMINT iCmp;
|
|
|
|
if (pTagInfo1->uiType < pTagInfo2->uiType)
|
|
{
|
|
return( -1);
|
|
}
|
|
else if (pTagInfo1->uiType > pTagInfo2->uiType)
|
|
{
|
|
return( 1);
|
|
}
|
|
else if ((iCmp = tagNameCompare( pTagInfo1->puzTagName, NULL,
|
|
pTagInfo2->puzTagName)) != 0)
|
|
{
|
|
return( iCmp);
|
|
}
|
|
else
|
|
{
|
|
return( tagNameCompare( pTagInfo1->puzNamespace, NULL,
|
|
pTagInfo2->puzNamespace));
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Comparison function for sorting by tag type and number.
|
|
****************************************************************************/
|
|
FSTATIC FLMINT compareTagTypeAndNum(
|
|
FLM_TAG_INFO * pTagInfo1,
|
|
FLM_TAG_INFO * pTagInfo2
|
|
)
|
|
{
|
|
if (pTagInfo1->uiType < pTagInfo2->uiType)
|
|
{
|
|
return( -1);
|
|
}
|
|
else if (pTagInfo1->uiType > pTagInfo2->uiType)
|
|
{
|
|
return( 1);
|
|
}
|
|
else if (pTagInfo1->uiTagNum < pTagInfo2->uiTagNum)
|
|
{
|
|
return( -1);
|
|
}
|
|
else if (pTagInfo1->uiTagNum > pTagInfo2->uiTagNum)
|
|
{
|
|
return( 1);
|
|
}
|
|
else
|
|
{
|
|
return( 0);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Sort an array of SCACHE pointers by their block address.
|
|
****************************************************************************/
|
|
FSTATIC void sortTagTbl(
|
|
FLM_TAG_INFO * * ppTagInfoTbl,
|
|
FLMUINT uiLowerBounds,
|
|
FLMUINT uiUpperBounds,
|
|
TAG_COMPARE_FUNC fnTagCompare)
|
|
{
|
|
FLMUINT uiLBPos;
|
|
FLMUINT uiUBPos;
|
|
FLMUINT uiMIDPos;
|
|
FLMUINT uiLeftItems;
|
|
FLMUINT uiRightItems;
|
|
FLM_TAG_INFO * pCurTagInfo;
|
|
FLMINT iCompare;
|
|
|
|
Iterate_Larger_Half:
|
|
|
|
uiUBPos = uiUpperBounds;
|
|
uiLBPos = uiLowerBounds;
|
|
uiMIDPos = (uiUpperBounds + uiLowerBounds + 1) / 2;
|
|
pCurTagInfo = ppTagInfoTbl [uiMIDPos ];
|
|
for (;;)
|
|
{
|
|
while (uiLBPos == uiMIDPos || // Don't compare with target
|
|
((iCompare =
|
|
fnTagCompare( ppTagInfoTbl [uiLBPos], pCurTagInfo)) < 0))
|
|
{
|
|
if (uiLBPos >= uiUpperBounds)
|
|
{
|
|
break;
|
|
}
|
|
uiLBPos++;
|
|
}
|
|
|
|
while (uiUBPos == uiMIDPos || // Don't compare with target
|
|
(((iCompare =
|
|
fnTagCompare( pCurTagInfo, ppTagInfoTbl [uiUBPos])) < 0)))
|
|
{
|
|
if (!uiUBPos)
|
|
{
|
|
break;
|
|
}
|
|
uiUBPos--;
|
|
}
|
|
|
|
if (uiLBPos < uiUBPos ) // Interchange and continue loop.
|
|
{
|
|
|
|
// Exchange [uiLBPos] with [uiUBPos].
|
|
|
|
tagInfoSwap( ppTagInfoTbl, uiLBPos, uiUBPos);
|
|
uiLBPos++; // Scan from left to right.
|
|
uiUBPos--; // Scan from right to left.
|
|
}
|
|
else // Past each other - done
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check for swap( LB, MID ) - cases 3 and 4
|
|
|
|
if( uiLBPos < uiMIDPos )
|
|
{
|
|
|
|
// Exchange [uiLBPos] with [uiMIDPos]
|
|
|
|
tagInfoSwap( ppTagInfoTbl, uiMIDPos, uiLBPos);
|
|
uiMIDPos = uiLBPos;
|
|
}
|
|
else if( uiMIDPos < uiUBPos )
|
|
{
|
|
|
|
// Exchange [uUBPos] with [uiMIDPos]
|
|
|
|
tagInfoSwap( ppTagInfoTbl, uiMIDPos, uiUBPos);
|
|
uiMIDPos = uiUBPos;
|
|
}
|
|
|
|
// Check the left piece.
|
|
|
|
uiLeftItems = (uiLowerBounds + 1 < uiMIDPos )
|
|
? uiMIDPos - uiLowerBounds // 2 or more
|
|
: 0;
|
|
uiRightItems = (uiMIDPos + 1 < uiUpperBounds )
|
|
? uiUpperBounds - uiMIDPos // 2 or more
|
|
: 0;
|
|
|
|
if( uiLeftItems < uiRightItems )
|
|
{
|
|
|
|
// Recurse on the LEFT side and goto the top on the RIGHT side.
|
|
|
|
if (uiLeftItems )
|
|
{
|
|
sortTagTbl( ppTagInfoTbl, uiLowerBounds, uiMIDPos - 1, fnTagCompare);
|
|
}
|
|
uiLowerBounds = uiMIDPos + 1;
|
|
goto Iterate_Larger_Half;
|
|
}
|
|
else if (uiLeftItems ) // Compute a truth table to figure out this check.
|
|
{
|
|
|
|
// Recurse on the RIGHT side and goto the top for the LEFT side.
|
|
|
|
if (uiRightItems )
|
|
{
|
|
sortTagTbl( ppTagInfoTbl, uiMIDPos + 1, uiUpperBounds, fnTagCompare);
|
|
}
|
|
uiUpperBounds = uiMIDPos - 1;
|
|
goto Iterate_Larger_Half;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Lookup a namespace - so we can reuse the memory.
|
|
****************************************************************************/
|
|
FLMUNICODE * F_NameTable::findNamespace(
|
|
FLMUNICODE * puzNamespace,
|
|
FLMUINT * puiInsertPos)
|
|
{
|
|
FLMUNICODE * puzFoundNamespace = NULL;
|
|
FLMUINT uiTblSize;
|
|
FLMUINT uiLow;
|
|
FLMUINT uiMid;
|
|
FLMUINT uiHigh;
|
|
FLMINT iCmp;
|
|
|
|
// Do binary search in the table
|
|
|
|
if ((uiTblSize = m_uiNumNamespaces) == 0)
|
|
{
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
uiHigh = --uiTblSize;
|
|
uiLow = 0;
|
|
for (;;)
|
|
{
|
|
uiMid = (uiLow + uiHigh) / 2;
|
|
|
|
if ((iCmp = tagNameCompare( puzNamespace, NULL,
|
|
m_ppuzNamespaces [uiMid])) == 0)
|
|
{
|
|
|
|
// Found Match
|
|
|
|
puzFoundNamespace = m_ppuzNamespaces [uiMid];
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = uiMid;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
// Check if we are done
|
|
|
|
if (uiLow >= uiHigh)
|
|
{
|
|
|
|
// Done, item not found
|
|
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = (iCmp < 0)
|
|
? uiMid
|
|
: uiMid + 1;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if (iCmp < 0)
|
|
{
|
|
if (uiMid == 0)
|
|
{
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
uiHigh = uiMid - 1;
|
|
}
|
|
else
|
|
{
|
|
if (uiMid == uiTblSize)
|
|
{
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = uiMid + 1;
|
|
}
|
|
goto Exit;
|
|
}
|
|
uiLow = uiMid + 1;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( puzFoundNamespace);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Insert a tag info structure into the sorted tables at the specified
|
|
positions.
|
|
****************************************************************************/
|
|
RCODE F_NameTable::insertNamespace(
|
|
FLMUNICODE * puzNamespace,
|
|
FLMUINT uiInsertPos)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLMUINT uiLoop;
|
|
|
|
// See if we need to resize the table. Add 32 each time. There
|
|
// should not be that many different namespaces.
|
|
|
|
if (m_uiNumNamespaces == m_uiNamespaceTblSize)
|
|
{
|
|
FLMUINT uiNewSize = m_uiNamespaceTblSize + 32;
|
|
FLMUNICODE ** ppNewTbl;
|
|
|
|
if( RC_BAD( rc = f_alloc( sizeof( FLMUNICODE *) * uiNewSize, &ppNewTbl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Copy the old tables into the new.
|
|
|
|
if (m_uiNumNamespaces)
|
|
{
|
|
f_memcpy( ppNewTbl, m_ppuzNamespaces,
|
|
sizeof( FLMUNICODE *) * m_uiNumNamespaces);
|
|
f_free( &m_ppuzNamespaces);
|
|
}
|
|
m_ppuzNamespaces = ppNewTbl;
|
|
m_uiNamespaceTblSize = uiNewSize;
|
|
}
|
|
|
|
// Insert the new namespace into the table.
|
|
|
|
uiLoop = m_uiNumNamespaces;
|
|
while (uiLoop > uiInsertPos)
|
|
{
|
|
m_ppuzNamespaces [uiLoop] = m_ppuzNamespaces [uiLoop - 1];
|
|
uiLoop--;
|
|
}
|
|
m_ppuzNamespaces [uiInsertPos] = puzNamespace;
|
|
|
|
// Increment the total number of namespaces
|
|
|
|
m_uiNumNamespaces++;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Allocate a new tag info structure and set it up.
|
|
****************************************************************************/
|
|
RCODE F_NameTable::allocTag(
|
|
FLMUINT uiType,
|
|
FLMUNICODE * puzTagName,
|
|
const char * pszTagName,
|
|
FLMUINT uiTagNum,
|
|
FLMUINT uiDataType,
|
|
FLMUNICODE * puzNamespace,
|
|
FLM_TAG_INFO ** ppTagInfo)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
void * pvMark;
|
|
FLMUINT uiSaveMemoryAllocated;
|
|
FLM_TAG_INFO * pTagInfo;
|
|
FLMUINT uiNameSize;
|
|
FLMUNICODE * puzTmp;
|
|
FLMUNICODE * puzTblNamespace;
|
|
FLMUINT uiNamespaceInsertPos;
|
|
|
|
// Create a new tag info structure.
|
|
|
|
pvMark = m_pool.poolMark();
|
|
uiSaveMemoryAllocated = m_uiMemoryAllocated;
|
|
if (RC_BAD( rc = m_pool.poolCalloc( sizeof( FLM_TAG_INFO),
|
|
(void **)&pTagInfo)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
m_uiMemoryAllocated += sizeof( FLM_TAG_INFO);
|
|
|
|
// Allocate the space for the tag name.
|
|
|
|
if (puzTagName)
|
|
{
|
|
uiNameSize = (f_unilen( puzTagName) + 1) * sizeof( FLMUNICODE);
|
|
if (RC_BAD( rc = m_pool.poolAlloc( uiNameSize,
|
|
(void **)&pTagInfo->puzTagName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
m_uiMemoryAllocated += uiNameSize;
|
|
f_memcpy( pTagInfo->puzTagName, puzTagName, uiNameSize);
|
|
}
|
|
else
|
|
{
|
|
uiNameSize = (f_strlen( pszTagName) + 1) * sizeof( FLMUNICODE);
|
|
if (RC_BAD( rc = m_pool.poolAlloc( uiNameSize,
|
|
(void **)&pTagInfo->puzTagName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
m_uiMemoryAllocated += uiNameSize;
|
|
puzTmp = pTagInfo->puzTagName;
|
|
while (*pszTagName)
|
|
{
|
|
*puzTmp++ = (FLMUNICODE)*pszTagName;
|
|
pszTagName++;
|
|
}
|
|
*puzTmp = 0;
|
|
}
|
|
pTagInfo->uiType = uiType;
|
|
pTagInfo->uiTagNum = uiTagNum;
|
|
pTagInfo->uiDataType = uiDataType;
|
|
|
|
if (puzNamespace && *puzNamespace)
|
|
{
|
|
|
|
// See if we have already allocated the namespace. If so, just
|
|
// point to it. Otherwise, allocate it and add it to the
|
|
// namespace table and then point to it.
|
|
|
|
if ((puzTblNamespace = findNamespace( puzNamespace,
|
|
&uiNamespaceInsertPos)) == NULL)
|
|
{
|
|
uiNameSize = (f_unilen( puzNamespace) + 1) * sizeof( FLMUNICODE);
|
|
if (RC_BAD( rc = m_pool.poolAlloc( uiNameSize,
|
|
(void **)&puzTblNamespace)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
m_uiMemoryAllocated += uiNameSize;
|
|
f_memcpy( puzTblNamespace, puzNamespace, uiNameSize);
|
|
if (RC_BAD( rc = insertNamespace( puzTblNamespace,
|
|
uiNamespaceInsertPos)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Need to re-mark the pool after this point, because
|
|
// we can now not afford to lose the namespace that was
|
|
// allocated if the pool is reset at Exit due to a later
|
|
// error.
|
|
|
|
pvMark = m_pool.poolMark();
|
|
uiSaveMemoryAllocated = m_uiMemoryAllocated;
|
|
}
|
|
|
|
pTagInfo->puzNamespace = puzTblNamespace;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (RC_BAD( rc))
|
|
{
|
|
m_pool.poolReset( pvMark);
|
|
m_uiMemoryAllocated = uiSaveMemoryAllocated;
|
|
pTagInfo = NULL;
|
|
}
|
|
*ppTagInfo = pTagInfo;
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Allocate the sort tables.
|
|
****************************************************************************/
|
|
RCODE F_NameTable::reallocSortTables(
|
|
FLMUINT uiNewTblSize)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLM_TAG_INFO ** ppNewTbl;
|
|
|
|
if( RC_BAD( f_alloc(
|
|
sizeof( FLM_TAG_INFO *) * uiNewTblSize * 2, &ppNewTbl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Copy the old tables into the new.
|
|
|
|
if (m_uiNumTags)
|
|
{
|
|
f_memcpy( ppNewTbl, m_ppSortedByTagTypeAndName,
|
|
sizeof( FLM_TAG_INFO *) * m_uiNumTags);
|
|
f_memcpy( &ppNewTbl [uiNewTblSize],
|
|
m_ppSortedByTagTypeAndNum,
|
|
sizeof( FLM_TAG_INFO *) * m_uiNumTags);
|
|
f_free( &m_ppSortedByTagTypeAndName);
|
|
}
|
|
m_ppSortedByTagTypeAndName = ppNewTbl;
|
|
m_ppSortedByTagTypeAndNum = &ppNewTbl [uiNewTblSize];
|
|
|
|
m_uiTblSize = uiNewTblSize;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Get a tag name, number, etc. using type + tag number ordering.
|
|
Tag name is returned as a UNICODE string or NATIVE string. If a
|
|
non-NULL UNICODE string is passed in, it will be used.
|
|
Otherwise, the NATIVE string will be used.
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_NameTable::getNextTagTypeAndNumOrder(
|
|
FLMUINT uiType,
|
|
FLMUINT * puiNextPos,
|
|
FLMUNICODE * puzTagName, // May be NULL
|
|
char * pszTagName, // May be NULL
|
|
FLMUINT uiNameBufSize,
|
|
FLMUINT * puiTagNum, // May be NULL
|
|
FLMUINT * puiDataType, // May be NULL
|
|
FLMUNICODE * puzNamespace, // May be NULL
|
|
FLMUINT uiNamespaceBufSize,
|
|
FLMBOOL bTruncatedNamesOk)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLM_TAG_INFO * pTagInfo = NULL;
|
|
FLMBOOL bFound = FALSE;
|
|
|
|
if (!m_bTablesSorted)
|
|
{
|
|
sortTags();
|
|
}
|
|
|
|
while (*puiNextPos < m_uiNumTags)
|
|
{
|
|
pTagInfo = m_ppSortedByTagTypeAndNum [*puiNextPos];
|
|
if (pTagInfo->uiType == uiType)
|
|
{
|
|
bFound = TRUE;
|
|
if (puiTagNum)
|
|
{
|
|
*puiTagNum = pTagInfo->uiTagNum;
|
|
}
|
|
if( puzTagName || pszTagName)
|
|
{
|
|
if (RC_BAD( rc = copyTagName( puzTagName, pszTagName,
|
|
&uiNameBufSize,
|
|
pTagInfo->puzTagName, bTruncatedNamesOk)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (puiDataType)
|
|
{
|
|
*puiDataType = pTagInfo->uiDataType;
|
|
}
|
|
|
|
if (puzNamespace)
|
|
{
|
|
if (RC_BAD( rc = copyTagName( puzNamespace, NULL,
|
|
&uiNamespaceBufSize,
|
|
pTagInfo->puzNamespace,
|
|
bTruncatedNamesOk)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Returned *puiNextPos should be the next one to retrieve.
|
|
|
|
(*puiNextPos)++;
|
|
break;
|
|
}
|
|
else if (pTagInfo->uiType > uiType)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
(*puiNextPos)++;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
rc = RC_SET( NE_FLM_EOF_HIT);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Get a tag name, number, etc. using type + tag name ordering.
|
|
Tag name is returned as a UNICODE string or NATIVE string. If a
|
|
non-NULL UNICODE string is passed in, it will be used.
|
|
Otherwise, the NATIVE string will be used.
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_NameTable::getNextTagTypeAndNameOrder(
|
|
FLMUINT uiType,
|
|
FLMUINT * puiNextPos,
|
|
FLMUNICODE * puzTagName, // May be NULL
|
|
char * pszTagName, // May be NULL
|
|
FLMUINT uiNameBufSize,
|
|
FLMUINT * puiTagNum, // May be NULL
|
|
FLMUINT * puiDataType, // May be NULL
|
|
FLMUNICODE * puzNamespace, // May be NULL
|
|
FLMUINT uiNamespaceBufSize,
|
|
FLMBOOL bTruncatedNamesOk)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLM_TAG_INFO * pTagInfo = NULL;
|
|
FLMBOOL bFound = FALSE;
|
|
|
|
if (!m_bTablesSorted)
|
|
{
|
|
sortTags();
|
|
}
|
|
|
|
while (*puiNextPos < m_uiNumTags)
|
|
{
|
|
pTagInfo = m_ppSortedByTagTypeAndName [*puiNextPos];
|
|
|
|
if (pTagInfo->uiType == uiType)
|
|
{
|
|
bFound = TRUE;
|
|
if (puiTagNum)
|
|
{
|
|
*puiTagNum = pTagInfo->uiTagNum;
|
|
}
|
|
if (puzTagName || pszTagName)
|
|
{
|
|
if (RC_BAD( rc = copyTagName( puzTagName, pszTagName,
|
|
&uiNameBufSize, pTagInfo->puzTagName,
|
|
bTruncatedNamesOk)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (puiDataType)
|
|
{
|
|
*puiDataType = pTagInfo->uiDataType;
|
|
}
|
|
|
|
if (puzNamespace)
|
|
{
|
|
if (RC_BAD( rc = copyTagName( puzNamespace, NULL,
|
|
&uiNamespaceBufSize,
|
|
pTagInfo->puzNamespace,
|
|
bTruncatedNamesOk)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Returned *puiNextPos should be the next one to retrieve.
|
|
|
|
(*puiNextPos)++;
|
|
break;
|
|
}
|
|
else if (pTagInfo->uiType > uiType)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
(*puiNextPos)++;
|
|
}
|
|
}
|
|
if (!bFound)
|
|
{
|
|
rc = RC_SET( NE_FLM_EOF_HIT);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Get a tag name from its tag type and number. Tag name is returned as a
|
|
UNICODE string or NATIVE string. If a non-NULL UNICODE string is passed
|
|
in, it will be used. Otherwise, the NATIVE string will be used.
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_NameTable::getFromTagTypeAndNum(
|
|
FLMUINT uiType,
|
|
FLMUINT uiTagNum,
|
|
FLMUNICODE * puzTagName, // May be NULL
|
|
char * pszTagName, // May be NULL
|
|
FLMUINT * puiNameBufSize, // May be NULL, returns # characters
|
|
FLMUINT * puiDataType, // May be NULL
|
|
FLMUNICODE * puzNamespace, // May be NULL
|
|
char * pszNamespace, // May be NULL
|
|
FLMUINT * puiNamespaceBufSize, // May be NULL, returns # characters
|
|
FLMBOOL bTruncatedNamesOk)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLM_TAG_INFO * pTagInfo;
|
|
FLMUNICODE * puzTmpNamespace = NULL;
|
|
FLMUNICODE * puzTmpName = NULL;
|
|
|
|
if ((pTagInfo = findTagByTypeAndNum( uiType, uiTagNum)) != NULL)
|
|
{
|
|
if( puzTagName || pszTagName)
|
|
{
|
|
if (RC_BAD( rc = copyTagName( puzTagName, pszTagName,
|
|
puiNameBufSize,
|
|
pTagInfo->puzTagName, bTruncatedNamesOk)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if (puiNameBufSize)
|
|
{
|
|
*puiNameBufSize = f_unilen( pTagInfo->puzTagName);
|
|
}
|
|
|
|
if (puiDataType)
|
|
{
|
|
*puiDataType = pTagInfo->uiDataType;
|
|
}
|
|
|
|
if (puzNamespace || pszNamespace)
|
|
{
|
|
if (RC_BAD( rc = copyTagName( puzNamespace, pszNamespace,
|
|
puiNamespaceBufSize,
|
|
pTagInfo->puzNamespace,
|
|
bTruncatedNamesOk)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if (puiNamespaceBufSize)
|
|
{
|
|
*puiNamespaceBufSize = f_unilen( pTagInfo->puzNamespace);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( NE_FLM_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (puzTmpName)
|
|
{
|
|
f_free( &puzTmpName);
|
|
}
|
|
|
|
if (puzTmpNamespace)
|
|
{
|
|
f_free( &puzTmpNamespace);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Get a tag number from its tag name and type. Tag name is passed
|
|
in as a UNICODE or NATIVE string. If a non-NULL UNICODE string is
|
|
passed in, it will be used. Otherwise, the NATIVE string will
|
|
be used.
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_NameTable::getFromTagTypeAndName(
|
|
FLMUINT uiType,
|
|
const FLMUNICODE * puzTagName,
|
|
const char * pszTagName,
|
|
FLMBOOL bMatchNamespace,
|
|
const FLMUNICODE * puzNamespace,
|
|
FLMUINT * puiTagNum, // May be NULL
|
|
FLMUINT * puiDataType) // May be NULL
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLM_TAG_INFO * pTagInfo;
|
|
FLMBOOL bAmbiguous;
|
|
|
|
if ((pTagInfo = findTagByTypeAndName( uiType,
|
|
puzTagName, pszTagName, bMatchNamespace,
|
|
puzNamespace,
|
|
&bAmbiguous)) != NULL)
|
|
{
|
|
if (puiTagNum)
|
|
{
|
|
*puiTagNum = pTagInfo->uiTagNum;
|
|
}
|
|
|
|
if (puiDataType)
|
|
{
|
|
*puiDataType = pTagInfo->uiDataType;
|
|
}
|
|
|
|
if (bAmbiguous)
|
|
{
|
|
rc = RC_SET( NE_FLM_MULTIPLE_MATCHES);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( NE_FLM_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Insert a tag info structure into the sorted tables at the specified
|
|
positions.
|
|
****************************************************************************/
|
|
RCODE F_NameTable::insertTagInTables(
|
|
FLM_TAG_INFO * pTagInfo,
|
|
FLMUINT uiTagTypeAndNameTblInsertPos,
|
|
FLMUINT uiTagTypeAndNumTblInsertPos)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLMUINT uiLoop;
|
|
|
|
// See if we need to resize the tables. Start at 256. Double each
|
|
// time up to 2048. Then just add 2048 at a time.
|
|
|
|
if (m_uiNumTags == m_uiTblSize)
|
|
{
|
|
FLMUINT uiNewSize;
|
|
|
|
if (!m_uiTblSize)
|
|
{
|
|
uiNewSize = 256;
|
|
}
|
|
else if (m_uiTblSize < 2048)
|
|
{
|
|
uiNewSize = m_uiTblSize * 2;
|
|
}
|
|
else
|
|
{
|
|
uiNewSize = m_uiTblSize + 2048;
|
|
}
|
|
|
|
if (RC_BAD( rc = reallocSortTables( uiNewSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Insert into the sorted-by-tag-type-and-name table
|
|
|
|
uiLoop = m_uiNumTags;
|
|
while (uiLoop > uiTagTypeAndNameTblInsertPos)
|
|
{
|
|
m_ppSortedByTagTypeAndName [uiLoop] =
|
|
m_ppSortedByTagTypeAndName [uiLoop - 1];
|
|
uiLoop--;
|
|
}
|
|
m_ppSortedByTagTypeAndName [uiTagTypeAndNameTblInsertPos] = pTagInfo;
|
|
|
|
// Insert into the sorted-by-tag-type-and-num table
|
|
|
|
uiLoop = m_uiNumTags;
|
|
while (uiLoop > uiTagTypeAndNumTblInsertPos)
|
|
{
|
|
m_ppSortedByTagTypeAndNum [uiLoop] =
|
|
m_ppSortedByTagTypeAndNum [uiLoop - 1];
|
|
uiLoop--;
|
|
}
|
|
m_ppSortedByTagTypeAndNum [uiTagTypeAndNumTblInsertPos] = pTagInfo;
|
|
|
|
// Increment the total number of tags
|
|
|
|
m_uiNumTags++;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Add a tag to the table. Tag name is passed in as a UNICODE string or
|
|
NATIVE string. If a non-NULL UNICODE string is passed in, it will
|
|
be used. Otherwise, the NATIVE string will be used.
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_NameTable::addTag(
|
|
FLMUINT uiType,
|
|
FLMUNICODE * puzTagName,
|
|
const char * pszTagName,
|
|
FLMUINT uiTagNum,
|
|
FLMUINT uiDataType,
|
|
FLMUNICODE * puzNamespace,
|
|
FLMBOOL bCheckDuplicates)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLMUINT uiTagTypeAndNameTblInsertPos;
|
|
FLMUINT uiTagTypeAndNumTblInsertPos;
|
|
FLM_TAG_INFO * pTagInfo;
|
|
FLMBOOL bAmbiguous;
|
|
|
|
// Must have a non-NULL tag name. Use UNICODE string if it is
|
|
// non-NULL. Otherwise, use NATIVE string.
|
|
|
|
if (puzTagName && *puzTagName)
|
|
{
|
|
pszTagName = NULL;
|
|
}
|
|
else if (pszTagName && *pszTagName)
|
|
{
|
|
puzTagName = NULL;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_FLM_INVALID_PARM);
|
|
goto Exit;
|
|
}
|
|
|
|
// Tag number of zero not allowed.
|
|
|
|
if (!uiTagNum)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_FLM_INVALID_PARM);
|
|
goto Exit;
|
|
}
|
|
|
|
// Tables must be sorted in order for this to work
|
|
|
|
if (bCheckDuplicates)
|
|
{
|
|
|
|
// Make sure that the tag type + name is not already used.
|
|
|
|
if (findTagByTypeAndName( uiType, puzTagName, pszTagName,
|
|
TRUE, puzNamespace,
|
|
&bAmbiguous, &uiTagTypeAndNameTblInsertPos))
|
|
{
|
|
rc = RC_SET( NE_FLM_EXISTS);
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure that the tag type + number is not already used.
|
|
|
|
if (findTagByTypeAndNum( uiType, uiTagNum,
|
|
&uiTagTypeAndNumTblInsertPos))
|
|
{
|
|
rc = RC_SET( NE_FLM_EXISTS);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiTagTypeAndNameTblInsertPos = uiTagTypeAndNumTblInsertPos = m_uiNumTags;
|
|
m_bTablesSorted = FALSE;
|
|
}
|
|
|
|
// Create a new tag info structure.
|
|
|
|
if (RC_BAD( rc = allocTag( uiType, puzTagName, pszTagName, uiTagNum,
|
|
uiDataType, puzNamespace, &pTagInfo)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Insert the tag structure into the appropriate places in the
|
|
// sorted tables.
|
|
|
|
if (RC_BAD( rc = insertTagInTables( pTagInfo,
|
|
uiTagTypeAndNameTblInsertPos,
|
|
uiTagTypeAndNumTblInsertPos)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Sort the tag tables according to their respective criteria.
|
|
****************************************************************************/
|
|
void F_NameTable::sortTags( void)
|
|
{
|
|
if (!m_bTablesSorted && m_uiNumTags > 1)
|
|
{
|
|
sortTagTbl( m_ppSortedByTagTypeAndName, 0, m_uiNumTags - 1,
|
|
compareTagTypeAndName);
|
|
sortTagTbl( m_ppSortedByTagTypeAndNum, 0, m_uiNumTags - 1,
|
|
compareTagTypeAndNum);
|
|
}
|
|
m_bTablesSorted = TRUE;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Remove a tag from the table
|
|
****************************************************************************/
|
|
void FLMAPI F_NameTable::removeTag(
|
|
FLMUINT uiType,
|
|
FLMUINT uiTagNum)
|
|
{
|
|
FLM_TAG_INFO * pTagInfo;
|
|
FLMUINT uiTagTypeAndNameTblPos;
|
|
FLMUINT uiTagTypeAndNumTblPos;
|
|
FLMBOOL bAmbiguous;
|
|
FLMBOOL bMatchNamespace;
|
|
FLMUNICODE * puzNamespace;
|
|
|
|
if ((pTagInfo = findTagByTypeAndNum( uiType, uiTagNum,
|
|
&uiTagTypeAndNumTblPos)) != NULL)
|
|
{
|
|
puzNamespace = pTagInfo->puzNamespace;
|
|
bMatchNamespace = TRUE;
|
|
|
|
if (findTagByTypeAndName( uiType, pTagInfo->puzTagName,
|
|
NULL, bMatchNamespace,
|
|
puzNamespace, &bAmbiguous,
|
|
&uiTagTypeAndNameTblPos) == NULL)
|
|
{
|
|
|
|
// It should have been in the name table too!
|
|
|
|
f_assert( 0);
|
|
}
|
|
|
|
// Shift everything in the sorted number table that is above
|
|
// the found position down one.
|
|
|
|
if (uiTagTypeAndNumTblPos < m_uiNumTags - 1)
|
|
{
|
|
f_memmove( &m_ppSortedByTagTypeAndNum [uiTagTypeAndNumTblPos],
|
|
&m_ppSortedByTagTypeAndNum [uiTagTypeAndNumTblPos + 1],
|
|
sizeof( FLM_TAG_INFO *) *
|
|
(m_uiNumTags - 1 - uiTagTypeAndNumTblPos));
|
|
}
|
|
|
|
// Shift everything in the sorted name table that is above
|
|
// the found position down one.
|
|
|
|
if (uiTagTypeAndNameTblPos < m_uiNumTags - 1)
|
|
{
|
|
f_memmove( &m_ppSortedByTagTypeAndName [uiTagTypeAndNameTblPos],
|
|
&m_ppSortedByTagTypeAndName [uiTagTypeAndNameTblPos + 1],
|
|
sizeof( FLM_TAG_INFO *) *
|
|
(m_uiNumTags - 1 - uiTagTypeAndNameTblPos));
|
|
}
|
|
m_uiNumTags--;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Create a clone of this name table
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_NameTable::cloneNameTable(
|
|
IF_NameTable ** ppNewNameTable)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLMUINT uiLoop;
|
|
FLM_TAG_INFO * pTagInfo;
|
|
FLMUINT uiPoolBlkSize;
|
|
F_NameTable * pNewNameTable = NULL;
|
|
|
|
// Allocate a new name table
|
|
|
|
if( (pNewNameTable = f_new F_NameTable) == NULL)
|
|
{
|
|
rc = RC_SET( NE_FLM_MEM);
|
|
goto Exit;
|
|
}
|
|
|
|
// Set the pool size to be as optimal as possible.
|
|
|
|
uiPoolBlkSize = m_uiMemoryAllocated / 8;
|
|
if (uiPoolBlkSize < 1024)
|
|
{
|
|
uiPoolBlkSize = 1024;
|
|
}
|
|
else if (uiPoolBlkSize > 65536)
|
|
{
|
|
uiPoolBlkSize = 65536;
|
|
}
|
|
|
|
pNewNameTable->clearTable( uiPoolBlkSize);
|
|
|
|
// Pre-allocate exactly enough table space
|
|
|
|
if (RC_BAD( rc = pNewNameTable->reallocSortTables( m_uiNumTags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Add all of the tags
|
|
|
|
for (uiLoop = 0; uiLoop < m_uiNumTags; uiLoop++)
|
|
{
|
|
pTagInfo = m_ppSortedByTagTypeAndNum [uiLoop];
|
|
if (RC_BAD( rc = pNewNameTable->addTag(
|
|
pTagInfo->uiType, pTagInfo->puzTagName, NULL, pTagInfo->uiTagNum,
|
|
pTagInfo->uiDataType, pTagInfo->puzNamespace, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pNewNameTable->sortTags();
|
|
*ppNewNameTable = pNewNameTable;
|
|
pNewNameTable = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pNewNameTable)
|
|
{
|
|
pNewNameTable->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Increment use count on this object.
|
|
****************************************************************************/
|
|
FLMINT FLMAPI F_NameTable::AddRef( void)
|
|
{
|
|
return( f_atomicInc( &m_refCnt));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Decrement the use count and delete if use count goes to zero.
|
|
****************************************************************************/
|
|
FLMINT FLMAPI F_NameTable::Release( void)
|
|
{
|
|
FLMINT iRefCnt;
|
|
|
|
if ((iRefCnt = f_atomicDec( &m_refCnt)) == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return( iRefCnt);
|
|
}
|
|
#endif
|
|
|
|
#if defined( FLM_WATCOM_NLM) || defined( FLM_OSX)
|
|
void gv_ftkntab( void)
|
|
{
|
|
}
|
|
#endif
|