Files
mars-flaim/xflaim/src/fdict.cpp
ahodgkinson 0e2ba5f0b3 Updated support for AIX.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@729 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-08-01 19:31:50 +00:00

10010 lines
215 KiB
C++

//------------------------------------------------------------------------------
// Desc: Routines to access anything in the dictionary
//
// Tabs: 3
//
// Copyright (c) 1995-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: fdict.cpp 3112 2006-01-19 13:12:40 -0700 (Thu, 19 Jan 2006) dsanders $
//------------------------------------------------------------------------------
#include "flaimsys.h"
// Data type strings
const char * fdictDataTypes[ XFLM_NUM_OF_TYPES + 1] =
{
XFLM_NODATA_OPTION_STR,
XFLM_STRING_OPTION_STR,
XFLM_INTEGER_OPTION_STR,
XFLM_BINARY_OPTION_STR,
NULL
};
extern RESERVED_TAG_NAME FlmReservedElementTags[];
extern RESERVED_TAG_NAME FlmReservedAttributeTags[];
FSTATIC void fdictInsertInIcdChain(
ICD ** ppFirstIcd,
ICD * pIcd);
FSTATIC void fdictRemoveFromIcdChain(
ICD ** ppFirstIcd,
ICD * pIcd);
FSTATIC RCODE fdictCopyCollection(
F_Pool * pDictPool,
F_COLLECTION ** ppDestCollection,
F_COLLECTION * pSrcCollection);
FSTATIC RCODE fdictCopyPrefix(
F_Pool * pDictPool,
F_PREFIX ** ppDestPrefix,
F_PREFIX * pSrcPrefix);
FSTATIC RCODE fdictCopyEncDef(
F_Pool * pDictPool,
F_ENCDEF ** ppDestEncDef,
F_ENCDEF * pSrcEncDef);
FSTATIC char * fdictGetOption(
char ** ppszSrc);
FSTATIC RCODE isIndexComponent(
F_Db * pDb,
F_DOMNode * pNode,
FLMBOOL * pbIsIndexComponent,
FLMUINT * puiElementId);
FSTATIC FLMBOOL indexDefsSame(
IXD * pOldIxd,
IXD * pNewIxd);
#define MAX_ENC_TYPES 2
// NOTE: If you change the arrangement of the values in this array, make sure
// you search the entire codebase for references to DDEncOpts and fdictLegalEncDefTypes
// and verify that the changes won't cause problems.
const char * DDEncOpts[MAX_ENC_TYPES] = {
XFLM_ENC_AES_OPTION_STR, /* AES */
XFLM_ENC_DES3_OPTION_STR /* Triple DES */
};
/***************************************************************************
Desc: Constructor
***************************************************************************/
F_Dict::F_Dict()
{
m_pNext = NULL;
m_pPrev = NULL;
m_pDatabase = NULL;
m_uiDictSeq = 0;
m_dictPool.poolInit( 1024);
m_pElementDefTbl = NULL;
m_uiLowestElementNum = 0;
m_uiHighestElementNum = 0;
m_pReservedElementDefTbl = NULL;
m_pExtElementDefTbl = NULL;
m_uiExtElementDefTblSize = 0;
m_hExtElementDefMutex = F_MUTEX_NULL;
m_pIxElementTbl = NULL;
m_uiIxElementTblSize = 0;
m_uiNumIxElements = 0;
m_pAttributeDefTbl = NULL;
m_uiLowestAttributeNum = 0;
m_uiHighestAttributeNum = 0;
m_pReservedAttributeDefTbl = NULL;
m_pExtAttributeDefTbl = NULL;
m_uiExtAttributeDefTblSize = 0;
m_hExtAttributeDefMutex = F_MUTEX_NULL;
m_pIxAttributeTbl = NULL;
m_uiIxAttributeTblSize = 0;
m_uiNumIxAttributes = 0;
m_pDictCollection = NULL;
m_pDataCollection = NULL;
m_pMaintCollection = NULL;
m_ppCollectionTbl = NULL;
m_uiLowestCollectionNum = 0;
m_uiHighestCollectionNum = 0;
m_ppPrefixTbl = NULL;
m_uiLowestPrefixNum = 0;
m_uiHighestPrefixNum = 0;
m_ppEncDefTbl = NULL;
m_uiLowestEncDefNum = 0;
m_uiHighestEncDefNum = 0;
m_pNameIndex = NULL;
m_pNumberIndex = NULL;
m_ppIxdTbl = NULL;
m_uiLowestIxNum = 0;
m_uiHighestIxNum = 0;
m_pNameTable = NULL;
m_pRootIcdList = NULL;
// Whenever an F_Dict is allocated, it is always immediately
// used by an F_Db.
m_uiUseCount = 1;
}
/***************************************************************************
Desc:
***************************************************************************/
F_Dict::~F_Dict()
{
resetDict();
}
/***************************************************************************
Desc: Clear the dictionary object so it can be reused. NOTE: This function
also needs to do all the freeing up that the destructor would do
because it is called by the destructor.
***************************************************************************/
void F_Dict::resetDict( void)
{
FLMUINT uiLoop;
f_free( &m_pElementDefTbl);
m_uiLowestElementNum = 0;
m_uiHighestElementNum = 0;
f_free( &m_pExtElementDefTbl);
m_uiExtElementDefTblSize = 0;
if (m_hExtElementDefMutex != F_MUTEX_NULL)
{
f_mutexDestroy( &m_hExtElementDefMutex);
}
f_free( &m_pReservedElementDefTbl);
f_free( &m_pIxElementTbl);
m_uiIxElementTblSize = 0;
m_uiNumIxElements = 0;
f_free( &m_pAttributeDefTbl);
m_uiLowestAttributeNum = 0;
m_uiHighestAttributeNum = 0;
f_free( &m_pExtAttributeDefTbl);
m_uiExtAttributeDefTblSize = 0;
if (m_hExtAttributeDefMutex != F_MUTEX_NULL)
{
f_mutexDestroy( &m_hExtAttributeDefMutex);
}
f_free( &m_pReservedAttributeDefTbl);
f_free( &m_pIxAttributeTbl);
m_uiIxAttributeTblSize = 0;
m_uiNumIxAttributes = 0;
f_free( &m_ppIxdTbl);
m_uiLowestIxNum = 0;
m_uiHighestIxNum = 0;
m_pNameIndex = NULL;
m_pNumberIndex = NULL;
f_free( &m_ppCollectionTbl);
m_uiLowestCollectionNum = 0;
m_uiHighestCollectionNum = 0;
f_free( &m_ppPrefixTbl);
m_uiLowestPrefixNum = 0;
m_uiHighestPrefixNum = 0;
for ( uiLoop = 0;
uiLoop <= (m_uiHighestEncDefNum - m_uiLowestEncDefNum);
uiLoop++ )
{
if (m_ppEncDefTbl &&
m_ppEncDefTbl[ uiLoop] &&
(*m_ppEncDefTbl[ uiLoop]).pCcs)
{
(*m_ppEncDefTbl[ uiLoop]).pCcs->Release();
}
}
f_free( &m_ppEncDefTbl);
m_uiLowestEncDefNum = 0;
m_uiHighestEncDefNum = 0;
m_pDictCollection = NULL;
m_pDataCollection = NULL;
m_pMaintCollection = NULL;
m_dictPool.poolFree();
m_dictPool.poolInit( 1024);
if (m_pNameTable)
{
m_pNameTable->Release();
m_pNameTable = NULL;
}
m_pRootIcdList = NULL;
}
/***************************************************************************
Desc:
***************************************************************************/
RCODE F_Dict::allocNameTable( void)
{
if ((m_pNameTable = f_new F_NameTable) == NULL)
{
return( RC_SET( NE_XFLM_MEM));
}
return( NE_XFLM_OK);
}
/***************************************************************************
Desc: Get the first ICD, if any for an element. NOTE: This is only called
for element numbers greater or equal to FLM_LOW_EXT_ELEMENT_NUM, so
we have to look in the m_pIxElementTbl table.
***************************************************************************/
IX_ITEM * F_Dict::findIxItem(
IX_ITEM * pIxTbl,
FLMUINT uiNumItems,
FLMUINT uiDictNum,
FLMUINT * puiInsertPos
)
{
IX_ITEM * pIxItem = NULL;
FLMUINT uiLow;
FLMUINT uiMid;
FLMUINT uiHigh;
FLMUINT uiTblDictNum;
// Do binary search in the table
if (!uiNumItems)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = --uiNumItems;
uiLow = 0;
for (;;)
{
uiMid = (uiLow + uiHigh) / 2;
uiTblDictNum = pIxTbl [uiMid].uiDictNum;
if (uiTblDictNum == uiDictNum)
{
// Found Match
if (puiInsertPos)
{
*puiInsertPos = uiMid;
}
pIxItem = &pIxTbl [uiMid];
goto Exit;
}
// Check if we are done
if (uiLow >= uiHigh)
{
if (puiInsertPos)
{
*puiInsertPos = (uiDictNum < uiTblDictNum)
? uiMid
: uiMid + 1;
}
goto Exit;
}
if (uiDictNum < uiTblDictNum)
{
if (uiMid == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = uiMid - 1;
}
else
{
if (uiMid == uiNumItems)
{
if (puiInsertPos)
{
*puiInsertPos = uiMid + 1;
}
goto Exit;
}
uiLow = uiMid + 1;
}
}
Exit:
return( pIxItem);
}
/***************************************************************************
Desc: Get information for an extended element - which are elements whose tag
number is greater than or equal to FLM_LOW_EXT_ELEMENT_NUM
Note: Populates data type, first Icd, and state
***************************************************************************/
RCODE F_Dict::getExtElement(
F_Db * pDb,
FLMUINT64 ui64DocumentID,
FLMUINT uiElementNum,
F_AttrElmInfo * pElmInfo)
{
RCODE rc = NE_XFLM_OK;
EXT_ATTR_ELM_DEF * pExtElementDef;
IX_ITEM * pIxItem;
FLMBOOL bMutexLocked;
// See if the element is in our extended list. If not, bring it in.
f_mutexLock( m_hExtElementDefMutex);
bMutexLocked = TRUE;
pExtElementDef = getExtElementDef( uiElementNum);
if (pExtElementDef->uiDictNum != uiElementNum)
{
f_mutexUnlock( m_hExtElementDefMutex);
bMutexLocked = FALSE;
if (!ui64DocumentID)
{
F_DataVector searchKey;
F_DataVector foundKey;
// Find and read the element definition document
// Need to lookup the document's ID, using the element number
if (RC_BAD( rc = searchKey.setUINT( 0, ELM_ELEMENT_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = searchKey.setUINT( 1, uiElementNum)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->keyRetrieve( XFLM_DICT_NUMBER_INDEX,
&searchKey, XFLM_EXACT, &foundKey)))
{
goto Exit;
}
ui64DocumentID = foundKey.getDocumentID();
}
// Must read the element definition document
if (RC_BAD( rc = pDb->getElmAttrInfo( ELM_ELEMENT_TAG,
ui64DocumentID, pElmInfo, TRUE, FALSE)))
{
goto Exit;
}
// See if the element is indexed.
pIxItem = findIxElement( uiElementNum);
// Relock the mutex and populate the extended structure
// with the information we found.
f_mutexLock( m_hExtElementDefMutex);
bMutexLocked = TRUE;
pExtElementDef->uiDictNum = uiElementNum;
pExtElementDef->attrElmDef.uiFlags =
(pElmInfo->m_uiDataType & ATTR_ELM_DATA_TYPE_MASK) |
(pElmInfo->m_uiState & ATTR_ELM_STATE_MASK);
pExtElementDef->attrElmDef.pFirstIcd = pIxItem
? pIxItem->pFirstIcd
: NULL;
}
pElmInfo->m_uiDataType = attrElmGetType( &pExtElementDef->attrElmDef);
pElmInfo->m_pFirstIcd = pExtElementDef->attrElmDef.pFirstIcd;
pElmInfo->m_uiState = attrElmGetState( &pExtElementDef->attrElmDef);
Exit:
if (bMutexLocked)
{
f_mutexUnlock( m_hExtElementDefMutex);
}
return( rc);
}
/***************************************************************************
Desc: Get information for an extended attribute - which are attributes whose
tag number is greater than or equal to FLM_LOW_EXT_ATTRIBUTE_NUM
***************************************************************************/
RCODE F_Dict::getExtAttribute(
F_Db * pDb,
FLMUINT64 ui64DocumentID,
FLMUINT uiAttributeNum,
F_AttrElmInfo * pAttrInfo)
{
RCODE rc = NE_XFLM_OK;
EXT_ATTR_ELM_DEF * pExtAttributeDef;
IX_ITEM * pIxItem;
FLMBOOL bMutexLocked;
// See if the attribute is in our extended list. If not, bring it in.
f_mutexLock( m_hExtAttributeDefMutex);
bMutexLocked = TRUE;
pExtAttributeDef = getExtAttributeDef( uiAttributeNum);
if (pExtAttributeDef->uiDictNum != uiAttributeNum)
{
f_mutexUnlock( m_hExtAttributeDefMutex);
bMutexLocked = FALSE;
if (!ui64DocumentID)
{
F_DataVector searchKey;
F_DataVector foundKey;
// Find and read the element definition document
// Need to lookup the document's ID, using the element number
if (RC_BAD( rc = searchKey.setUINT( 0, ELM_ATTRIBUTE_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = searchKey.setUINT( 1, uiAttributeNum)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->keyRetrieve( XFLM_DICT_NUMBER_INDEX,
&searchKey, XFLM_EXACT, &foundKey)))
{
goto Exit;
}
ui64DocumentID = foundKey.getDocumentID();
}
// Must read the attribute definition document
if (RC_BAD( rc = pDb->getElmAttrInfo( ELM_ATTRIBUTE_TAG,
ui64DocumentID, pAttrInfo, TRUE, FALSE)))
{
goto Exit;
}
// See if the attribute is indexed.
pIxItem = findIxAttribute( uiAttributeNum);
// Relock the mutex and populate the extended structure
// with the information we found.
f_mutexLock( m_hExtAttributeDefMutex);
bMutexLocked = TRUE;
pExtAttributeDef->uiDictNum = uiAttributeNum;
pExtAttributeDef->attrElmDef.uiFlags =
(pAttrInfo->m_uiDataType & ATTR_ELM_DATA_TYPE_MASK) |
(pAttrInfo->m_uiState & ATTR_ELM_STATE_MASK);
pExtAttributeDef->attrElmDef.pFirstIcd = pIxItem
? pIxItem->pFirstIcd
: NULL;
}
pAttrInfo->m_uiDataType = attrElmGetType( &pExtAttributeDef->attrElmDef);
pAttrInfo->m_pFirstIcd = pExtAttributeDef->attrElmDef.pFirstIcd;
pAttrInfo->m_uiState = attrElmGetState( &pExtAttributeDef->attrElmDef);
pAttrInfo->m_uiFlags = attrElmGetFlags( &pExtAttributeDef->attrElmDef);
Exit:
if (bMutexLocked)
{
f_mutexUnlock( m_hExtAttributeDefMutex);
}
return( rc);
}
/***************************************************************************
Desc: Get the element information.
Note: Populates data type, first ICD, and state
***************************************************************************/
RCODE F_Dict::getElement(
F_Db * pDb,
FLMUINT uiElementNum, // [in] Element Number to look up
F_AttrElmInfo * pElmInfo)
{
RCODE rc = NE_XFLM_OK;
ATTR_ELM_DEF * pElementDef;
if (elementIsReservedTag( uiElementNum))
{
if ((pElementDef = getReservedElementDef( uiElementNum)) != NULL)
{
goto Get_Type_And_State;
}
else
{
rc = RC_SET( NE_XFLM_BAD_ELEMENT_NUM);
goto Exit;
}
}
else if (uiElementNum <= FLM_HIGH_FIXED_ELEMENT_NUM)
{
if ((pElementDef = getElementDef( uiElementNum)) != NULL)
{
Get_Type_And_State:
pElmInfo->m_uiDataType = attrElmGetType( pElementDef);
pElmInfo->m_pFirstIcd = pElementDef->pFirstIcd;
pElmInfo->m_uiState = attrElmGetState( pElementDef);
pElmInfo->m_uiFlags = attrElmGetFlags( pElementDef);
}
else
{
rc = RC_SET( NE_XFLM_BAD_ELEMENT_NUM);
goto Exit;
}
}
else if (uiElementNum >= FLM_LOW_EXT_ELEMENT_NUM && m_pExtElementDefTbl)
{
if (RC_BAD( rc = getExtElement( pDb, 0, uiElementNum, pElmInfo)))
{
goto Exit;
}
}
else
{
rc = RC_SET( NE_XFLM_BAD_ELEMENT_NUM);
goto Exit;
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Get the attribute information.
Note: Populates data type, first ICD, and state
***************************************************************************/
RCODE F_Dict::getAttribute(
F_Db * pDb,
FLMUINT uiAttributeNum,
F_AttrElmInfo * pAttrInfo)
{
RCODE rc = NE_XFLM_OK;
ATTR_ELM_DEF * pAttributeDef;
if( attributeIsReservedTag( uiAttributeNum))
{
if ((pAttributeDef = getReservedAttributeDef( uiAttributeNum)) != NULL)
{
goto Get_Type_And_State;
}
else
{
rc = RC_SET( NE_XFLM_BAD_ATTRIBUTE_NUM);
goto Exit;
}
}
else if (uiAttributeNum <= FLM_HIGH_FIXED_ATTRIBUTE_NUM)
{
if ((pAttributeDef = getAttributeDef( uiAttributeNum)) != NULL)
{
Get_Type_And_State:
pAttrInfo->m_uiDataType = attrElmGetType( pAttributeDef);
pAttrInfo->m_pFirstIcd = pAttributeDef->pFirstIcd;
pAttrInfo->m_uiState = attrElmGetState( pAttributeDef);
pAttrInfo->m_uiFlags = attrElmGetFlags( pAttributeDef);
}
else
{
rc = RC_SET( NE_XFLM_BAD_ATTRIBUTE_NUM);
goto Exit;
}
}
else if (uiAttributeNum >= FLM_LOW_EXT_ATTRIBUTE_NUM && m_pExtAttributeDefTbl)
{
if (RC_BAD( rc = getExtAttribute( pDb, 0, uiAttributeNum, pAttrInfo)))
{
goto Exit;
}
}
else
{
rc = RC_SET( NE_XFLM_BAD_ATTRIBUTE_NUM);
goto Exit;
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Get the data type for any given element or attribute in the
current db
***************************************************************************/
RCODE F_Db::getDataType(
FLMUINT uiDictType,
FLMUINT uiNameId,
FLMUINT * puiDataType)
{
RCODE rc = NE_XFLM_OK;
F_AttrElmInfo defInfo;
flmAssert( uiDictType == ELM_ELEMENT_TAG ||
uiDictType == ELM_ATTRIBUTE_TAG);
if( RC_BAD( rc =
(uiDictType == ELM_ELEMENT_TAG
? m_pDict->getElement( this, uiNameId, &defInfo)
: m_pDict->getAttribute( this, uiNameId, &defInfo))))
{
goto Exit;
}
*puiDataType = defInfo.m_uiDataType;
Exit:
return( rc);
}
/***************************************************************************
Desc: Get the next element defined in the dictionary after the one that
is passed in.
Note: Populates data type, first ICD, and state
***************************************************************************/
RCODE F_Dict::getNextElement(
F_Db * pDb,
FLMUINT * puiElementNum,
F_AttrElmInfo * pElmInfo)
{
RCODE rc = NE_XFLM_OK;
ATTR_ELM_DEF * pElementDef = NULL;
FLMUINT uiElementNum = *puiElementNum;
if (uiElementNum < m_uiLowestElementNum)
{
uiElementNum = m_uiLowestElementNum;
}
else
{
uiElementNum++;
}
while (uiElementNum >= m_uiLowestElementNum &&
uiElementNum <= m_uiHighestElementNum)
{
pElementDef = &m_pElementDefTbl [uiElementNum - m_uiLowestElementNum];
if (attrElmGetState( pElementDef))
{
break;
}
else
{
pElementDef = NULL;
}
uiElementNum++;
}
if (pElementDef)
{
// At this point we know we have an element.
*puiElementNum = uiElementNum;
pElmInfo->m_uiDataType = attrElmGetType( pElementDef);
pElmInfo->m_pFirstIcd = pElementDef->pFirstIcd;
pElmInfo->m_uiState = attrElmGetState( pElementDef);
}
else
{
F_DataVector searchKey;
F_DataVector foundKey;
FLMUINT uiType;
// See if it is perchance in the extended list, if there
// is one
if (!m_pExtElementDefTbl)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
searchKey.reset();
foundKey.reset();
if (RC_BAD( rc = searchKey.setUINT( 0, ELM_ELEMENT_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = searchKey.setUINT( 1, uiElementNum)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->keyRetrieve( XFLM_DICT_NUMBER_INDEX,
&searchKey, XFLM_EXCL, &foundKey)))
{
if (rc == NE_XFLM_EOF_HIT ||
rc == NE_XFLM_BOF_HIT ||
rc == NE_XFLM_NOT_FOUND)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
}
goto Exit;
}
// If it is not an element definition document, skip it
// we are done - there are no more.
if (RC_BAD( rc = foundKey.getUINT( 0, &uiType)))
{
if (rc == NE_XFLM_NOT_FOUND)
{
flmAssert( 0);
rc = RC_SET( NE_XFLM_EOF_HIT);
}
goto Exit;
}
if (uiType != ELM_ELEMENT_TAG)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
// Get the element number.
if (RC_BAD( rc = foundKey.getUINT( 1, &uiElementNum)))
{
if (rc == NE_XFLM_NOT_FOUND)
{
flmAssert( 0);
rc = RC_SET( NE_XFLM_EOF_HIT);
}
goto Exit;
}
// At this point, we know we found one, so we will populate
// the extended element structure.
if (RC_BAD( rc = getExtElement( pDb, foundKey.getDocumentID(),
uiElementNum, pElmInfo)))
{
goto Exit;
}
*puiElementNum = uiElementNum;
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Get the next attribute defined in the dictionary after the one that
is passed in.
Note: Populates data type, first ICD, state, and flags
***************************************************************************/
RCODE F_Dict::getNextAttribute(
F_Db * pDb,
FLMUINT * puiAttributeNum,
F_AttrElmInfo * pAttrInfo)
{
RCODE rc = NE_XFLM_OK;
ATTR_ELM_DEF * pAttributeDef = NULL;
FLMUINT uiAttributeNum = *puiAttributeNum;
if (uiAttributeNum < m_uiLowestAttributeNum)
{
uiAttributeNum = m_uiLowestAttributeNum;
}
else
{
uiAttributeNum++;
}
while (uiAttributeNum >= m_uiLowestAttributeNum &&
uiAttributeNum <= m_uiHighestAttributeNum)
{
pAttributeDef = &m_pAttributeDefTbl [uiAttributeNum - m_uiLowestAttributeNum];
if (attrElmGetState( pAttributeDef))
{
break;
}
else
{
pAttributeDef = NULL;
}
uiAttributeNum++;
}
if (pAttributeDef)
{
// At this point we know we have an attribute.
*puiAttributeNum = uiAttributeNum;
pAttrInfo->m_uiDataType = attrElmGetType( pAttributeDef);
pAttrInfo->m_pFirstIcd = pAttributeDef->pFirstIcd;
pAttrInfo->m_uiState = attrElmGetState( pAttributeDef);
pAttrInfo->m_uiFlags = attrElmGetFlags( pAttributeDef);
}
else
{
F_DataVector searchKey;
F_DataVector foundKey;
FLMUINT uiType;
// See if it is perchance in the extended list, if there
// is one
if (!m_pExtAttributeDefTbl)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
searchKey.reset();
foundKey.reset();
if (RC_BAD( rc = searchKey.setUINT( 0, ELM_ATTRIBUTE_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = searchKey.setUINT( 1, uiAttributeNum)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->keyRetrieve( XFLM_DICT_NUMBER_INDEX,
&searchKey, XFLM_EXCL, &foundKey)))
{
if (rc == NE_XFLM_EOF_HIT ||
rc == NE_XFLM_BOF_HIT ||
rc == NE_XFLM_NOT_FOUND)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
}
goto Exit;
}
// If it is not an attribute definition document, skip it
// we are done - there are no more.
if (RC_BAD( rc = foundKey.getUINT( 0, &uiType)))
{
if (rc == NE_XFLM_NOT_FOUND)
{
flmAssert( 0);
rc = RC_SET( NE_XFLM_EOF_HIT);
}
goto Exit;
}
if (uiType != ELM_ATTRIBUTE_TAG)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
// Get the attribute number.
if (RC_BAD( rc = foundKey.getUINT( 1, &uiAttributeNum)))
{
if (rc == NE_XFLM_NOT_FOUND)
{
flmAssert( 0);
rc = RC_SET( NE_XFLM_EOF_HIT);
}
goto Exit;
}
// At this point, we know we found one, so we will populate
// the extended attribute structure.
if (RC_BAD( rc = getExtAttribute( pDb, foundKey.getDocumentID(),
uiAttributeNum, pAttrInfo)))
{
goto Exit;
}
*puiAttributeNum = uiAttributeNum;
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Get the collection given a collection number.
***************************************************************************/
RCODE F_Dict::getCollection(
FLMUINT uiCollectionNum,
F_COLLECTION ** ppCollection, // [out] optional
FLMBOOL bOfflineOk
)
{
RCODE rc = NE_XFLM_OK;
F_COLLECTION * pCollection = NULL;
// Try most commonly used one first - default data collection
if( uiCollectionNum == XFLM_DATA_COLLECTION)
{
pCollection = m_pDataCollection;
}
else if( uiCollectionNum &&
uiCollectionNum >= m_uiLowestCollectionNum &&
uiCollectionNum <= m_uiHighestCollectionNum)
{
pCollection = m_ppCollectionTbl [uiCollectionNum -
m_uiLowestCollectionNum];
}
else
{
switch (uiCollectionNum)
{
case XFLM_DICT_COLLECTION:
pCollection = m_pDictCollection;
break;
case XFLM_MAINT_COLLECTION:
pCollection = m_pMaintCollection;
break;
}
}
// If the collection is encrypted, and we are in limited mode, then it must
// be offline.
if (!pCollection)
{
if (ppCollection)
{
*ppCollection = NULL;
}
rc = RC_SET( NE_XFLM_BAD_COLLECTION);
goto Exit;
}
else
{
if ((pCollection->lfInfo.uiEncId && m_bInLimitedMode) && !bOfflineOk)
{
rc = RC_SET( NE_XFLM_COLLECTION_OFFLINE);
}
if (ppCollection)
{
*ppCollection = pCollection;
}
}
Exit:
return rc;
}
/***************************************************************************
Desc: Returns the ID of a prefix (unicode buffer)
***************************************************************************/
RCODE F_Dict::getPrefixId(
F_Db * pDb,
const FLMUNICODE * puzPrefix,
FLMUINT * puiPrefixId)
{
RCODE rc = NE_XFLM_OK;
F_DataVector searchKey;
F_DataVector foundKey;
// Get the prefix number - look up in the index
if (RC_BAD( rc = searchKey.setUINT( 0, ELM_PREFIX_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = searchKey.setUnicode( 1, puzPrefix)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->keyRetrieve( XFLM_DICT_NAME_INDEX,
&searchKey, XFLM_EXACT, &foundKey)))
{
goto Exit;
}
// Data part of the retrieved key has the dictionary number
// for this prefix
if (RC_BAD( rc = foundKey.getUINT( 3, puiPrefixId)))
{
if (rc == NE_XFLM_NOT_FOUND)
{
flmAssert( 0);
*puiPrefixId = 0;
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Returns the ID of a prefix (native buffer)
***************************************************************************/
RCODE F_Dict::getPrefixId(
F_Db * pDb,
const char * pszPrefix,
FLMUINT * puiPrefixId)
{
RCODE rc = NE_XFLM_OK;
F_DataVector searchKey;
F_DataVector foundKey;
// Get the prefix number - look up in the index
if (RC_BAD( rc = searchKey.setUINT( 0, ELM_PREFIX_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = searchKey.setUTF8( 1, (FLMBYTE *)pszPrefix)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->keyRetrieve( XFLM_DICT_NAME_INDEX,
&searchKey, XFLM_EXACT, &foundKey)))
{
goto Exit;
}
// Data part of the retrieved key has the dictionary number
// for this prefix
if (RC_BAD( rc = foundKey.getUINT( 3, puiPrefixId)))
{
if (rc == NE_XFLM_NOT_FOUND)
{
flmAssert( 0);
*puiPrefixId = 0;
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Returns the ID of an encryption definition (unicode buffer)
***************************************************************************/
RCODE F_Dict::getEncDefId(
F_Db * pDb,
const FLMUNICODE * puzEncDef,
FLMUINT * puiEncDefId)
{
RCODE rc = NE_XFLM_OK;
F_DataVector searchKey;
F_DataVector foundKey;
// Get the encdef number - look up in the name index
if (RC_BAD( rc = searchKey.setUINT( 0, ELM_ENCDEF_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = searchKey.setUnicode( 1, puzEncDef)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->keyRetrieve( XFLM_DICT_NAME_INDEX,
&searchKey, XFLM_EXACT, &foundKey)))
{
goto Exit;
}
// Data part of the retrieved key has the dictionary number
// for this encdef
if (RC_BAD( rc = foundKey.getUINT( 3, puiEncDefId)))
{
if (rc == NE_XFLM_NOT_FOUND)
{
flmAssert( 0);
*puiEncDefId = 0;
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Returns the ID of an encryption definition (native buffer)
***************************************************************************/
RCODE F_Dict::getEncDefId(
F_Db * pDb,
const char * pszEncDef,
FLMUINT * puiEncDefId)
{
RCODE rc = NE_XFLM_OK;
F_DataVector searchKey;
F_DataVector foundKey;
// Get the encdef number - look up in the name index
if (RC_BAD( rc = searchKey.setUINT( 0, ELM_ENCDEF_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = searchKey.setUTF8( 1, (FLMBYTE *)pszEncDef)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->keyRetrieve( XFLM_DICT_NAME_INDEX,
&searchKey, XFLM_EXACT, &foundKey)))
{
goto Exit;
}
// Data part of the retrieved key has the dictionary number
// for this encdef
if (RC_BAD( rc = foundKey.getUINT( 3, puiEncDefId)))
{
if (rc == NE_XFLM_NOT_FOUND)
{
flmAssert( 0);
*puiEncDefId = 0;
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Returns the name of a prefix, either Unicode or Native.
***************************************************************************/
RCODE F_Dict::getPrefix(
FLMBOOL bUnicode,
FLMUINT uiPrefixId,
void * pvPrefixBuf,
FLMUINT uiBufSize,
FLMUINT * puiCharsReturned)
{
RCODE rc = NE_XFLM_OK;
F_PREFIX * pPrefix;
FLMUNICODE * puzName;
FLMUINT uiOffset = 0;
FLMUNICODE * puzPrefixBuf = (FLMUNICODE *)pvPrefixBuf;
char * pszPrefixBuf = (char *)pvPrefixBuf;
FLMUINT uiBufChars = (bUnicode ? uiBufSize / sizeof(FLMUNICODE) : uiBufSize);
if( RC_BAD( rc = getPrefix( uiPrefixId, &pPrefix)))
{
goto Exit;
}
if( (puzName = pPrefix->puzPrefixName) != NULL)
{
if( bUnicode && puzPrefixBuf)
{
if( !uiBufChars)
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
while( *puzName)
{
if( uiBufChars == 1)
{
puzPrefixBuf[ uiOffset] = 0;
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
puzPrefixBuf[ uiOffset++] = *puzName;
puzName++;
uiBufChars--;
}
puzPrefixBuf[ uiOffset] = 0;
}
else if (pszPrefixBuf)
{
if (!uiBufChars)
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
while ( *puzName)
{
if (uiBufChars == 1)
{
pszPrefixBuf[ uiOffset] = 0;
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
// Is the character convertable?
if (*puzName > 127)
{
rc = RC_SET( NE_XFLM_CONV_ILLEGAL);
goto Exit;
}
else
{
pszPrefixBuf[ uiOffset] = (char)*puzName;
uiOffset++;
}
puzName++;
}
pszPrefixBuf[ uiOffset] = 0;
}
else if( puiCharsReturned)
{
uiOffset = f_unilen( puzName);
}
}
Exit:
if( puiCharsReturned)
{
*puiCharsReturned = uiOffset;
}
return( rc);
}
/***************************************************************************
Desc: Returns prefix object
***************************************************************************/
RCODE F_Dict::getPrefix(
FLMUINT uiPrefixNum,
F_PREFIX ** ppPrefix)
{
F_PREFIX * pPrefix = NULL;
if( uiPrefixNum)
{
if( uiPrefixNum >= m_uiLowestPrefixNum &&
uiPrefixNum <= m_uiHighestPrefixNum)
{
pPrefix = m_ppPrefixTbl[ uiPrefixNum - m_uiLowestPrefixNum];
}
}
if( ppPrefix)
{
*ppPrefix = pPrefix;
}
return( pPrefix ? NE_XFLM_OK : RC_SET( NE_XFLM_BAD_PREFIX));
}
/***************************************************************************
Desc: Returns the name of an encdef, either Unicode or Native.
***************************************************************************/
RCODE F_Dict::getEncDef(
FLMBOOL bUnicode,
FLMUINT uiEncDefId,
void * pvEncDefBuf,
FLMUINT uiBufSize,
FLMUINT * puiCharsReturned)
{
RCODE rc = NE_XFLM_OK;
F_ENCDEF * pEncDef;
FLMUNICODE * puzName;
FLMUINT uiOffset = 0;
FLMUNICODE * puzEncDefBuf = (FLMUNICODE *)pvEncDefBuf;
char * pszEncDefBuf = (char *)pvEncDefBuf;
FLMUINT uiBufChars = (bUnicode ? uiBufSize / sizeof(FLMUNICODE) : uiBufSize);
if( RC_BAD( rc = getEncDef( uiEncDefId, &pEncDef)))
{
goto Exit;
}
if( (puzName = pEncDef->puzEncDefName) != NULL)
{
if( bUnicode && puzEncDefBuf)
{
if( !uiBufChars)
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
while( *puzName)
{
if( uiBufChars == 1)
{
puzEncDefBuf[ uiOffset] = 0;
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
puzEncDefBuf[ uiOffset++] = *puzName;
puzName++;
uiBufChars--;
}
puzEncDefBuf[ uiOffset] = 0;
}
else if (pszEncDefBuf)
{
if (!uiBufChars)
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
while ( *puzName)
{
if (uiBufChars == 1)
{
pszEncDefBuf[ uiOffset] = 0;
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
// Is the character convertable?
if (*puzName > 127)
{
rc = RC_SET( NE_XFLM_CONV_ILLEGAL);
goto Exit;
}
else
{
pszEncDefBuf[ uiOffset] = (char)*puzName;
uiOffset++;
}
puzName++;
}
pszEncDefBuf[ uiOffset] = 0;
}
else if( puiCharsReturned)
{
uiOffset = f_unilen( puzName);
}
}
Exit:
if( puiCharsReturned)
{
*puiCharsReturned = uiOffset;
}
return( rc);
}
/***************************************************************************
Desc: Returns encdef object
***************************************************************************/
RCODE F_Dict::getEncDef(
FLMUINT uiEncDefNum,
F_ENCDEF ** ppEncDef)
{
F_ENCDEF * pEncDef = NULL;
if( uiEncDefNum)
{
if( uiEncDefNum >= m_uiLowestEncDefNum &&
uiEncDefNum <= m_uiHighestEncDefNum)
{
pEncDef = m_ppEncDefTbl[ uiEncDefNum - m_uiLowestEncDefNum];
}
}
if( ppEncDef)
{
*ppEncDef = pEncDef;
}
return( pEncDef ? NE_XFLM_OK : RC_SET( NE_XFLM_BAD_ENCDEF_NUM));
}
/***************************************************************************
Desc: Returns the root node of the specified attribute definition
***************************************************************************/
RCODE F_Dict::getDefinitionDoc(
F_Db * pDb,
FLMUINT uiTag,
FLMUINT uiDictId,
F_DOMNode ** ppDoc)
{
RCODE rc = NE_XFLM_OK;
F_DataVector searchKey;
F_DataVector foundKey;
// Need to lookup the document's ID, using its dictionary number
// attribute
if (RC_BAD( rc = searchKey.setUINT( 0, uiTag)))
{
goto Exit;
}
if (RC_BAD( rc = searchKey.setUINT( 1, uiDictId)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->keyRetrieve( XFLM_DICT_NUMBER_INDEX,
&searchKey, XFLM_EXACT, &foundKey)))
{
goto Exit;
}
if( RC_BAD( rc = pDb->getNode( XFLM_DICT_COLLECTION,
foundKey.getDocumentID(), ppDoc)))
{
goto Exit;
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Get the IXD and LFILE information given an index number.
***************************************************************************/
RCODE F_Dict::getIndex(
FLMUINT uiIndexNum,
LFILE ** ppLFile, // [out] optional
IXD ** ppIxd, // [out] optional
FLMBOOL bOfflineOk)
{
RCODE rc = NE_XFLM_OK;
IXD * pIxd = NULL;
if (uiIndexNum >= m_uiLowestIxNum &&
uiIndexNum <= m_uiHighestIxNum)
{
pIxd = m_ppIxdTbl [uiIndexNum - m_uiLowestIxNum];
}
else
{
switch (uiIndexNum)
{
case XFLM_DICT_NUMBER_INDEX:
pIxd = m_pNumberIndex;
break;
case XFLM_DICT_NAME_INDEX:
pIxd = m_pNameIndex;
break;
}
}
if (ppIxd)
{
*ppIxd = pIxd;
}
if (!pIxd)
{
if (ppLFile)
{
*ppLFile = NULL;
}
rc = RC_SET( NE_XFLM_BAD_IX);
goto Exit;
}
else
{
if (ppLFile)
{
*ppLFile = &pIxd->lfInfo;
}
// If the index is suspended the IXD_OFFLINE flag
// will be set, so it is sufficient to just test
// the IXD_OFFLINE for both suspended and offline
// conditions.
if ((pIxd->uiFlags & IXD_OFFLINE) && !bOfflineOk)
{
rc = RC_SET( NE_XFLM_INDEX_OFFLINE);
goto Exit;
}
// An encrypted index is offline if we are in limited mode.
if (pIxd->lfInfo.uiEncId && m_bInLimitedMode && !bOfflineOk)
{
rc = RC_SET( NE_XFLM_INDEX_OFFLINE);
goto Exit;
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Given an index number, returns the next index after that. These
should be returned in ascending numeric order ALWAYS - there are
routines that are depending on this.
***************************************************************************/
IXD * F_Dict::getNextIndex(
FLMUINT uiIndexNum,
FLMBOOL bOkToGetPredefined)
{
IXD * pIxd = NULL;
if (uiIndexNum < m_uiLowestIxNum)
{
uiIndexNum = m_uiLowestIxNum;
}
else
{
uiIndexNum++;
}
while (uiIndexNum >= m_uiLowestIxNum &&
uiIndexNum <= m_uiHighestIxNum)
{
if ((pIxd = m_ppIxdTbl [uiIndexNum - m_uiLowestIxNum]) != NULL)
{
goto Exit;
}
uiIndexNum++;
}
// pIxd better be NULL at this point
flmAssert( pIxd == NULL);
if (bOkToGetPredefined)
{
if (uiIndexNum <= XFLM_DICT_NUMBER_INDEX)
{
pIxd = m_pNumberIndex;
}
else if (uiIndexNum <= XFLM_DICT_NAME_INDEX)
{
pIxd = m_pNameIndex;
}
}
Exit:
return( pIxd);
}
/***************************************************************************
Desc: Given a collection number, returns the next collection after that.
These should be returned in ascending numeric order ALWAYS - there
are routines that are depending on this.
***************************************************************************/
F_COLLECTION * F_Dict::getNextCollection(
FLMUINT uiCollectionNum,
FLMBOOL bOkToGetPredefined)
{
F_COLLECTION * pCollection = NULL;
if (uiCollectionNum < m_uiLowestCollectionNum)
{
uiCollectionNum = m_uiLowestCollectionNum;
}
else
{
uiCollectionNum++;
}
while (uiCollectionNum >= m_uiLowestCollectionNum &&
uiCollectionNum <= m_uiHighestCollectionNum)
{
if ((pCollection = m_ppCollectionTbl [uiCollectionNum -
m_uiLowestCollectionNum]) != NULL)
{
goto Exit; // Will return pLFile
}
uiCollectionNum++;
}
// pCollection better be NULL at this point
flmAssert( pCollection == NULL);
if (bOkToGetPredefined)
{
if( uiCollectionNum <= XFLM_MAINT_COLLECTION)
{
pCollection = m_pMaintCollection;
}
else if( uiCollectionNum <= XFLM_DATA_COLLECTION)
{
pCollection = m_pDataCollection;
}
else if (uiCollectionNum <= XFLM_DICT_COLLECTION)
{
pCollection = m_pDictCollection;
}
}
Exit:
return( pCollection);
}
/****************************************************************************
Desc: Link the dictionary to an F_Database object
NOTE: This routine assumes the global mutex is locked.
****************************************************************************/
void F_Dict::linkToDatabase(
F_Database * pDatabase)
{
if ((m_pNext = pDatabase->m_pDictList) != NULL)
{
m_uiDictSeq = m_pNext->m_uiDictSeq + 1;
m_pNext->m_pPrev = this;
}
else
{
m_uiDictSeq = 1;
}
pDatabase->m_pDictList = this;
m_pDatabase = pDatabase;
}
/****************************************************************************
Desc: Unlink the dictionary from its F_Database object
NOTE: This routine assumes the database mutex is locked.
****************************************************************************/
void F_Dict::unlinkFromDatabase( void)
{
// Unlink the local dictionary from its database - if it is connected
// to one.
if (m_pDatabase)
{
if (m_pPrev)
{
m_pPrev->m_pNext = m_pNext;
}
else
{
m_pDatabase->m_pDictList = m_pNext;
}
if (m_pNext)
{
m_pNext->m_pPrev = m_pPrev;
}
}
// Free the local dictionary and its associated tables.
Release();
}
/****************************************************************************
Desc: Insert an IFD into the chain of IFDs that is headed by ppFirstIfd.
Alter ppFirstIfd if linking at head of chain.
****************************************************************************/
FSTATIC void fdictInsertInIcdChain(
ICD ** ppFirstIcd,
ICD * pIcd)
{
ICD * pTempIcd;
ICD * pPrevInChain;
if (!(*ppFirstIcd))
{
*ppFirstIcd = pIcd;
}
else
{
// Follow the chain and index at the front or rear depending on
// if the attribute or element is required within the set.
pTempIcd = *ppFirstIcd;
if ((pIcd->uiFlags & ICD_REQUIRED_IN_SET) ||
!(pTempIcd->uiFlags & ICD_REQUIRED_IN_SET))
{
pIcd->pNextInChain = pTempIcd;
*ppFirstIcd = pIcd;
}
else
{
// Not required in set and first ICD is required in set.
// Look for first not required ICD in the chain.
pPrevInChain = pTempIcd;
pTempIcd = pTempIcd->pNextInChain;
for (; pTempIcd; pTempIcd = pTempIcd->pNextInChain)
{
if (!(pTempIcd->uiFlags & ICD_REQUIRED_IN_SET))
{
break;
}
pPrevInChain = pTempIcd;
}
pIcd->pNextInChain = pPrevInChain->pNextInChain;
pPrevInChain->pNextInChain = pIcd;
}
}
}
/****************************************************************************
Desc: Remove an ICD from the chain of ICDs that is headed by ppFirstIcd.
Alter ppFirstIcd if it was at the head of the chain.
****************************************************************************/
FSTATIC void fdictRemoveFromIcdChain(
ICD ** ppFirstIcd,
ICD * pIcd)
{
ICD * pTmpIcd;
ICD * pPrevInChain;
pPrevInChain = NULL;
pTmpIcd = *ppFirstIcd;
while (pTmpIcd != pIcd)
{
pPrevInChain = pTmpIcd;
pTmpIcd = pTmpIcd->pNextInChain;
}
// Better have found it!
flmAssert( pTmpIcd == pIcd);
// Unlink from the chain
if (!pPrevInChain)
{
*ppFirstIcd = pIcd->pNextInChain;
}
else
{
pPrevInChain->pNextInChain = pIcd->pNextInChain;
}
}
/****************************************************************************
Desc: Set the first ICD pointer for an extended element - if the element
is currently in memory. Should not need to lock the mutex to do this
because the dictionary should not be in a shared state - only one
F_Db should be pointing to it, and it should be in the middle of
an update transaction where an index definition is being added,
modified, or deleted.
****************************************************************************/
void F_Dict::setExtElementFirstIcd(
FLMUINT uiElementNum,
ICD * pFirstIcd)
{
EXT_ATTR_ELM_DEF * pExtElementDef;
pExtElementDef = getExtElementDef( uiElementNum);
if (pExtElementDef->uiDictNum == uiElementNum)
{
pExtElementDef->attrElmDef.pFirstIcd = pFirstIcd;
}
}
/****************************************************************************
Desc: Set the first ICD pointer for an extended attribute - if the attribute
is currently in memory. Should not need to lock the mutex to do this
because the dictionary should not be in a shared state - only one
F_Db should be pointing to it, and it should be in the middle of
an update transaction where an index definition is being added,
modified, or deleted.
****************************************************************************/
void F_Dict::setExtAttributeFirstIcd(
FLMUINT uiAttributeNum,
ICD * pFirstIcd)
{
EXT_ATTR_ELM_DEF * pExtAttributeDef;
pExtAttributeDef = getExtAttributeDef( uiAttributeNum);
if (pExtAttributeDef->uiDictNum == uiAttributeNum)
{
pExtAttributeDef->attrElmDef.pFirstIcd = pFirstIcd;
}
}
/****************************************************************************
Desc: Link an ICD into its ICD chain.
****************************************************************************/
RCODE F_Dict::linkIcdInChain(
ICD * pIcd)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiLoop;
FLMUINT uiInsertPos;
IX_ITEM * pIxItem;
if (pIcd->uiFlags & ICD_IS_ATTRIBUTE)
{
ATTR_ELM_DEF * pAttributeDef;
if (pIcd->uiDictNum <= FLM_HIGH_FIXED_ATTRIBUTE_NUM)
{
// Link the ICD into its chain, making sure that required attributes
// are first in the chain.
pAttributeDef = getAttributeDef( pIcd->uiDictNum);
// Attribute had better be defined at this point. We should have already
// verified them.
flmAssert( pAttributeDef != NULL);
fdictInsertInIcdChain( &pAttributeDef->pFirstIcd, pIcd);
}
else if (attributeIsReservedTag( pIcd->uiDictNum))
{
// Link the ICD into its chain, making sure that required attributes
// are first in the chain.
pAttributeDef = getReservedAttributeDef( pIcd->uiDictNum);
// Attribute had better be defined at this point. We should have already
// verified them.
flmAssert( pAttributeDef);
fdictInsertInIcdChain( &pAttributeDef->pFirstIcd, pIcd);
}
else
{
// Better be one of our extended attributes
flmAssert( pIcd->uiDictNum >= FLM_LOW_EXT_ATTRIBUTE_NUM);
if ((pIxItem = findIxAttribute( pIcd->uiDictNum,
&uiInsertPos)) == NULL)
{
// Expand the table size if necessary - by 50 elements at a time.
if (m_uiNumIxAttributes == m_uiIxAttributeTblSize)
{
FLMUINT uiNewTblSize = m_uiIxAttributeTblSize + 50;
IX_ITEM * pNewTbl;
if (RC_BAD( rc = f_calloc( sizeof( IX_ITEM) * uiNewTblSize,
&pNewTbl)))
{
goto Exit;
}
if (m_uiIxAttributeTblSize)
{
f_memcpy( pNewTbl, m_pIxAttributeTbl,
sizeof( IX_ITEM) * m_uiIxAttributeTblSize);
f_free( &m_pIxAttributeTbl);
}
m_pIxAttributeTbl = pNewTbl;
m_uiIxAttributeTblSize = uiNewTblSize;
}
// Insert a new IX_ITEM at the specified position.
uiLoop = m_uiNumIxAttributes;
while (uiLoop > uiInsertPos)
{
f_memcpy( &m_pIxAttributeTbl [uiLoop],
&m_pIxAttributeTbl [uiLoop - 1], sizeof( IX_ITEM));
uiLoop--;
}
pIxItem = &m_pIxAttributeTbl [uiInsertPos];
pIxItem->uiDictNum = pIcd->uiDictNum;
pIxItem->pFirstIcd = NULL;
m_uiNumIxAttributes++;
}
fdictInsertInIcdChain( &pIxItem->pFirstIcd, pIcd);
setExtAttributeFirstIcd( pIcd->uiDictNum, pIxItem->pFirstIcd);
}
}
else if (pIcd->uiDictNum == ELM_ROOT_TAG)
{
fdictInsertInIcdChain( &m_pRootIcdList, pIcd);
}
else
{
ATTR_ELM_DEF * pElementDef;
if (pIcd->uiDictNum <= FLM_HIGH_FIXED_ELEMENT_NUM)
{
// Link the ICD into its chain, making sure that required elements
// are first in the chain.
pElementDef = getElementDef( pIcd->uiDictNum);
// Element had better be defined at this point. We should have already
// verified them.
flmAssert( pElementDef != NULL);
fdictInsertInIcdChain( &pElementDef->pFirstIcd, pIcd);
}
else if (elementIsReservedTag( pIcd->uiDictNum))
{
// Link the ICD into its chain, making sure that required elements
// are first in the chain.
pElementDef = getReservedElementDef( pIcd->uiDictNum);
// Element had better be defined at this point. We should have already
// verified them.
flmAssert( pElementDef);
fdictInsertInIcdChain( &pElementDef->pFirstIcd, pIcd);
}
else
{
// Better be one of our extended elements
flmAssert( pIcd->uiDictNum >= FLM_LOW_EXT_ELEMENT_NUM);
if ((pIxItem = findIxElement( pIcd->uiDictNum,
&uiInsertPos)) == NULL)
{
// Expand the table size if necessary - by 50 elements at a time.
if (m_uiNumIxElements == m_uiIxElementTblSize)
{
FLMUINT uiNewTblSize = m_uiIxElementTblSize + 50;
IX_ITEM * pNewTbl;
if (RC_BAD( rc = f_calloc( sizeof( IX_ITEM) * uiNewTblSize,
&pNewTbl)))
{
goto Exit;
}
if (m_uiIxElementTblSize)
{
f_memcpy( pNewTbl, m_pIxElementTbl,
sizeof( IX_ITEM) * m_uiIxElementTblSize);
f_free( &m_pIxElementTbl);
}
m_pIxElementTbl = pNewTbl;
m_uiIxElementTblSize = uiNewTblSize;
}
// Insert a new IX_ITEM at the specified position.
uiLoop = m_uiNumIxElements;
while (uiLoop > uiInsertPos)
{
f_memcpy( &m_pIxElementTbl [uiLoop],
&m_pIxElementTbl [uiLoop - 1], sizeof( IX_ITEM));
uiLoop--;
}
pIxItem = &m_pIxElementTbl [uiInsertPos];
pIxItem->uiDictNum = pIcd->uiDictNum;
pIxItem->pFirstIcd = NULL;
m_uiNumIxElements++;
}
fdictInsertInIcdChain( &pIxItem->pFirstIcd, pIcd);
setExtElementFirstIcd( pIcd->uiDictNum, pIxItem->pFirstIcd);
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Link all of the ICDs of a tree into their proper chains from the
IX_ITEM array or ATTR_ELM_DEF array.
***************************************************************************/
RCODE F_Dict::linkIcds(
ICD * pIcdTree)
{
RCODE rc = NE_XFLM_OK;
ICD * pIcd = pIcdTree;
while (pIcd)
{
if (RC_BAD( rc = linkIcdInChain( pIcd)))
{
goto Exit;
}
if (pIcd->pFirstChild)
{
pIcd = pIcd->pFirstChild;
}
else
{
while (pIcd && !pIcd->pNextSibling)
{
pIcd = pIcd->pParent;
}
if (!pIcd)
{
break;
}
pIcd = pIcd->pNextSibling;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Unlink an ICD from the ICD chain it is in.
****************************************************************************/
void F_Dict::unlinkIcdFromChain(
ICD * pIcd)
{
IX_ITEM * pIxItem;
if (pIcd->uiFlags & ICD_IS_ATTRIBUTE)
{
ATTR_ELM_DEF * pAttributeDef;
// Unlink the ICD from its chain - must find its previous ICD.
if (pIcd->uiDictNum <= FLM_HIGH_FIXED_ATTRIBUTE_NUM)
{
pAttributeDef = getAttributeDef( pIcd->uiDictNum);
// Attribute had better be defined at this point.
flmAssert( pAttributeDef != NULL && pAttributeDef->pFirstIcd);
fdictRemoveFromIcdChain( &pAttributeDef->pFirstIcd, pIcd);
}
else if (attributeIsReservedTag( pIcd->uiDictNum))
{
pAttributeDef = getReservedAttributeDef( pIcd->uiDictNum);
// Attribute had better be defined at this point.
flmAssert( pAttributeDef != NULL && pAttributeDef->pFirstIcd);
fdictRemoveFromIcdChain( &pAttributeDef->pFirstIcd, pIcd);
}
else
{
// Better be one of our extended attributes
flmAssert( pIcd->uiDictNum >= FLM_LOW_EXT_ATTRIBUTE_NUM);
pIxItem = findIxAttribute( pIcd->uiDictNum);
// If there is an ICD, it better be in the IX_ITEM list!
flmAssert( pIxItem && pIxItem->pFirstIcd);
fdictRemoveFromIcdChain( &pIxItem->pFirstIcd, pIcd);
setExtAttributeFirstIcd( pIcd->uiDictNum, pIxItem->pFirstIcd);
}
}
else if (pIcd->uiDictNum == ELM_ROOT_TAG)
{
fdictRemoveFromIcdChain( &m_pRootIcdList, pIcd);
}
else
{
ATTR_ELM_DEF * pElementDef;
// Unlink the ICD from its chain - must find its previous ICD.
if (pIcd->uiDictNum <= FLM_HIGH_FIXED_ELEMENT_NUM)
{
pElementDef = getElementDef( pIcd->uiDictNum);
// Element had better be defined at this point.
flmAssert( pElementDef != NULL && pElementDef->pFirstIcd);
fdictRemoveFromIcdChain( &pElementDef->pFirstIcd, pIcd);
}
else if (elementIsReservedTag( pIcd->uiDictNum))
{
pElementDef = getReservedElementDef( pIcd->uiDictNum);
// Element had better be defined at this point.
flmAssert( pElementDef != NULL && pElementDef->pFirstIcd);
fdictRemoveFromIcdChain( &pElementDef->pFirstIcd, pIcd);
}
else
{
// Better be one of our extended elements
flmAssert( pIcd->uiDictNum >= FLM_LOW_EXT_ATTRIBUTE_NUM);
pIxItem = findIxElement( pIcd->uiDictNum);
// If there is an ICD, it better be in the IX_ITEM list!
flmAssert( pIxItem && pIxItem->pFirstIcd);
fdictRemoveFromIcdChain( &pIxItem->pFirstIcd, pIcd);
setExtElementFirstIcd( pIcd->uiDictNum, pIxItem->pFirstIcd);
}
}
}
/****************************************************************************
Desc: Unlink all ICDs in an ICD tree from the chains they are in.
****************************************************************************/
void F_Dict::unlinkIcds(
ICD * pIcdTree)
{
ICD * pIcd = pIcdTree;
while (pIcd)
{
unlinkIcdFromChain( pIcd);
if (pIcd->pFirstChild)
{
pIcd = pIcd->pFirstChild;
}
else
{
while (pIcd && !pIcd->pNextSibling)
{
pIcd = pIcd->pParent;
}
if (!pIcd)
{
break;
}
pIcd = pIcd->pNextSibling;
}
}
}
/****************************************************************************
Desc: Copies an IXD and all of its ICDs.
****************************************************************************/
RCODE F_Dict::copyIXD(
IXD ** ppDestIxd,
IXD * pSrcIxd)
{
RCODE rc = NE_XFLM_OK;
IXD * pDestIxd;
ICD * pSrcIcd;
ICD * pDestIcd;
ICD * pLastIcd = NULL;
ICD * pTmpIcd;
FLMBOOL bLinkAsChild = FALSE;
if (!pSrcIxd)
{
*ppDestIxd = NULL;
goto Exit;
}
// Allocate the IXD structure
if (RC_BAD( rc = m_dictPool.poolAlloc( sizeof( IXD), (void **)&pDestIxd)))
{
goto Exit;
}
*ppDestIxd = pDestIxd;
f_memcpy( pDestIxd, pSrcIxd, sizeof( IXD));
// Null out the pointers to the ICDs.
pDestIxd->pIcdTree = NULL;
pDestIxd->pFirstKey = NULL;
pDestIxd->pLastKey = NULL;
pDestIxd->pFirstData = NULL;
pDestIxd->pLastData = NULL;
pDestIxd->pFirstContext = NULL;
pDestIxd->pLastContext = NULL;
// Copy the ICDs
pSrcIcd = pSrcIxd->pIcdTree;
while (pSrcIcd)
{
if (RC_BAD( rc = m_dictPool.poolAlloc( sizeof( ICD),
(void **)&pDestIcd)))
{
goto Exit;
}
f_memcpy( pDestIcd, pSrcIcd, sizeof( ICD));
pDestIcd->pNextInChain = NULL;
pDestIcd->pIxd = pDestIxd;
// Link into key component list
if (pDestIcd->uiKeyComponent)
{
pTmpIcd = pDestIxd->pFirstKey;
while (pTmpIcd &&
pDestIcd->uiKeyComponent > pTmpIcd->uiKeyComponent)
{
pTmpIcd = pTmpIcd->pNextKeyComponent;
}
if ((pDestIcd->pNextKeyComponent = pTmpIcd) == NULL)
{
// Link at end of list.
if ((pDestIcd->pPrevKeyComponent = pDestIxd->pLastKey) != NULL)
{
pDestIxd->pLastKey->pNextKeyComponent = pDestIcd;
}
else
{
pDestIxd->pFirstKey = pDestIcd;
}
pDestIxd->pLastKey = pDestIcd;
}
else
{
// Link in front of pTmpIcd
flmAssert( pDestIcd->uiKeyComponent < pTmpIcd->uiKeyComponent);
if ((pDestIcd->pPrevKeyComponent =
pTmpIcd->pPrevKeyComponent) == NULL)
{
pDestIxd->pFirstKey = pDestIcd;
}
else
{
pTmpIcd->pPrevKeyComponent->pNextKeyComponent = pDestIcd;
}
pTmpIcd->pPrevKeyComponent = pDestIcd;
}
}
// Link into the data component list
if (pDestIcd->uiDataComponent)
{
pTmpIcd = pDestIxd->pFirstData;
while (pTmpIcd && pDestIcd->uiDataComponent > pTmpIcd->uiDataComponent)
{
pTmpIcd = pTmpIcd->pNextDataComponent;
}
if ((pDestIcd->pNextDataComponent = pTmpIcd) == NULL)
{
// Link at end of list
if ((pDestIcd->pPrevDataComponent = pDestIxd->pLastData) != NULL)
{
pDestIxd->pLastData->pNextDataComponent = pDestIcd;
}
else
{
pDestIxd->pFirstData = pDestIcd;
}
pDestIxd->pLastData = pDestIcd;
}
else
{
// Link in front of pTmpIcd
flmAssert( pDestIcd->uiDataComponent != pTmpIcd->uiDataComponent);
if ((pDestIcd->pPrevDataComponent =
pTmpIcd->pPrevDataComponent) == NULL)
{
// Link at very front of list
pDestIxd->pFirstData = pDestIcd;
}
else
{
pTmpIcd->pPrevDataComponent->pNextDataComponent = pDestIcd;
}
pTmpIcd->pPrevDataComponent = pDestIcd;
}
}
// Link into the context component list if not a key or data component
if (!pDestIcd->uiDataComponent && !pDestIcd->uiKeyComponent)
{
pTmpIcd = pDestIxd->pFirstContext;
while (pTmpIcd && pDestIcd->uiCdl > pTmpIcd->uiCdl)
{
pTmpIcd = pTmpIcd->pNextKeyComponent;
}
if ((pDestIcd->pNextKeyComponent = pTmpIcd) == NULL)
{
// Link at end of list
if ((pDestIcd->pPrevKeyComponent = pDestIxd->pLastContext) != NULL)
{
pDestIxd->pLastContext->pNextKeyComponent = pDestIcd;
}
else
{
pDestIxd->pFirstContext = pDestIcd;
}
pDestIxd->pLastContext = pDestIcd;
}
else
{
// Link in front of pTmpIcd
flmAssert( pDestIcd->uiCdl != pTmpIcd->uiCdl);
if ((pDestIcd->pPrevKeyComponent =
pTmpIcd->pPrevKeyComponent) == NULL)
{
// Link at very front of list
pDestIxd->pFirstContext = pDestIcd;
}
else
{
pTmpIcd->pPrevKeyComponent->pNextKeyComponent = pDestIcd;
}
pTmpIcd->pPrevKeyComponent = pDestIcd;
}
}
// Link the ICD into the destination ICD tree
pDestIcd->pFirstChild = NULL;
if (!pDestIxd->pIcdTree)
{
pDestIxd->pIcdTree = pDestIcd;
pDestIcd->pParent = NULL;
pDestIcd->pPrevSibling = NULL;
pDestIcd->pNextSibling = NULL;
}
else if (bLinkAsChild)
{
// link as child
pLastIcd->pFirstChild = pDestIcd;
pDestIcd->pParent = pLastIcd;
pDestIcd->pPrevSibling = NULL;
pDestIcd->pNextSibling = NULL;
}
else
{
// link as sibling
pLastIcd->pNextSibling = pDestIcd;
pDestIcd->pPrevSibling = pLastIcd;
pDestIcd->pNextSibling = NULL;
pDestIcd->pParent = pLastIcd->pParent;
}
// Go to the next source ICD
pLastIcd = pDestIcd;
if (pSrcIcd->pFirstChild)
{
pSrcIcd = pSrcIcd->pFirstChild;
bLinkAsChild = TRUE;
}
else
{
while (pSrcIcd && !pSrcIcd->pNextSibling)
{
pLastIcd = pLastIcd->pParent;
pSrcIcd = pSrcIcd->pParent;
}
if (!pSrcIcd)
{
break;
}
bLinkAsChild = FALSE;
pSrcIcd = pSrcIcd->pNextSibling;
}
}
// Put the ICDs into their appropriate ICD chains.
if (RC_BAD( rc = linkIcds( pDestIxd->pIcdTree)))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Copies a collection
****************************************************************************/
FSTATIC RCODE fdictCopyCollection(
F_Pool * pDictPool,
F_COLLECTION ** ppDestCollection,
F_COLLECTION * pSrcCollection)
{
RCODE rc = NE_XFLM_OK;
if (!pSrcCollection)
{
*ppDestCollection = NULL;
}
else
{
if (RC_BAD( rc = pDictPool->poolAlloc( sizeof( F_COLLECTION),
(void **)ppDestCollection)))
{
goto Exit;
}
f_memcpy( *ppDestCollection, pSrcCollection, sizeof( F_COLLECTION));
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Copies a prefix
****************************************************************************/
FSTATIC RCODE fdictCopyPrefix(
F_Pool * pDictPool,
F_PREFIX ** ppDestPrefix,
F_PREFIX * pSrcPrefix)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiPrefixLen;
if (!pSrcPrefix)
{
*ppDestPrefix = NULL;
}
else
{
if (RC_BAD( rc = pDictPool->poolAlloc( sizeof( F_PREFIX),
(void **)ppDestPrefix)))
{
goto Exit;
}
(*ppDestPrefix)->ui64PrefixId = pSrcPrefix->ui64PrefixId;
uiPrefixLen = f_unilen( pSrcPrefix->puzPrefixName);
if( RC_BAD( rc = pDictPool->poolAlloc(
sizeof( FLMUNICODE) * (uiPrefixLen + 1),
(void **)&(*ppDestPrefix)->puzPrefixName)))
{
goto Exit;
}
f_memcpy( (*ppDestPrefix)->puzPrefixName,
pSrcPrefix->puzPrefixName,
(uiPrefixLen + 1) * sizeof( FLMUNICODE));
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Copies an encryption def (F_ENCDEF)
****************************************************************************/
FSTATIC RCODE fdictCopyEncDef(
F_Pool * pDictPool,
F_ENCDEF ** ppDestEncDef,
F_ENCDEF * pSrcEncDef)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiEncDefLen;
if (!pSrcEncDef)
{
*ppDestEncDef = NULL;
}
else
{
if (RC_BAD( rc = pDictPool->poolAlloc( sizeof( F_ENCDEF),
(void **)ppDestEncDef)))
{
goto Exit;
}
(*ppDestEncDef)->ui64EncDefId = pSrcEncDef->ui64EncDefId;
(*ppDestEncDef)->ui64DocumentId = pSrcEncDef->ui64DocumentId;
uiEncDefLen = f_unilen( pSrcEncDef->puzEncDefName);
if( RC_BAD( rc = pDictPool->poolAlloc(
sizeof( FLMUNICODE) * (uiEncDefLen + 1),
(void **)&(*ppDestEncDef)->puzEncDefName)))
{
goto Exit;
}
f_memcpy( (*ppDestEncDef)->puzEncDefName,
pSrcEncDef->puzEncDefName,
(uiEncDefLen + 1) * sizeof( FLMUNICODE));
(*ppDestEncDef)->pCcs = pSrcEncDef->pCcs;
(*ppDestEncDef)->uiEncKeySize = pSrcEncDef->uiEncKeySize;
(*ppDestEncDef)->pCcs->AddRef();
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Clones a dictionary from another one.
****************************************************************************/
RCODE F_Dict::cloneDict(
F_Dict * pSrcDict)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCount;
FLMUINT uiLoop;
FLMBOOL bElementMutexLocked = FALSE;
FLMBOOL bAttributeMutexLocked = FALSE;
resetDict();
// Copy the element definitions.
m_uiLowestElementNum = pSrcDict->m_uiLowestElementNum;
m_uiHighestElementNum = pSrcDict->m_uiHighestElementNum;
if (m_uiHighestElementNum)
{
uiCount = m_uiHighestElementNum - m_uiLowestElementNum + 1;
if (RC_BAD( rc = f_alloc( uiCount * sizeof( ATTR_ELM_DEF),
&m_pElementDefTbl)))
{
goto Exit;
}
f_memcpy( m_pElementDefTbl, pSrcDict->m_pElementDefTbl,
uiCount * sizeof( ATTR_ELM_DEF));
// NULL out every element's pFirstIcd pointer. These will
// be fixed up as indexes are added.
for (uiLoop = 0; uiLoop < uiCount; uiLoop++)
{
m_pElementDefTbl[ uiLoop].pFirstIcd = NULL;
}
}
// Copy the reserved element definitions.
uiCount = XFLM_LAST_RESERVED_ELEMENT_TAG -
XFLM_FIRST_RESERVED_ELEMENT_TAG + 1;
if (RC_BAD( rc = f_alloc( uiCount * sizeof( ATTR_ELM_DEF),
&m_pReservedElementDefTbl)))
{
goto Exit;
}
f_memcpy( m_pReservedElementDefTbl, pSrcDict->m_pReservedElementDefTbl,
uiCount * sizeof( ATTR_ELM_DEF));
// NULL out every element's pFirstIcd pointer. These will
// be fixed up as indexes are added.
for (uiLoop = 0; uiLoop < uiCount; uiLoop++)
{
m_pReservedElementDefTbl [uiLoop].pFirstIcd = NULL;
}
// Copy the extended element definitions, if any
if (pSrcDict->m_pExtElementDefTbl)
{
// Source table's mutex must be locked while copying
f_mutexLock( pSrcDict->m_hExtElementDefMutex);
bElementMutexLocked = TRUE;
m_uiExtElementDefTblSize = pSrcDict->m_uiExtElementDefTblSize;
// Allocate a mutex
if (RC_BAD( rc = f_mutexCreate( &m_hExtElementDefMutex)))
{
goto Exit;
}
// Allocate the array
if (RC_BAD( rc = f_alloc( m_uiExtElementDefTblSize *
sizeof( EXT_ATTR_ELM_DEF), &m_pExtElementDefTbl)))
{
goto Exit;
}
f_memcpy( m_pExtElementDefTbl, pSrcDict->m_pExtElementDefTbl,
m_uiExtElementDefTblSize * sizeof( EXT_ATTR_ELM_DEF));
f_mutexUnlock( pSrcDict->m_hExtElementDefMutex);
bElementMutexLocked = FALSE;
// NULL out every element's pFirstIcd pointer. These will
// be fixed up as indexes are added.
for (uiLoop = 0; uiLoop < m_uiExtElementDefTblSize; uiLoop++)
{
m_pExtElementDefTbl [uiLoop].attrElmDef.pFirstIcd = NULL;
}
}
// Copy the extended element IX_ITEM structures for indexing.
if (pSrcDict->m_pIxElementTbl)
{
m_uiIxElementTblSize = pSrcDict->m_uiIxElementTblSize;
m_uiNumIxElements = pSrcDict->m_uiNumIxElements;
if (RC_BAD( rc = f_alloc( sizeof( IX_ITEM) * m_uiIxElementTblSize,
&m_pIxElementTbl)))
{
goto Exit;
}
f_memcpy( m_pIxElementTbl, pSrcDict->m_pIxElementTbl,
sizeof( IX_ITEM) * m_uiIxElementTblSize);
// NULL out every element's pFirstIcd pointer. These will
// be fixed up as indexes are added.
for (uiLoop = 0; uiLoop < m_uiNumIxElements; uiLoop++)
{
m_pIxElementTbl [uiLoop].pFirstIcd = NULL;
}
}
// Copy the attribute definitions.
m_uiLowestAttributeNum = pSrcDict->m_uiLowestAttributeNum;
m_uiHighestAttributeNum = pSrcDict->m_uiHighestAttributeNum;
if (m_uiHighestAttributeNum)
{
uiCount = m_uiHighestAttributeNum - m_uiLowestAttributeNum + 1;
if (RC_BAD( rc = f_alloc( uiCount * sizeof( ATTR_ELM_DEF),
&m_pAttributeDefTbl)))
{
goto Exit;
}
f_memcpy( m_pAttributeDefTbl, pSrcDict->m_pAttributeDefTbl,
uiCount * sizeof( ATTR_ELM_DEF));
// NULL out every attribute's pFirstIcd pointer. These will
// be fixed up as indexes are added.
for (uiLoop = 0; uiLoop < uiCount; uiLoop++)
{
m_pAttributeDefTbl[ uiLoop].pFirstIcd = NULL;
}
}
// Copy the reserved attribute definitions.
uiCount = XFLM_LAST_RESERVED_ATTRIBUTE_TAG -
XFLM_FIRST_RESERVED_ATTRIBUTE_TAG + 1;
if (RC_BAD( rc = f_alloc( uiCount * sizeof( ATTR_ELM_DEF),
&m_pReservedAttributeDefTbl)))
{
goto Exit;
}
f_memcpy( m_pReservedAttributeDefTbl, pSrcDict->m_pReservedAttributeDefTbl,
uiCount * sizeof( ATTR_ELM_DEF));
// NULL out every attribute's pFirstIcd pointer. These will
// be fixed up as indexes are added.
for (uiLoop = 0; uiLoop < uiCount; uiLoop++)
{
m_pReservedAttributeDefTbl [uiLoop].pFirstIcd = NULL;
}
// Copy the extended attribute definitions, if any
if (pSrcDict->m_pExtAttributeDefTbl)
{
// Source table's mutex must be locked while copying
f_mutexLock( pSrcDict->m_hExtAttributeDefMutex);
bAttributeMutexLocked = TRUE;
m_uiExtAttributeDefTblSize = pSrcDict->m_uiExtAttributeDefTblSize;
// Allocate a mutex
if (RC_BAD( rc = f_mutexCreate( &m_hExtAttributeDefMutex)))
{
goto Exit;
}
// Allocate the array
if (RC_BAD( rc = f_alloc( m_uiExtAttributeDefTblSize *
sizeof( EXT_ATTR_ELM_DEF),
&m_pExtAttributeDefTbl)))
{
goto Exit;
}
f_memcpy( m_pExtAttributeDefTbl, pSrcDict->m_pExtAttributeDefTbl,
m_uiExtAttributeDefTblSize * sizeof( EXT_ATTR_ELM_DEF));
f_mutexUnlock( pSrcDict->m_hExtAttributeDefMutex);
bAttributeMutexLocked = FALSE;
// NULL out every attribute's pFirstIcd pointer. These will
// be fixed up as indexes are added.
for (uiLoop = 0; uiLoop < m_uiExtAttributeDefTblSize; uiLoop++)
{
m_pExtAttributeDefTbl[ uiLoop].attrElmDef.pFirstIcd = NULL;
}
}
// Copy the extended attribute IX_ITEM structures for indexing.
if (pSrcDict->m_pIxAttributeTbl)
{
m_uiIxAttributeTblSize = pSrcDict->m_uiIxAttributeTblSize;
m_uiNumIxAttributes = pSrcDict->m_uiNumIxAttributes;
if (RC_BAD( rc = f_alloc( sizeof( IX_ITEM) * m_uiIxAttributeTblSize,
&m_pIxAttributeTbl)))
{
goto Exit;
}
f_memcpy( m_pIxAttributeTbl, pSrcDict->m_pIxAttributeTbl,
sizeof( IX_ITEM) * m_uiIxAttributeTblSize);
// NULL out every attribute's pFirstIcd pointer. These will
// be fixed up as indexes are added.
for (uiLoop = 0; uiLoop < m_uiNumIxAttributes; uiLoop++)
{
m_pIxAttributeTbl [uiLoop].pFirstIcd = NULL;
}
}
// Copy the pre-defined collections
if (RC_BAD( rc = fdictCopyCollection( &m_dictPool,
&m_pDictCollection,
pSrcDict->m_pDictCollection)))
{
goto Exit;
}
if (RC_BAD( rc = fdictCopyCollection( &m_dictPool,
&m_pDataCollection,
pSrcDict->m_pDataCollection)))
{
goto Exit;
}
if (RC_BAD( rc = fdictCopyCollection( &m_dictPool,
&m_pMaintCollection,
pSrcDict->m_pMaintCollection)))
{
goto Exit;
}
// Collection Table
if ((uiCount = pSrcDict->getCollectionCount( FALSE)) > 0)
{
m_uiLowestCollectionNum = pSrcDict->m_uiLowestCollectionNum;
m_uiHighestCollectionNum = pSrcDict->m_uiHighestCollectionNum;
if (RC_BAD( rc = f_alloc( uiCount * sizeof( F_COLLECTION *),
&m_ppCollectionTbl)))
{
goto Exit;
}
// Copy each F_COLLECTION in the table.
for (uiLoop = 0; uiLoop < uiCount; uiLoop++)
{
if (RC_BAD( rc = fdictCopyCollection( &m_dictPool,
&m_ppCollectionTbl [uiLoop],
pSrcDict->m_ppCollectionTbl [uiLoop])))
{
goto Exit;
}
}
}
// Copy the user-defined prefixes
if ((uiCount = pSrcDict->getPrefixCount()) > 0)
{
m_uiLowestPrefixNum = pSrcDict->m_uiLowestPrefixNum;
m_uiHighestPrefixNum = pSrcDict->m_uiHighestPrefixNum;
if (RC_BAD( rc = f_alloc( uiCount * sizeof( F_PREFIX *),
&m_ppPrefixTbl)))
{
goto Exit;
}
// Copy each F_PREFIX in the table.
for (uiLoop = 0; uiLoop < uiCount; uiLoop++)
{
if (RC_BAD( rc = fdictCopyPrefix( &m_dictPool,
&m_ppPrefixTbl [uiLoop],
pSrcDict->m_ppPrefixTbl [uiLoop])))
{
goto Exit;
}
}
}
// Copy the encryption definitions
if ((uiCount = pSrcDict->getEncDefCount()) > 0)
{
m_uiLowestEncDefNum = pSrcDict->m_uiLowestEncDefNum;
m_uiHighestEncDefNum = pSrcDict->m_uiHighestEncDefNum;
if (RC_BAD( rc = f_alloc( uiCount * sizeof( F_ENCDEF *),
&m_ppEncDefTbl)))
{
goto Exit;
}
// Copy each F_ENCDEF in the table.
for (uiLoop = 0; uiLoop < uiCount; uiLoop++)
{
if (RC_BAD( rc = fdictCopyEncDef( &m_dictPool,
&m_ppEncDefTbl [uiLoop],
pSrcDict->m_ppEncDefTbl [uiLoop])))
{
goto Exit;
}
}
}
// Copy the hard-coded indexes
if (RC_BAD( rc = copyIXD( &m_pNameIndex, pSrcDict->m_pNameIndex)))
{
goto Exit;
}
if (RC_BAD( rc = copyIXD( &m_pNumberIndex, pSrcDict->m_pNumberIndex)))
{
goto Exit;
}
// IXD Table
m_uiLowestIxNum = pSrcDict->m_uiLowestIxNum;
m_uiHighestIxNum = pSrcDict->m_uiHighestIxNum;
// Array of IXD pointers - for user defined indexes only
if ((uiCount = pSrcDict->getIndexCount( FALSE)) > 0)
{
if (RC_BAD( rc = f_alloc( uiCount * sizeof( IXD *),
&m_ppIxdTbl)))
{
goto Exit;
}
// Copy each IXD in the table.
for (uiLoop = 0; uiLoop < uiCount; uiLoop++)
{
if (RC_BAD( rc = copyIXD( &m_ppIxdTbl [uiLoop],
pSrcDict->m_ppIxdTbl [uiLoop])))
{
goto Exit;
}
}
}
// Copy the name table
if (RC_BAD( rc = allocNameTable()))
{
goto Exit;
}
if (RC_BAD( rc = m_pNameTable->cloneNameTable( pSrcDict->m_pNameTable)))
{
goto Exit;
}
// See if we can get the limited mode flag from the database file instead
// of copying it from the source dictionary.
if (pSrcDict->m_pDatabase)
{
m_bInLimitedMode = pSrcDict->m_pDatabase->inLimitedMode();
}
else
{
m_bInLimitedMode = pSrcDict->m_bInLimitedMode;
}
Exit:
if (bElementMutexLocked)
{
f_mutexUnlock( pSrcDict->m_hExtElementDefMutex);
}
if (bAttributeMutexLocked)
{
f_mutexUnlock( pSrcDict->m_hExtAttributeDefMutex);
}
return( rc);
}
/***************************************************************************
Desc: This routine checks to see if an element is referenced in an index
definition.
***************************************************************************/
RCODE F_Dict::checkElementReferences(
FLMUINT uiElementNum
)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiIxdCount;
FLMUINT uiIxdLoop;
IXD * pIxd;
ICD * pIcd;
// Look through all ICDs in all IXDs.
uiIxdCount = getIndexCount( FALSE);
for (uiIxdLoop = 0; uiIxdLoop < uiIxdCount; uiIxdLoop++)
{
if ((pIxd = m_ppIxdTbl [uiIxdLoop]) != NULL)
{
// Loop through all of the index's ICDs.
pIcd = pIxd->pIcdTree;
while (pIcd)
{
if (!(pIcd->uiFlags & ICD_IS_ATTRIBUTE) &&
pIcd->uiDictNum == uiElementNum)
{
rc = RC_SET( NE_XFLM_CANNOT_DEL_ELEMENT);
goto Exit;
}
if (pIcd->pFirstChild)
{
pIcd = pIcd->pFirstChild;
}
else
{
while (pIcd && !pIcd->pNextSibling)
{
pIcd = pIcd->pParent;
}
if (!pIcd)
{
break;
}
pIcd = pIcd->pNextSibling;
}
}
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc: This routine checks to see if an attribute is referenced in an index
definition.
***************************************************************************/
RCODE F_Dict::checkAttributeReferences(
FLMUINT uiAttributeNum
)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiIxdCount;
FLMUINT uiIxdLoop;
IXD * pIxd;
ICD * pIcd;
// Look through all ICDs in all IXDs.
uiIxdCount = getIndexCount( FALSE);
for (uiIxdLoop = 0; uiIxdLoop < uiIxdCount; uiIxdLoop++)
{
if ((pIxd = m_ppIxdTbl [uiIxdLoop]) != NULL)
{
// Loop through all of the index's ICDs.
pIcd = pIxd->pIcdTree;
while (pIcd)
{
if ((pIcd->uiFlags & ICD_IS_ATTRIBUTE) &&
pIcd->uiDictNum == uiAttributeNum)
{
rc = RC_SET( NE_XFLM_CANNOT_DEL_ATTRIBUTE);
goto Exit;
}
if (pIcd->pFirstChild)
{
pIcd = pIcd->pFirstChild;
}
else
{
while (pIcd && !pIcd->pNextSibling)
{
pIcd = pIcd->pParent;
}
if (!pIcd)
{
break;
}
pIcd = pIcd->pNextSibling;
}
}
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc: This routine checks to see if a collection is referenced in an index
definition.
***************************************************************************/
RCODE F_Dict::checkCollectionReferences(
FLMUINT uiCollectionNum
)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiIxdCount;
FLMUINT uiIxdLoop;
IXD * pIxd;
// Look through all IXDs
uiIxdCount = getIndexCount( FALSE);
for (uiIxdLoop = 0; uiIxdLoop < uiIxdCount; uiIxdLoop++)
{
if ((pIxd = m_ppIxdTbl [uiIxdLoop]) != NULL)
{
if (pIxd->uiCollectionNum == uiCollectionNum)
{
rc = RC_SET( NE_XFLM_MUST_DELETE_INDEXES);
goto Exit;
}
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Reallocate a field, index, or collection table. Note that any new
slots in the table will be zeroed out.
***************************************************************************/
RCODE F_Dict::reallocTbl(
FLMUINT uiNewId,
FLMUINT uiElementSize,
void ** ppvTbl,
FLMUINT * puiLowest,
FLMUINT * puiHighest,
FLMUINT uiAdjustFactor,
FLMUINT uiMaxId
)
{
RCODE rc = NE_XFLM_OK;
void * pvNewTbl;
FLMUINT uiLowest = *puiLowest;
FLMUINT uiOldLowest = uiLowest;
FLMUINT uiHighest = *puiHighest;
FLMUINT uiOldCount;
FLMUINT uiNewCount;
if (!uiHighest)
{
uiOldCount = 0;
if (uiNewId <= uiAdjustFactor)
{
uiLowest = 1;
}
else
{
uiLowest = uiNewId - uiAdjustFactor;
}
if (uiNewId >= uiMaxId - uiAdjustFactor)
{
uiHighest = uiMaxId;
}
else
{
uiHighest = uiNewId + uiAdjustFactor;
}
}
else
{
uiOldCount = uiHighest - uiLowest + 1;
if (uiNewId < uiLowest)
{
if (uiNewId <= uiAdjustFactor)
{
uiLowest = 1;
}
else
{
uiLowest = uiNewId - uiAdjustFactor;
}
}
else
{
if (uiNewId >= uiMaxId - uiAdjustFactor)
{
uiHighest = uiMaxId;
}
else
{
uiHighest = uiNewId + uiAdjustFactor;
}
}
}
// Reallocate the table.
uiNewCount = uiHighest - uiLowest + 1;
if (RC_BAD( rc = f_calloc( uiNewCount * uiElementSize,
&pvNewTbl)))
{
goto Exit;
}
if (uiOldCount)
{
f_memcpy( (FLMBYTE *)pvNewTbl +
uiElementSize * (uiOldLowest - uiLowest),
*ppvTbl, uiOldCount * uiElementSize);
}
f_free( ppvTbl);
*ppvTbl = pvNewTbl;
*puiLowest = uiLowest;
*puiHighest = uiHighest;
Exit:
return( rc);
}
/***************************************************************************
Desc: Maps a string to an element or attribute data type.
***************************************************************************/
RCODE fdictGetDataType(
char * pszDataType,
FLMUINT * puiDataType)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiDataType;
// Parse the type keyword - only one type allowed.
for (uiDataType = 0; uiDataType < XFLM_NUM_OF_TYPES; uiDataType++)
{
if (f_stricmp( pszDataType, fdictDataTypes [uiDataType]) == 0)
{
*puiDataType = uiDataType;
goto Exit; // Will return NE_XFLM_OK
}
}
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_DATA_TYPE);
Exit:
return( rc);
}
/***************************************************************************
Desc: Maps a string to an element or attribute data type.
***************************************************************************/
const char * fdictGetDataTypeStr(
FLMUINT uiDataType
)
{
if( uiDataType > XFLM_NUM_OF_TYPES)
{
return( NULL);
}
return( fdictDataTypes[ uiDataType]);
}
/***************************************************************************
Desc: Maps a string to an element or attribute state.
***************************************************************************/
RCODE fdictGetState(
const char * pszState,
FLMUINT * puiState)
{
RCODE rc = NE_XFLM_OK;
if (f_stricmp( pszState, XFLM_CHECKING_OPTION_STR) == 0)
{
*puiState = ATTR_ELM_STATE_CHECKING;
}
else if (f_stricmp( pszState, XFLM_PURGE_OPTION_STR) == 0)
{
*puiState = ATTR_ELM_STATE_PURGE;
}
else if (f_stricmp( pszState, XFLM_ACTIVE_OPTION_STR) == 0)
{
*puiState = ATTR_ELM_STATE_ACTIVE;
}
else
{
rc = RC_SET( NE_XFLM_ILLEGAL_STATE);
goto Exit;
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Maps a string to an index state.
***************************************************************************/
RCODE fdictGetIndexState(
const char * pszState,
FLMUINT * puiState)
{
RCODE rc = NE_XFLM_OK;
if (f_stricmp( pszState, XFLM_INDEX_SUSPENDED_STR) == 0)
{
*puiState = IXD_SUSPENDED | IXD_OFFLINE;
}
else if (f_stricmp( pszState, XFLM_INDEX_OFFLINE_STR) == 0)
{
*puiState = IXD_OFFLINE;
}
else if (!pszState [0] ||
f_stricmp( pszState, XFLM_INDEX_ONLINE_STR) == 0)
{
*puiState = 0;
}
else
{
rc = RC_SET( NE_XFLM_ILLEGAL_STATE);
goto Exit;
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Determine if an element name is legal - formatwise
***************************************************************************/
FINLINE RCODE fdictLegalElementName(
FLMUNICODE * // puzElementName
)
{
//VISIT: Need to fill this out - could return NE_XFLM_ILLEGAL_ELEMENT_NAME
return( NE_XFLM_OK);
}
/***************************************************************************
Desc: Determine if an attribute name is legal - formatwise
***************************************************************************/
FINLINE RCODE fdictLegalAttributeName(
FLMUNICODE * puzAttributeName
)
{
if (*puzAttributeName == '/' && *(puzAttributeName + 1) == 0)
{
return( RC_SET( NE_XFLM_ILLEGAL_ATTRIBUTE_NAME));
}
//VISIT: Need to fill this out - could return NE_XFLM_ILLEGAL_ATTRIBUTE_NAME
return( NE_XFLM_OK);
}
/***************************************************************************
Desc: Determine if an element number is legal
***************************************************************************/
FINLINE RCODE fdictLegalElementNumber(
FLMUINT uiElementNumber,
FLMBOOL bAllowReserved)
{
return( (uiElementNumber > 0 && uiElementNumber <= XFLM_MAX_ELEMENT_NUM) ||
(bAllowReserved &&
uiElementNumber >= XFLM_FIRST_RESERVED_ELEMENT_TAG &&
uiElementNumber <= XFLM_LAST_RESERVED_ELEMENT_TAG)
? NE_XFLM_OK
: RC_SET( NE_XFLM_ILLEGAL_ELEMENT_NUMBER));
}
/***************************************************************************
Desc: Determine if an attribute number is legal
***************************************************************************/
FINLINE RCODE fdictLegalAttributeNumber(
FLMUINT uiAttributeNumber,
FLMBOOL bAllowReserved)
{
return( (uiAttributeNumber > 0 &&
uiAttributeNumber <= XFLM_MAX_ATTRIBUTE_NUM) ||
(bAllowReserved &&
uiAttributeNumber >= XFLM_FIRST_RESERVED_ATTRIBUTE_TAG &&
uiAttributeNumber <= XFLM_LAST_RESERVED_ATTRIBUTE_TAG)
? NE_XFLM_OK
: RC_SET( NE_XFLM_ILLEGAL_ATTRIBUTE_NUMBER));
}
/***************************************************************************
Desc: Retrieve a dictionary. If there is no dictionary, open it first.
***************************************************************************/
RCODE F_Db::getDictionary(
F_Dict ** ppDict)
{
RCODE rc = NE_XFLM_OK;
if (!m_pDict)
{
if (RC_BAD( rc = dictOpen()))
{
goto Exit;
}
}
*ppDict = m_pDict;
Exit:
return rc;
}
/***************************************************************************
Desc: Change an element's or attribute's state.
***************************************************************************/
RCODE F_Db::changeItemState(
FLMUINT uiDictType,
FLMUINT uiDictNum,
const char * pszState)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiNewState;
FLMBOOL bStartedTrans = FALSE;
F_DataVector srchKey;
F_DataVector foundKey;
F_DOMNode * pNode = NULL;
F_DOMNode * pAttr = NULL;
F_DOMNode * pChangeCountAttr = NULL;
F_DOMNode * pTrackerDoc = NULL;
FLMUINT64 ui64DocumentId;
FLMUINT64 ui64Count;
FLMBOOL bMustAbortOnError = FALSE;
F_AttrElmInfo defInfo;
if (uiDictType != ELM_ELEMENT_TAG && uiDictType != ELM_ATTRIBUTE_TAG)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_PARM);
goto Exit;
}
if (RC_BAD( rc = fdictGetState( pszState, &uiNewState)))
{
goto Exit;
}
if (RC_BAD( rc = checkState( __FILE__, __LINE__)))
{
goto Exit;
}
if (m_eTransType != XFLM_NO_TRANS)
{
if (!okToCommitTrans())
{
rc = RC_SET( NE_XFLM_ABORT_TRANS);
goto Exit;
}
else if (m_eTransType == XFLM_READ_TRANS)
{
rc = RC_SET( NE_XFLM_ILLEGAL_TRANS_OP);
goto Exit;
}
}
else
{
// Need to have an update transaction going.
if (RC_BAD( rc = beginTrans( XFLM_UPDATE_TRANS)))
{
goto Exit;
}
bStartedTrans = TRUE;
}
// Commit any keys in the KREF buffers.
if (RC_BAD( rc = keysCommit( FALSE)))
{
goto Exit;
}
// See if the element or attribute is defined, and get its
// current state
if (uiDictType == ELM_ELEMENT_TAG)
{
if (RC_BAD( rc = m_pDict->getElement( this, uiDictNum, &defInfo)))
{
goto Exit;
}
// Nothing to change if the state does not change.
if (uiNewState == defInfo.m_uiState)
{
goto Exit;
}
if (elementIsReservedTag( uiDictNum))
{
rc = RC_SET( NE_XFLM_CANNOT_MOD_ELEMENT_STATE);
goto Exit;
}
}
else
{
if (RC_BAD( rc = m_pDict->getAttribute( this, uiDictNum, &defInfo)))
{
goto Exit;
}
// Nothing to change if the state does not change.
if (uiNewState == defInfo.m_uiState)
{
goto Exit;
}
if (attributeIsReservedTag( uiDictNum))
{
rc = RC_SET( NE_XFLM_CANNOT_MOD_ATTRIBUTE_STATE);
goto Exit;
}
}
// Check the legal state changes that can be made by external callers
// of this routine
if (!m_bItemStateUpdOk)
{
switch (defInfo.m_uiState)
{
case ATTR_ELM_STATE_ACTIVE:
{
if( uiNewState != ATTR_ELM_STATE_CHECKING &&
uiNewState != ATTR_ELM_STATE_PURGE)
{
rc = RC_SET( NE_XFLM_ILLEGAL_STATE_CHANGE);
goto Exit;
}
// Add a task to the tracker container so the maintenance thread
// will sweep the database
if( !(m_uiFlags & FDB_SWEEP_SCHEDULED))
{
if( RC_BAD( rc = createRootNode( XFLM_MAINT_COLLECTION,
ELM_SWEEP_TAG, ELEMENT_NODE, &pTrackerDoc)))
{
goto Exit;
}
if( RC_BAD( rc = pTrackerDoc->setAttributeValueUINT64( this,
ATTR_TRANSACTION_TAG, m_ui64CurrTransID)))
{
goto Exit;
}
if( RC_BAD( rc = pTrackerDoc->addModeFlags(
this, FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
if( RC_BAD( rc = documentDone( pTrackerDoc)))
{
goto Exit;
}
f_semSignal( m_pDatabase->m_hMaintSem);
m_uiFlags |= FDB_SWEEP_SCHEDULED;
}
break;
}
case ATTR_ELM_STATE_CHECKING:
case ATTR_ELM_STATE_PURGE:
{
if (uiNewState != ATTR_ELM_STATE_ACTIVE)
{
rc = RC_SET( NE_XFLM_ILLEGAL_STATE_CHANGE);
goto Exit;
}
break;
}
default:
{
// Only other old state is ATTR_ELM_STATE_UNUSED, and it
// can be changed to any other state.
break;
}
}
}
bMustAbortOnError = TRUE;
// To do a state change, must create a new dictionary
if( !(m_uiFlags & FDB_UPDATED_DICTIONARY))
{
if( RC_BAD( rc = dictClone()))
{
goto Exit;
}
}
// Find the element's document
if( RC_BAD( rc = srchKey.setUINT( 0, uiDictType)))
{
goto Exit;
}
if( RC_BAD( rc = srchKey.setUINT( 1, uiDictNum)))
{
goto Exit;
}
if( RC_BAD( rc = keyRetrieve( XFLM_DICT_NUMBER_INDEX,
&srchKey, XFLM_EXACT, &foundKey)))
{
if( rc == NE_XFLM_NOT_FOUND)
{
// We should have found the thing! It should have
// already been indexed!
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
// Read the root node of the document
ui64DocumentId = foundKey.getDocumentID();
if (RC_BAD( rc = getNode( XFLM_DICT_COLLECTION, ui64DocumentId, &pNode)))
{
if (rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
// We should have found the thing! It should have
// already been indexed!
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
// Find the state attribute
if (RC_BAD( rc = pNode->getAttribute( this, ATTR_STATE_TAG,
(IF_DOMNode **)&pAttr)))
{
if (rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
// Create the attribute since it was not found
if (RC_BAD( rc = pNode->createAttribute( this, ATTR_STATE_TAG,
(IF_DOMNode **)&pAttr)))
{
goto Exit;
}
}
else
{
// Unfreeze the attribute state
if (RC_BAD( rc = pAttr->removeModeFlags(
this, FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
}
// Set the attribute state
if (RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pszState)))
{
goto Exit;
}
// Freeze the attribute state
if( RC_BAD( rc = pAttr->addModeFlags( this,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
// Find the state change count attribute
if (RC_BAD( rc = pNode->getAttribute( this, ATTR_STATE_CHANGE_COUNT_TAG,
(IF_DOMNode **)&pChangeCountAttr)))
{
if (rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
// Create the attribute since it was not found
if (RC_BAD( rc = pNode->createAttribute( this,
ATTR_STATE_CHANGE_COUNT_TAG,
(IF_DOMNode **)&pChangeCountAttr)))
{
goto Exit;
}
ui64Count = 0;
}
else
{
// Unfreeze the attribute state
if (RC_BAD( rc = pChangeCountAttr->removeModeFlags(
this, FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
if (RC_BAD( rc = pChangeCountAttr->getUINT64( this, &ui64Count)))
{
goto Exit;
}
}
// Increment the state change count.
if (RC_BAD( rc = pChangeCountAttr->setUINT64( this, ui64Count + 1)))
{
goto Exit;
}
// Freeze the attribute state change count.
if( RC_BAD( rc = pChangeCountAttr->addModeFlags( this,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
// Set the state in the dictionary
if (uiDictType == ELM_ELEMENT_TAG)
{
if (uiDictNum <= FLM_HIGH_FIXED_ELEMENT_NUM)
{
ATTR_ELM_DEF * pElementDef;
if ((pElementDef = m_pDict->getElementDef( uiDictNum)) != NULL)
{
attrElmSetState( pElementDef, uiNewState);
}
}
else
{
EXT_ATTR_ELM_DEF * pExtElementDef;
// Better be one of our extended elements - cannot change
// state on reserved elements.
flmAssert( elementIsUserDefined( uiDictNum));
// No need to lock the mutex, because no other threads can
// be accessing it right now.
if (m_pDict->m_pExtElementDefTbl)
{
pExtElementDef = m_pDict->getExtElementDef( uiDictNum);
if (pExtElementDef->uiDictNum == uiDictNum)
{
attrElmSetState( &pExtElementDef->attrElmDef, uiNewState);
}
}
}
}
else
{
if (uiDictNum <= FLM_HIGH_FIXED_ATTRIBUTE_NUM)
{
ATTR_ELM_DEF * pAttributeDef;
if ((pAttributeDef = m_pDict->getAttributeDef( uiDictNum)) != NULL)
{
attrElmSetState( pAttributeDef, uiNewState);
}
}
else
{
EXT_ATTR_ELM_DEF * pExtAttributeDef;
// Better be one of our extended attributes - cannot change
// state on reserved attributes.
flmAssert( attributeIsUserDefined( uiDictNum));
// No need to lock the mutex, because no other threads can
// be accessing it right now.
if (m_pDict->m_pExtAttributeDefTbl)
{
pExtAttributeDef = m_pDict->getExtAttributeDef( uiDictNum);
if (pExtAttributeDef->uiDictNum == uiDictNum)
{
attrElmSetState( &pExtAttributeDef->attrElmDef, uiNewState);
}
}
}
}
Exit:
if( pNode)
{
pNode->Release();
}
if( pAttr)
{
pAttr->Release();
}
if( pTrackerDoc)
{
pTrackerDoc->Release();
}
if( pChangeCountAttr)
{
pChangeCountAttr->Release();
}
if( bStartedTrans)
{
rc = commitTrans( 0, FALSE);
}
else if( RC_BAD( rc) && bMustAbortOnError)
{
setMustAbortTrans( rc);
}
return( rc);
}
/***************************************************************************
Desc: Retrieve an element or attribute definition - get name, data type,
state, and namespace.
***************************************************************************/
RCODE F_Db::getElmAttrInfo(
FLMUINT uiType,
FLMUINT64 ui64DocumentID,
F_AttrElmInfo * pDefInfo,
FLMBOOL bOpeningDict,
FLMBOOL bDeleting)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pDocNode = NULL;
F_DOMNode * pAttr = NULL;
F_CachedNode * pCachedDocNode;
char szTmpBuf[ 80];
FLMUINT uiNameId;
FLMUNICODE * puzName = NULL;
FLMBOOL bNamespaceDecl = FALSE;
FLMBOOL bHadUniqueSubElementTag = FALSE;
// Retrieve the root element of the definition
if (RC_BAD( rc = getNode( XFLM_DICT_COLLECTION, ui64DocumentID, &pDocNode)))
{
goto Exit;
}
flmAssert( pDocNode->getNodeType() == ELEMENT_NODE);
pDefInfo->m_pDocNode = (IF_DOMNode *)pDocNode;
pDocNode->AddRef();
pCachedDocNode = pDocNode->m_pCachedNode;
uiNameId = pCachedDocNode->getNameId();
if( uiType != uiNameId)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
// Cycle through the attributes on the root of the definition
if( pCachedDocNode->hasAttributes())
{
if( RC_BAD( rc = pDocNode->getFirstAttribute(
this, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
for( ;;)
{
if( RC_BAD( rc = pAttr->getNameId( this, &uiNameId)))
{
goto Exit;
}
switch( uiNameId)
{
case ATTR_NAME_TAG:
{
pDefInfo->m_pNameAttr = (IF_DOMNode *)pAttr;
pAttr->AddRef();
if( RC_BAD( rc = pAttr->getUnicode( this, &puzName)))
{
goto Exit;
}
if( isXMLNS( puzName) &&
(puzName [5] == 0 ||
(puzName [5] == ':' && puzName [6] != 0)))
{
if( uiType == ELM_ATTRIBUTE_TAG)
{
pDefInfo->m_uiFlags |= ATTR_ELM_NS_DECL;
bNamespaceDecl = TRUE;
}
else
{
rc = RC_SET( NE_XFLM_ILLEGAL_ELEMENT_NAME);
goto Exit;
}
}
if (uiType == ELM_ELEMENT_TAG)
{
if (RC_BAD( rc = fdictLegalElementName( puzName)))
{
goto Exit;
}
}
else
{
if (RC_BAD( rc = fdictLegalAttributeName( puzName)))
{
goto Exit;
}
}
// Put a freeze on name if we are not deleting.
// Modify is allowed, but delete is not.
if( !bDeleting && !bOpeningDict)
{
if( RC_BAD( rc = pAttr->addModeFlags(
this, FDOM_CANNOT_DELETE)))
{
goto Exit;
}
}
break;
}
case ATTR_TARGET_NAMESPACE_TAG:
{
pDefInfo->m_pTargetNamespaceAttr = (IF_DOMNode *)pAttr;
pAttr->AddRef();
break;
}
case ATTR_TYPE_TAG:
{
if( RC_BAD( rc = pAttr->getUTF8( this, (FLMBYTE *)szTmpBuf,
sizeof( szTmpBuf), 0, ~((FLMUINT)0))))
{
goto Exit;
}
if (RC_BAD( rc = fdictGetDataType(
(char *)szTmpBuf, &pDefInfo->m_uiDataType)))
{
goto Exit;
}
if (uiType == ELM_ATTRIBUTE_TAG &&
pDefInfo->m_uiDataType == XFLM_NODATA_TYPE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_DATA_TYPE);
goto Exit;
}
break;
}
case ATTR_STATE_TAG:
{
if (RC_BAD( rc = pAttr->getUTF8(
this, (FLMBYTE *)szTmpBuf,
sizeof( szTmpBuf), 0, ~((FLMUINT)0))))
{
goto Exit;
}
if (RC_BAD( rc = fdictGetState( (char *)szTmpBuf,
&pDefInfo->m_uiState)))
{
goto Exit;
}
// Freeze the state - can only be changed by an explicit
// call to changeItemState.
if( !bOpeningDict)
{
if( RC_BAD( rc = pAttr->addModeFlags( this,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
}
break;
}
case ATTR_DICT_NUMBER_TAG:
{
if (RC_BAD( rc = pAttr->getUINT( this, &pDefInfo->m_uiDictNum)))
{
goto Exit;
}
if (uiType == ELM_ELEMENT_TAG)
{
if (RC_BAD( rc = fdictLegalElementNumber(
pDefInfo->m_uiDictNum, FALSE)))
{
goto Exit;
}
}
else
{
if (RC_BAD( rc = fdictLegalAttributeNumber(
pDefInfo->m_uiDictNum, FALSE)))
{
goto Exit;
}
}
break;
}
case ATTR_UNIQUE_SUB_ELEMENTS_TAG:
{
// This one is only allowed on element definitions.
if (uiType != ELM_ELEMENT_TAG)
{
rc = RC_SET( NE_XFLM_ILLEGAL_UNIQUE_SUB_ELEMENT_VALUE);
goto Exit;
}
bHadUniqueSubElementTag = TRUE;
if( RC_BAD( rc = pAttr->getUTF8( this, (FLMBYTE *)szTmpBuf,
sizeof( szTmpBuf), 0, ~((FLMUINT)0))))
{
goto Exit;
}
if (f_stricmp( szTmpBuf, "yes") == 0 ||
f_stricmp( szTmpBuf, "true") == 0 ||
f_stricmp( szTmpBuf, "1") == 0 ||
f_stricmp( szTmpBuf, "on") == 0 ||
f_stricmp( szTmpBuf, "enable") == 0)
{
pDefInfo->m_uiFlags |= ATTR_ELM_UNIQUE_SUBELMS;
}
else if (f_stricmp( szTmpBuf, "no") != 0 &&
f_stricmp( szTmpBuf, "false") != 0 &&
f_stricmp( szTmpBuf, "0") != 0 &&
f_stricmp( szTmpBuf, "off") != 0 &&
f_stricmp( szTmpBuf, "disable") != 0)
{
rc = RC_SET( NE_XFLM_ILLEGAL_UNIQUE_SUB_ELEMENT_VALUE);
goto Exit;
}
// Freeze the state - cannot be changed or deleted.
if( !bDeleting && !bOpeningDict)
{
if( RC_BAD( rc = pAttr->addModeFlags( this,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
}
break;
}
default:
{
// Ignore all other attributes
break;
}
}
if( RC_BAD( rc = pAttr->getNextSibling( this, (IF_DOMNode **)&pAttr)))
{
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
}
}
// Make sure we had both a name and number specified
if (!pDefInfo->m_pNameAttr)
{
rc = (RCODE)(uiType == ELM_ELEMENT_TAG
? RC_SET( NE_XFLM_MISSING_ELEMENT_NAME)
: RC_SET( NE_XFLM_MISSING_ATTRIBUTE_NAME));
goto Exit;
}
if (!pDefInfo->m_uiDictNum)
{
rc = (RCODE)(uiType == ELM_ELEMENT_TAG
? RC_SET( NE_XFLM_MISSING_ELEMENT_NUMBER)
: RC_SET( NE_XFLM_MISSING_ATTRIBUTE_NUMBER));
goto Exit;
}
if (!bDeleting && bNamespaceDecl &&
pDefInfo->m_uiDataType != XFLM_TEXT_TYPE)
{
rc = RC_SET( NE_XFLM_ILLEGAL_NAMESPACE_DECL_DATATYPE);
goto Exit;
}
// If we didn't have a unique sub-element tag, set one - better only
// be missing when we first add the element definition.
if (!bHadUniqueSubElementTag && uiType == ELM_ELEMENT_TAG)
{
flmAssert( !bOpeningDict && !bDeleting);
// Set attribute and freeze it if it was missing.
if (RC_BAD( rc = pDocNode->createAttribute(
this, ATTR_UNIQUE_SUB_ELEMENTS_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)"no")))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->addModeFlags( this,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
}
else if (pDefInfo->m_uiFlags & ATTR_ELM_UNIQUE_SUBELMS)
{
// If sub-elements must be unique, the data type has to be
// nodata.
if (pDefInfo->m_uiDataType != XFLM_NODATA_TYPE)
{
rc = RC_SET( NE_XFLM_DATA_TYPE_MUST_BE_NO_DATA);
goto Exit;
}
}
Exit:
if( pDocNode)
{
pDocNode->Release();
}
if( pAttr)
{
pAttr->Release();
}
if( puzName)
{
f_free( &puzName);
}
return( rc);
}
/***************************************************************************
Desc: Add, modify, or delete an element definition in the dictionary.
***************************************************************************/
RCODE F_Dict::updateElementDef(
F_Db * pDb,
FLMUINT64 ui64DocumentID,
FLMUINT uiElementNum,
FLMBOOL bOpeningDict,
FLMBOOL bDeleting
)
{
RCODE rc = NE_XFLM_OK;
ATTR_ELM_DEF * pElementDef;
EXT_ATTR_ELM_DEF * pExtElementDef;
FLMUNICODE * puzElementName = NULL;
FLMUNICODE * puzNamespace = NULL;
IX_ITEM * pIxElement;
F_AttrElmInfo defInfo;
F_DOMNode * pTmpNode = NULL;
if (bDeleting)
{
flmAssert( uiElementNum);
// NOTE: It is possible that the element may not be in the
// element table yet, because dictDocumentDone had not been
// called to put it in there, but we are calling dictDocumentDone
// to remove it.
// Remove the tag number from the name table
m_pNameTable->removeTag( ELM_ELEMENT_TAG, uiElementNum);
if (uiElementNum <= FLM_HIGH_FIXED_ELEMENT_NUM)
{
if ((pElementDef = getElementDef( uiElementNum)) != NULL)
{
pElementDef->uiFlags = 0; // Unused slot
pElementDef->pFirstIcd = NULL;
}
}
else
{
// Better be one of our extended elements - cannot delete
// reserved elements.
flmAssert( elementIsUserDefined( uiElementNum));
// No need to lock the mutex, because no other threads can
// be accessing it right now.
if (m_pExtElementDefTbl)
{
pExtElementDef = getExtElementDef( uiElementNum);
if (pExtElementDef->uiDictNum == uiElementNum)
{
pExtElementDef->uiDictNum = 0;
pExtElementDef->attrElmDef.uiFlags = 0;
pExtElementDef->attrElmDef.pFirstIcd = NULL;
}
}
}
goto Exit;
}
if (RC_BAD( rc = pDb->getElmAttrInfo( ELM_ELEMENT_TAG,
ui64DocumentID, &defInfo,
bOpeningDict, bDeleting)))
{
goto Exit;
}
if (!uiElementNum)
{
uiElementNum = defInfo.m_uiDictNum;
}
flmAssert( uiElementNum == defInfo.m_uiDictNum);
// Get the element name
if( RC_BAD( rc = defInfo.m_pNameAttr->getUnicode(
pDb, &puzElementName)))
{
goto Exit;
}
if( RC_BAD( rc = fdictLegalElementName( puzElementName)))
{
goto Exit;
}
// Get the element's namespace
if( defInfo.m_pTargetNamespaceAttr)
{
if( RC_BAD( rc = defInfo.m_pTargetNamespaceAttr->getUnicode(
pDb, &puzNamespace)))
{
goto Exit;
}
}
// Add to the tag table, unless we already have our quota of
// element names. Remove the tag by number first, in case
// it was renamed.
if (!bOpeningDict)
{
m_pNameTable->removeTag( ELM_ELEMENT_TAG, uiElementNum);
}
if (RC_BAD( rc = m_pNameTable->addTag( ELM_ELEMENT_TAG,
puzElementName, NULL,
uiElementNum, defInfo.m_uiDataType, puzNamespace,
bOpeningDict ? FALSE : TRUE)))
{
goto Exit;
}
if (uiElementNum <= FLM_HIGH_FIXED_ELEMENT_NUM)
{
// See if we are updating an existing element, in which case the
// data type cannot be changed.
if ((pElementDef = getElementDef( uiElementNum)) != NULL)
{
if (attrElmGetType( pElementDef) != defInfo.m_uiDataType)
{
rc = RC_SET( NE_XFLM_CANNOT_MOD_DATA_TYPE);
goto Exit;
}
// Still need to assign uiFldType because state could change.
pElementDef->uiFlags = (defInfo.m_uiDataType & ATTR_ELM_DATA_TYPE_MASK) |
(defInfo.m_uiState & ATTR_ELM_STATE_MASK) |
(defInfo.m_uiFlags & ATTR_ELM_FLAGS_MASK);
}
else
{
// If it will fit in the range of elements, simply set it.
// Otherwise, we will need to reallocate the array to make
// room for it.
if (uiElementNum < m_uiLowestElementNum ||
uiElementNum > m_uiHighestElementNum)
{
if (RC_BAD( rc = reallocTbl( uiElementNum, sizeof( ATTR_ELM_DEF),
(void **)&m_pElementDefTbl,
&m_uiLowestElementNum,
&m_uiHighestElementNum, 200,
XFLM_MAX_ELEMENT_NUM)))
{
goto Exit;
}
}
pElementDef = &m_pElementDefTbl [uiElementNum - m_uiLowestElementNum];
pElementDef->uiFlags = (defInfo.m_uiDataType & ATTR_ELM_DATA_TYPE_MASK) |
(defInfo.m_uiState & ATTR_ELM_STATE_MASK) |
(defInfo.m_uiFlags & ATTR_ELM_FLAGS_MASK);
}
}
else
{
// Cannot be modifying or adding in the reserved range. Element
// number must be user defined.
flmAssert( elementIsUserDefined( uiElementNum));
// See if we should increase the extended table size. Do so if:
// 1. It has not yet been allocated, or
// 2. It has not yet reached its maximum size and this field
// number would hash to a slot beyond that maximum.
if (!m_pExtElementDefTbl ||
(m_uiExtElementDefTblSize < MAX_EXT_ATTR_ELM_ARRAY_SIZE &&
uiElementNum % MAX_EXT_ATTR_ELM_ARRAY_SIZE >
m_uiExtElementDefTblSize - 1))
{
FLMUINT uiNewSize = uiElementNum %
MAX_EXT_ATTR_ELM_ARRAY_SIZE + 1000;
FLMUINT uiOldSize = m_uiExtElementDefTblSize;
EXT_ATTR_ELM_DEF * pNewTbl;
EXT_ATTR_ELM_DEF * pOldTbl = m_pExtElementDefTbl;
FLMUINT uiLoop;
if (uiNewSize > MAX_EXT_ATTR_ELM_ARRAY_SIZE)
{
uiNewSize = MAX_EXT_ATTR_ELM_ARRAY_SIZE;
}
// If we had no array, allocate a mutex too.
if (!pOldTbl)
{
// Better not be a mutex allocated at this point either.
flmAssert( m_hExtElementDefMutex == F_MUTEX_NULL);
if (RC_BAD( rc = f_mutexCreate( &m_hExtElementDefMutex)))
{
goto Exit;
}
}
// Allocate a new array
if (RC_BAD( rc = f_calloc( sizeof( EXT_ATTR_ELM_DEF) * uiNewSize,
&pNewTbl)))
{
goto Exit;
}
m_pExtElementDefTbl = pNewTbl;
m_uiExtElementDefTblSize = uiNewSize;
// Rehash everything from the old table into the new table and then
// free the old one.
if (pOldTbl)
{
for (uiLoop = 0; uiLoop < uiOldSize; uiLoop++)
{
if (pOldTbl [uiLoop].uiDictNum)
{
pExtElementDef = getExtElementDef(
pOldTbl [uiLoop].uiDictNum);
f_memcpy( pExtElementDef, &pOldTbl [uiLoop],
sizeof( EXT_ATTR_ELM_DEF));
}
}
f_free( &pOldTbl);
}
}
// Put the new or modified field into the table. No need to lock the
// mutex to do this because no other threads can be accessing this table
// at this time.
pExtElementDef = getExtElementDef( uiElementNum);
pExtElementDef->uiDictNum = uiElementNum;
pIxElement = findIxElement( uiElementNum);
pExtElementDef->attrElmDef.pFirstIcd = pIxElement
? pIxElement->pFirstIcd
: NULL;
pExtElementDef->attrElmDef.uiFlags =
(defInfo.m_uiDataType & ATTR_ELM_DATA_TYPE_MASK) |
(defInfo.m_uiState & ATTR_ELM_STATE_MASK) |
(defInfo.m_uiFlags & ATTR_ELM_FLAGS_MASK);
}
Exit:
if (puzElementName)
{
f_free( &puzElementName);
}
if (puzNamespace)
{
f_free( &puzNamespace);
}
if( pTmpNode)
{
pTmpNode->Release();
}
return( rc);
}
/***************************************************************************
Desc: Add, modify, or delete an attribute definition in the dictionary.
***************************************************************************/
RCODE F_Dict::updateAttributeDef(
F_Db * pDb,
FLMUINT64 ui64DocumentID,
FLMUINT uiAttributeNum,
FLMBOOL bOpeningDict,
FLMBOOL bDeleting
)
{
RCODE rc = NE_XFLM_OK;
ATTR_ELM_DEF * pAttributeDef;
EXT_ATTR_ELM_DEF * pExtAttributeDef;
FLMUNICODE * puzAttributeName = NULL;
FLMUNICODE * puzNamespace = NULL;
IX_ITEM * pIxAttribute;
F_AttrElmInfo defInfo;
if (bDeleting)
{
flmAssert( uiAttributeNum);
// NOTE: It is possible that the attribute may not be in the
// attribute table yet, because dictDocumentDone had not been
// called to put it in there, but we are calling dictDocumentDone
// to remove it.
// Remove the tag number from the name table
m_pNameTable->removeTag( ELM_ATTRIBUTE_TAG, uiAttributeNum);
if (uiAttributeNum <= FLM_HIGH_FIXED_ATTRIBUTE_NUM)
{
if ((pAttributeDef = getAttributeDef( uiAttributeNum)) != NULL)
{
pAttributeDef->uiFlags = 0; // Unused slot
pAttributeDef->pFirstIcd = NULL;
}
}
else
{
// Better be one of our extended attributes - cannot delete
// reserved attributes.
flmAssert( attributeIsUserDefined( uiAttributeNum));
// No need to lock the mutex, because no other threads can
// be accessing it right now.
if (m_pExtAttributeDefTbl)
{
pExtAttributeDef = getExtAttributeDef( uiAttributeNum);
if (pExtAttributeDef->uiDictNum == uiAttributeNum)
{
pExtAttributeDef->uiDictNum = 0;
pExtAttributeDef->attrElmDef.uiFlags = 0;
pExtAttributeDef->attrElmDef.pFirstIcd = NULL;
}
}
}
goto Exit;
}
if (RC_BAD( rc = pDb->getElmAttrInfo( ELM_ATTRIBUTE_TAG,
ui64DocumentID, &defInfo,
bOpeningDict, bDeleting)))
{
goto Exit;
}
if (!uiAttributeNum)
{
uiAttributeNum = defInfo.m_uiDictNum;
}
flmAssert( uiAttributeNum == defInfo.m_uiDictNum);
// Get the attribute name
if( RC_BAD( rc = defInfo.m_pNameAttr->getUnicode(
pDb, &puzAttributeName)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalAttributeName( puzAttributeName)))
{
goto Exit;
}
// Get the attribute's namespace
if( defInfo.m_pTargetNamespaceAttr)
{
if( RC_BAD( rc = defInfo.m_pTargetNamespaceAttr->getUnicode(
pDb, &puzNamespace)))
{
goto Exit;
}
}
// Add to the tag table, unless we already have our quota of
// attribute names. Remove the tag by number first, in case
// it was renamed.
if (!bOpeningDict)
{
m_pNameTable->removeTag( ELM_ATTRIBUTE_TAG, uiAttributeNum);
}
if (RC_BAD( rc = m_pNameTable->addTag( ELM_ATTRIBUTE_TAG,
puzAttributeName, NULL,
uiAttributeNum, defInfo.m_uiDataType, puzNamespace,
bOpeningDict ? FALSE : TRUE)))
{
goto Exit;
}
if (uiAttributeNum <= FLM_HIGH_FIXED_ATTRIBUTE_NUM)
{
// See if we are updating an existing attribute, in which case the
// data type cannot be changed.
if ((pAttributeDef = getAttributeDef( uiAttributeNum)) != NULL)
{
if ( attrElmGetType( pAttributeDef) != defInfo.m_uiDataType)
{
rc = RC_SET( NE_XFLM_CANNOT_MOD_DATA_TYPE);
goto Exit;
}
// Still need to assign uiFldType because state could change.
pAttributeDef->uiFlags = (defInfo.m_uiDataType & ATTR_ELM_DATA_TYPE_MASK) |
(defInfo.m_uiState & ATTR_ELM_STATE_MASK) |
(defInfo.m_uiFlags & ATTR_ELM_FLAGS_MASK);
}
else
{
// If it will fit in the range of attributes, simply set it.
// Otherwise, we will need to reallocate the array to make
// room for it.
if (uiAttributeNum < m_uiLowestAttributeNum ||
uiAttributeNum > m_uiHighestAttributeNum)
{
if (RC_BAD( rc = reallocTbl( uiAttributeNum, sizeof( ATTR_ELM_DEF),
(void **)&m_pAttributeDefTbl,
&m_uiLowestAttributeNum,
&m_uiHighestAttributeNum, 200,
XFLM_MAX_ATTRIBUTE_NUM)))
{
goto Exit;
}
}
pAttributeDef = &m_pAttributeDefTbl [uiAttributeNum -
m_uiLowestAttributeNum];
pAttributeDef->uiFlags = (defInfo.m_uiDataType & ATTR_ELM_DATA_TYPE_MASK) |
(defInfo.m_uiState & ATTR_ELM_STATE_MASK) |
(defInfo.m_uiFlags & ATTR_ELM_FLAGS_MASK);
}
}
else
{
// Cannot be modifying or adding in the reserved range. Attribute
// number must be user defined.
flmAssert( attributeIsUserDefined( uiAttributeNum));
// See if we should increase the extended table size. Do so if:
// 1. It has not yet been allocated, or
// 2. It has not yet reached its maximum size and this field
// number would hash to a slot beyond that maximum.
if (!m_pExtAttributeDefTbl ||
(m_uiExtAttributeDefTblSize < MAX_EXT_ATTR_ELM_ARRAY_SIZE &&
uiAttributeNum % MAX_EXT_ATTR_ELM_ARRAY_SIZE >
m_uiExtAttributeDefTblSize - 1))
{
FLMUINT uiNewSize = uiAttributeNum %
MAX_EXT_ATTR_ELM_ARRAY_SIZE + 1000;
FLMUINT uiOldSize = m_uiExtAttributeDefTblSize;
EXT_ATTR_ELM_DEF * pNewTbl;
EXT_ATTR_ELM_DEF * pOldTbl = m_pExtAttributeDefTbl;
FLMUINT uiLoop;
if (uiNewSize > MAX_EXT_ATTR_ELM_ARRAY_SIZE)
{
uiNewSize = MAX_EXT_ATTR_ELM_ARRAY_SIZE;
}
// If we had no array, allocate a mutex too.
if (!pOldTbl)
{
// Better not be a mutex allocated at this point either.
flmAssert( m_hExtAttributeDefMutex == F_MUTEX_NULL);
if (RC_BAD( rc = f_mutexCreate( &m_hExtAttributeDefMutex)))
{
goto Exit;
}
}
// Allocate a new array
if (RC_BAD( rc = f_calloc( sizeof( EXT_ATTR_ELM_DEF) * uiNewSize,
&pNewTbl)))
{
goto Exit;
}
m_pExtAttributeDefTbl = pNewTbl;
m_uiExtAttributeDefTblSize = uiNewSize;
// Rehash everything from the old table into the new table and then
// free the old one.
if (pOldTbl)
{
for (uiLoop = 0; uiLoop < uiOldSize; uiLoop++)
{
if (pOldTbl [uiLoop].uiDictNum)
{
pExtAttributeDef = getExtAttributeDef(
pOldTbl [uiLoop].uiDictNum);
f_memcpy( pExtAttributeDef, &pOldTbl [uiLoop],
sizeof( EXT_ATTR_ELM_DEF));
}
}
f_free( &pOldTbl);
}
}
// Put the new or modified field into the table. No need to lock the
// mutex to do this because no other threads can be accessing this table
// at this time.
pExtAttributeDef = getExtAttributeDef( uiAttributeNum);
pExtAttributeDef->uiDictNum = uiAttributeNum;
pIxAttribute = findIxAttribute( uiAttributeNum);
pExtAttributeDef->attrElmDef.pFirstIcd = pIxAttribute
? pIxAttribute->pFirstIcd
: NULL;
pExtAttributeDef->attrElmDef.uiFlags =
(defInfo.m_uiDataType & ATTR_ELM_DATA_TYPE_MASK) |
(defInfo.m_uiState & ATTR_ELM_STATE_MASK) |
(defInfo.m_uiFlags & ATTR_ELM_FLAGS_MASK);
}
Exit:
if (puzAttributeName)
{
f_free( &puzAttributeName);
}
if (puzNamespace)
{
f_free( &puzNamespace);
}
return( rc);
}
/***************************************************************************
Desc: Determine if an index name is legal - formatwise
***************************************************************************/
FINLINE RCODE fdictLegalIndexName(
FLMUNICODE * // puzIndexName
)
{
//VISIT: Need to fill this out - may need to return NE_XFLM_ILLEGAL_INDEX_NAME
return( NE_XFLM_OK);
}
/***************************************************************************
Desc: Determine if an index number is legal
***************************************************************************/
FINLINE RCODE fdictLegalIndexNumber(
FLMUINT uiIndexNumber
)
{
return( (uiIndexNumber > 0 && uiIndexNumber <= XFLM_MAX_INDEX_NUM)
? NE_XFLM_OK
: RC_SET( NE_XFLM_ILLEGAL_INDEX_NUMBER));
}
/***************************************************************************
Desc: Determine if a collection name is legal - formatwise
***************************************************************************/
FINLINE RCODE fdictLegalCollectionName(
FLMUNICODE * // puzCollectionName
)
{
//VISIT: Need to fill this out - may need to return NE_XFLM_ILLEGAL_COLLECTION_NAME
return( NE_XFLM_OK);
}
/***************************************************************************
Desc: Determine if a collection number is legal
***************************************************************************/
FINLINE RCODE fdictLegalCollectionNumber(
FLMUINT uiCollectionNumber
)
{
return( ( (uiCollectionNumber > 0 &&
uiCollectionNumber <= XFLM_MAX_COLLECTION_NUM) ||
(uiCollectionNumber == XFLM_DATA_COLLECTION))
? NE_XFLM_OK
: RC_SET( NE_XFLM_ILLEGAL_COLLECTION_NUMBER));
}
/***************************************************************************
Desc: Determine if a prefix name is legal - formatwise
***************************************************************************/
FINLINE RCODE fdictLegalPrefixName(
FLMUNICODE * // puzPrefixName
)
{
//VISIT: Need to fill this out - may need to return NE_XFLM_ILLEGAL_PREFIX_NAME
return( NE_XFLM_OK);
}
/***************************************************************************
Desc: Determine if a prefix number is legal
***************************************************************************/
FINLINE RCODE fdictLegalPrefixNumber(
FLMUINT uiPrefixNumber
)
{
return( (uiPrefixNumber > 0 &&
uiPrefixNumber <= XFLM_MAX_PREFIX_NUM)
? NE_XFLM_OK
: RC_SET( NE_XFLM_ILLEGAL_PREFIX_NUMBER));
}
/***************************************************************************
Desc: Determine if an encryption def name is legal - formatwise
***************************************************************************/
FINLINE RCODE fdictLegalEncDefName(
FLMUNICODE * // puzEncDefName
)
{
//VISIT: Need to fill this out - may need to return NE_XFLM_ILLEGAL_ENCDEF_NAME
return( NE_XFLM_OK);
}
/***************************************************************************
Desc: Determine if an encryption def number is legal
***************************************************************************/
FINLINE RCODE fdictLegalEncDefNumber(
FLMUINT uiEncDefNumber
)
{
return( (uiEncDefNumber > 0 &&
uiEncDefNumber <= XFLM_MAX_ENCDEF_NUM)
? NE_XFLM_OK
: RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_ENCDEF_NUMBER));
}
/***************************************************************************
Desc: Determine if an encryption def type (algorithm) is legal
***************************************************************************/
FINLINE RCODE fdictLegalEncDefType(
char * pszEncDefType,
FLMUINT * puiEncDefType
)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiType;
// Parse the type keyword - only one type allowed.
for( uiType = 0;
uiType < MAX_ENC_TYPES ;
uiType++)
{
if( f_strnicmp( pszEncDefType, DDEncOpts[ uiType], f_strlen(DDEncOpts[ uiType])) == 0)
{
*puiEncDefType = uiType;
goto Exit;
}
}
rc = RC_SET( NE_XFLM_INVALID_ENC_ALGORITHM);
Exit:
return( rc);
}
/***************************************************************************
Desc: Determine if a specified encryption key size is legal
***************************************************************************/
FINLINE RCODE fdictLegalEncKeySize(
FLMUINT uiEncType,
FLMUINT uiEncKeySize
)
{
RCODE rc = NE_XFLM_OK;
switch( uiEncType)
{
case FLM_NICI_AES:
{
if (uiEncKeySize != XFLM_NICI_AES128 &&
uiEncKeySize != XFLM_NICI_AES192 &&
uiEncKeySize != XFLM_NICI_AES256)
{
rc = RC_SET( NE_XFLM_INVALID_ENC_KEY_SIZE);
goto Exit;
}
break;
}
case FLM_NICI_DES3:
{
if (uiEncKeySize != XFLM_NICI_DES3X)
{
rc = RC_SET( NE_XFLM_INVALID_ENC_KEY_SIZE);
goto Exit;
}
break;
}
default:
{
rc = RC_SET( NE_XFLM_INVALID_ENC_ALGORITHM);
goto Exit;
}
}
Exit:
return rc;
}
/***************************************************************************
Desc: return a legal key size, based on the encryption algorithm.
***************************************************************************/
FINLINE FLMBOOL fdictGetLegalKeySize(
FLMUINT uiEncType,
FLMUINT * puiEncKeySize
)
{
FLMBOOL bSizeOk = FALSE;
// Note: The uiEncType should have already been validated.
switch( uiEncType)
{
case FLM_NICI_AES:
{
if ( *puiEncKeySize == 0)
{
*puiEncKeySize = XFLM_NICI_AES256;
bSizeOk = TRUE;
}
else if ( *puiEncKeySize == XFLM_NICI_AES256)
{
*puiEncKeySize = XFLM_NICI_AES192;
bSizeOk = TRUE;
}
else if ( *puiEncKeySize == XFLM_NICI_AES192)
{
*puiEncKeySize = XFLM_NICI_AES128;
bSizeOk = TRUE;
}
break;
}
case FLM_NICI_DES3:
{
if ( *puiEncKeySize == 0)
{
*puiEncKeySize = XFLM_NICI_DES3X;
bSizeOk = TRUE;
}
break;
}
}
return bSizeOk;
}
/***************************************************************************
Desc: Parse an option from a string. Function returns pointer to
beginning of option. Parameter is moved to just after where that
option started.
***************************************************************************/
FSTATIC char * fdictGetOption(
char ** ppszSrc
)
{
char * pszMatch = NULL;
char * pszSrc = *ppszSrc;
while (*pszSrc == NATIVE_SPACE)
{
pszSrc++;
}
// See if at end of string.
if (!(*pszSrc))
{
goto Exit;
}
pszMatch = pszSrc;
while (*pszSrc && *pszSrc != NATIVE_SPACE)
{
pszSrc++;
}
if (*pszSrc)
{
*pszSrc = 0;
pszSrc++;
}
Exit:
*ppszSrc = pszSrc;
return( pszMatch);
}
/***************************************************************************
Desc: Retrieve an index definition.
***************************************************************************/
RCODE F_Db::getIndexDef(
FLMUINT64 ui64DocumentID,
FLMUNICODE ** ppuzIndexName,
FLMUINT * puiIndexNumber,
FLMUINT * puiCollectionNumber,
FLMUINT * puiLanguage,
FLMUINT * puiFlags,
FLMUINT64 * pui64LastDocIndexed,
FLMUINT * puiEncId,
F_DOMNode ** ppNode,
FLMBOOL bOpeningDict,
FLMBOOL bDeleting)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pNode = NULL;
F_CachedNode * pCachedNode;
F_DOMNode * pAttr = NULL;
FLMBOOL bHadIndexNumber = FALSE;
FLMBOOL bHadIndexName = FALSE;
char szTmpBuf[ 80];
FLMUNICODE * puzCollectionName = NULL;
FLMUINT uiNameCollectionNum = 0;
FLMUINT uiNameId;
FLMBOOL bHadLastDocIndexed = FALSE;
FLMBOOL bHadState = FALSE;
// Set up defaults
*ppuzIndexName = NULL;
*puiIndexNumber = 0;
*puiCollectionNumber = XFLM_DATA_COLLECTION;
*puiLanguage = m_pDatabase->m_uiDefaultLanguage;
*puiFlags = 0;
*puiEncId = 0;
*ppNode = NULL;
// Retrieve the root element of the index definition
if (RC_BAD( rc = getNode( XFLM_DICT_COLLECTION, ui64DocumentID, &pNode)))
{
goto Exit;
}
flmAssert( pNode->getNodeType() == ELEMENT_NODE);
pCachedNode = pNode->m_pCachedNode;
// Cycle through the attributes
if( !pCachedNode->hasAttributes())
{
rc = RC_SET( NE_XFLM_MISSING_INDEX_NAME);
goto Exit;
}
if( RC_BAD( rc = pNode->getFirstAttribute( this, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
for( ;;)
{
if( RC_BAD( rc = pAttr->getNameId( this, &uiNameId)))
{
goto Exit;
}
switch (uiNameId)
{
case ATTR_NAME_TAG:
{
if (RC_BAD( rc = pAttr->getUnicode( this, ppuzIndexName)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalIndexName( *ppuzIndexName)))
{
goto Exit;
}
bHadIndexName = TRUE;
break;
}
case ATTR_DICT_NUMBER_TAG:
{
if (RC_BAD( rc = pAttr->getUINT( this, puiIndexNumber)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalIndexNumber( *puiIndexNumber)))
{
goto Exit;
}
bHadIndexNumber = TRUE;
break;
}
case ATTR_COLLECTION_NUMBER_TAG:
{
if (RC_BAD( rc = pAttr->getUINT( this, puiCollectionNumber)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalCollectionNumber(
*puiCollectionNumber)))
{
goto Exit;
}
if (uiNameCollectionNum &&
*puiCollectionNumber != uiNameCollectionNum)
{
rc = RC_SET( NE_XFLM_COLLECTION_NAME_MISMATCH);
goto Exit;
}
break;
}
case ATTR_COLLECTION_NAME_TAG:
{
F_DataVector searchKey;
F_DataVector dataPart;
if (RC_BAD( rc = pAttr->getUnicode( this, &puzCollectionName)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalCollectionName( puzCollectionName)))
{
goto Exit;
}
// Get the collection number - look up in the index
if (RC_BAD( rc = searchKey.setUINT( 0, ELM_COLLECTION_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = searchKey.setUnicode( 1, puzCollectionName)))
{
goto Exit;
}
if (RC_BAD( rc = keyRetrieve( XFLM_DICT_NAME_INDEX,
&searchKey, XFLM_EXACT, &dataPart)))
{
goto Exit;
}
// Data part of the retrieved key has the dictionary number
// for this collection.
if (RC_BAD( rc = dataPart.getUINT( 3, &uiNameCollectionNum)))
{
if (rc == NE_XFLM_NOT_FOUND)
{
uiNameCollectionNum = 0;
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
flmAssert( uiNameCollectionNum);
if (*puiCollectionNumber &&
uiNameCollectionNum != *puiCollectionNumber)
{
rc = RC_SET( NE_XFLM_COLLECTION_NAME_MISMATCH);
goto Exit;
}
*puiCollectionNumber = uiNameCollectionNum;
break;
}
case ATTR_LANGUAGE_TAG:
{
if( RC_BAD( rc = pAttr->getUTF8( this, (FLMBYTE *)szTmpBuf,
sizeof( szTmpBuf), 0, ~((FLMUINT)0))))
{
goto Exit;
}
*puiLanguage = f_languageToNum( (char *)szTmpBuf);
break;
}
case ATTR_INDEX_OPTIONS_TAG:
{
char * pszTmp;
char * pszOption;
if( RC_BAD( rc = pAttr->getUTF8( this, (FLMBYTE *)szTmpBuf,
sizeof( szTmpBuf), 0, ~((FLMUINT)0))))
{
goto Exit;
}
pszTmp = &szTmpBuf [0];
while ((pszOption = fdictGetOption( (char **)&pszTmp)) != NULL)
{
if (f_stricmp( pszOption,
XFLM_ABS_POS_OPTION_STR) == 0)
{
(*puiFlags) |= IXD_ABS_POS;
}
else
{
rc = RC_SET( NE_XFLM_INVALID_INDEX_OPTION);
goto Exit;
}
}
break;
}
case ATTR_STATE_TAG:
{
FLMUINT uiState;
if (RC_BAD( rc = pAttr->getUTF8( this, (FLMBYTE *)szTmpBuf,
sizeof( szTmpBuf), 0, ~((FLMUINT)0))))
{
goto Exit;
}
if (RC_BAD( rc = fdictGetIndexState( szTmpBuf, &uiState)))
{
goto Exit;
}
*puiFlags = (*puiFlags & (~(IXD_SUSPENDED | IXD_OFFLINE))) |
uiState;
// Freeze the state - can only be changed by an explicit
// call to indexSuspend or indexResume.
if (!bOpeningDict)
{
if( RC_BAD( rc = pAttr->addModeFlags( this,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
}
bHadState = TRUE;
break;
}
case ATTR_LAST_DOC_INDEXED_TAG:
{
if (RC_BAD( rc = pAttr->getUINT64( this, pui64LastDocIndexed)))
{
goto Exit;
}
bHadLastDocIndexed = TRUE;
break;
}
case ATTR_ENCRYPTION_ID_TAG:
{
if (RC_BAD( rc = pAttr->getUINT( this, puiEncId)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalEncDefNumber( *puiEncId)))
{
goto Exit;
}
break;
}
default:
{
// Ignore all other attributes
break;
}
}
if( RC_BAD( rc = pAttr->getNextSibling( this, (IF_DOMNode **)&pAttr)))
{
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
}
if (!bHadLastDocIndexed)
{
*pui64LastDocIndexed =
(FLMUINT64)(((*puiFlags) & (IXD_SUSPENDED | IXD_OFFLINE))
? (FLMUINT64)0
: ~((FLMUINT64)0));
}
// Make sure we had both a name and number specified
if (!bHadIndexName)
{
rc = RC_SET( NE_XFLM_MISSING_INDEX_NAME);
goto Exit;
}
if (!bHadIndexNumber)
{
rc = RC_SET( NE_XFLM_MISSING_INDEX_NUMBER);
goto Exit;
}
// Set a state attribute and freeze it if it was missing.
if (!bOpeningDict && !bDeleting && !bHadState)
{
if (RC_BAD( rc = pNode->createAttribute( this, ATTR_STATE_TAG,
(IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->setUTF8( this,
(FLMBYTE *)XFLM_INDEX_ONLINE_STR)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->addModeFlags( this,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
}
*ppNode = pNode;
// Set to NULL so it will not be released at Exit.
pNode = NULL;
Exit:
if (pNode)
{
pNode->Release();
}
if (pAttr)
{
pAttr->Release();
}
if (puzCollectionName)
{
f_free( &puzCollectionName);
}
return( rc);
}
/***************************************************************************
Desc: Get the information for an index component.
***************************************************************************/
RCODE F_Db::getIndexComponentDef(
F_Dict * pDict,
F_DOMNode * pElementNode,
FLMUINT uiElementId,
IXD * pIxd,
ICD * pIcd
)
{
RCODE rc = NE_XFLM_OK;
IF_DOMNode * pAttr = NULL;
F_CachedNode * pCachedNode;
ICD * pTmpIcd;
ICD * pPrevIcd;
char szTmpBuf[ 200];
char * pszTmp;
char * pszOption;
FLMUNICODE * puzName = NULL;
FLMUNICODE * puzNamespace = NULL;
FLMUINT uiKeyComponent;
FLMUINT uiDataComponent;
FLMUINT uiNameDictNumber = 0;
FLMUINT uiDataType= 0;
FLMBOOL bLimitSet = FALSE;
FLMBOOL bRequiredSet = FALSE;
FLMBOOL bIndexOnSet = FALSE;
FLMBOOL bCompareRuleSet = FALSE;
FLMBOOL bIsAttr = FALSE;
FLMBOOL bHadDictNumber = FALSE;
F_NameTable * pNameTable = NULL;
FLMUINT uiNameId;
if (uiElementId == ELM_ATTRIBUTE_COMPONENT_TAG)
{
bIsAttr = TRUE;
pIcd->uiFlags |= ICD_IS_ATTRIBUTE;
}
pCachedNode = pElementNode->m_pCachedNode;
if( !pCachedNode->hasAttributes())
{
rc = (RCODE)(bIsAttr
? RC_SET( NE_XFLM_MISSING_ATTRIBUTE_NUMBER)
: RC_SET( NE_XFLM_MISSING_ELEMENT_NUMBER));
goto Exit;
}
if( RC_BAD( rc = pElementNode->getFirstAttribute( this, &pAttr)))
{
goto Exit;
}
for( ;;)
{
if( RC_BAD( rc = pAttr->getNameId( this, &uiNameId)))
{
goto Exit;
}
switch (uiNameId)
{
case ATTR_DICT_NUMBER_TAG:
if (RC_BAD( rc = pAttr->getUINT( this, &pIcd->uiDictNum)))
{
goto Exit;
}
if (bIsAttr)
{
if (RC_BAD( rc = fdictLegalAttributeNumber( pIcd->uiDictNum, TRUE)))
{
goto Exit;
}
}
else
{
if (RC_BAD( rc = fdictLegalElementNumber( pIcd->uiDictNum, TRUE)))
{
goto Exit;
}
}
bHadDictNumber = TRUE;
break;
case ATTR_NAME_TAG:
if (RC_BAD( rc = pAttr->getUnicode( this, &puzName)))
{
goto Exit;
}
if (bIsAttr)
{
if (RC_BAD( rc = fdictLegalAttributeName( puzName)))
{
goto Exit;
}
}
else
{
if (RC_BAD( rc = fdictLegalElementName( puzName)))
{
goto Exit;
}
}
break;
case ATTR_TARGET_NAMESPACE_TAG:
if (RC_BAD( rc = pAttr->getUnicode( this, &puzNamespace)))
{
goto Exit;
}
break;
case ATTR_INDEX_ON_TAG:
if( RC_BAD( rc = pAttr->getUTF8( this, (FLMBYTE *)szTmpBuf,
sizeof( szTmpBuf), 0, ~((FLMUINT)0))))
{
goto Exit;
}
if (f_stricmp( szTmpBuf, XFLM_VALUE_OPTION_STR) == 0)
{
pIcd->uiFlags |= ICD_VALUE;
pIcd->uiFlags &= (~(ICD_PRESENCE | ICD_SUBSTRING |
ICD_EACHWORD | ICD_METAPHONE));
}
else if (f_stricmp( szTmpBuf, XFLM_PRESENCE_OPTION_STR) == 0)
{
pIcd->uiFlags |= ICD_PRESENCE;
pIcd->uiFlags &= (~(ICD_VALUE | ICD_SUBSTRING |
ICD_EACHWORD | ICD_METAPHONE));
}
else if (f_stricmp( szTmpBuf, XFLM_SUBSTRING_OPTION_STR) == 0)
{
pIcd->uiFlags |= ICD_SUBSTRING;
pIcd->uiFlags &= (~(ICD_PRESENCE | ICD_VALUE |
ICD_EACHWORD | ICD_METAPHONE));
}
else if (f_stricmp( szTmpBuf, XFLM_EACHWORD_OPTION_STR) == 0)
{
pIcd->uiFlags |= ICD_EACHWORD;
pIcd->uiFlags &= (~(ICD_PRESENCE | ICD_VALUE |
ICD_SUBSTRING | ICD_METAPHONE));
}
else if (f_stricmp( szTmpBuf, XFLM_METAPHONE_OPTION_STR) == 0)
{
pIcd->uiFlags |= ICD_METAPHONE;
pIcd->uiFlags &= (~(ICD_PRESENCE | ICD_VALUE |
ICD_SUBSTRING | ICD_EACHWORD));
}
else
{
rc = RC_SET( NE_XFLM_ILLEGAL_INDEX_ON);
goto Exit;
}
bIndexOnSet = TRUE;
break;
case ATTR_REQUIRED_TAG:
if( RC_BAD( rc = pAttr->getUTF8( this, (FLMBYTE *)szTmpBuf,
sizeof( szTmpBuf), 0, ~((FLMUINT)0))))
{
goto Exit;
}
if (f_stricmp( szTmpBuf, "yes") == 0 ||
f_stricmp( szTmpBuf, "true") == 0 ||
f_stricmp( szTmpBuf, "1") == 0 ||
f_stricmp( szTmpBuf, "on") == 0 ||
f_stricmp( szTmpBuf, "enable") == 0)
{
pIcd->uiFlags |= ICD_REQUIRED_PIECE;
}
else if (f_stricmp( szTmpBuf, "no") != 0 &&
f_stricmp( szTmpBuf, "false") != 0 &&
f_stricmp( szTmpBuf, "0") != 0 &&
f_stricmp( szTmpBuf, "off") != 0 &&
f_stricmp( szTmpBuf, "disable") != 0)
{
rc = RC_SET( NE_XFLM_ILLEGAL_REQUIRED_VALUE);
goto Exit;
}
bRequiredSet = TRUE;
break;
case ATTR_LIMIT_TAG:
if (RC_BAD( rc = pAttr->getUINT( this, &pIcd->uiLimit)))
{
goto Exit;
}
bLimitSet = TRUE;
break;
case ATTR_COMPARE_RULES_TAG:
if (RC_BAD( rc = pAttr->getUTF8( this, (FLMBYTE *)szTmpBuf,
sizeof( szTmpBuf), 0, ~((FLMUINT)0))))
{
goto Exit;
}
pszTmp = &szTmpBuf [0];
while ((pszOption = fdictGetOption( &pszTmp)) != NULL)
{
if (f_stricmp( pszOption,
XFLM_CASE_INSENSITIVE_OPTION_STR) == 0)
{
pIcd->uiCompareRules |= XFLM_COMP_CASE_INSENSITIVE;
}
else if (f_stricmp( pszOption,
XFLM_MINSPACES_OPTION_STR) == 0)
{
pIcd->uiCompareRules |= XFLM_COMP_COMPRESS_WHITESPACE;
}
else if (f_stricmp( pszOption,
XFLM_WHITESPACE_AS_SPACE_STR) == 0)
{
pIcd->uiCompareRules |= XFLM_COMP_WHITESPACE_AS_SPACE;
}
else if (f_stricmp( pszOption,
XFLM_IGNORE_LEADINGSPACES_OPTION_STR) == 0)
{
pIcd->uiCompareRules |= XFLM_COMP_IGNORE_LEADING_SPACE;
}
else if (f_stricmp( pszOption,
XFLM_IGNORE_TRAILINGSPACES_OPTION_STR) == 0)
{
pIcd->uiCompareRules |= XFLM_COMP_IGNORE_TRAILING_SPACE;
}
else if (f_stricmp( pszOption,
XFLM_NOUNDERSCORE_OPTION_STR) == 0)
{
pIcd->uiCompareRules |= XFLM_COMP_NO_UNDERSCORES;
}
else if (f_stricmp( pszOption,
XFLM_NOSPACE_OPTION_STR) == 0)
{
pIcd->uiCompareRules |= XFLM_COMP_NO_WHITESPACE;
}
else if (f_stricmp( pszOption,
XFLM_NODASH_OPTION_STR) == 0)
{
pIcd->uiCompareRules |= XFLM_COMP_NO_DASHES;
}
else if (f_stricmp( pszOption,
XFLM_DESCENDING_OPTION_STR) == 0)
{
pIcd->uiFlags |= ICD_DESCENDING;
}
else if (f_stricmp( pszOption,
XFLM_MISSING_HIGH_OPTION_STR) == 0)
{
pIcd->uiFlags |= ICD_MISSING_HIGH;
}
else
{
rc = RC_SET( NE_XFLM_INVALID_COMPARE_RULE);
goto Exit;
}
}
bCompareRuleSet = TRUE;
break;
case ATTR_KEY_COMPONENT_TAG:
if( RC_BAD( rc = pAttr->getUINT( this, &uiKeyComponent)))
{
goto Exit;
}
if (!uiKeyComponent)
{
rc = RC_SET( NE_XFLM_ILLEGAL_KEY_COMPONENT_NUM);
goto Exit;
}
// Insert into its place in the list of key components
pPrevIcd = NULL;
pTmpIcd = pIxd->pFirstKey;
while (pTmpIcd && uiKeyComponent > pTmpIcd->uiKeyComponent)
{
pPrevIcd = pTmpIcd;
pTmpIcd = pTmpIcd->pNextKeyComponent;
}
// Make sure not already in the list
if (pTmpIcd && pTmpIcd->uiKeyComponent == uiKeyComponent)
{
rc = RC_SET( NE_XFLM_DUPLICATE_KEY_COMPONENT);
goto Exit;
}
// Link after pPrevIcd
if (pPrevIcd)
{
if ((pIcd->pNextKeyComponent =
pPrevIcd->pNextKeyComponent) != NULL)
{
pIcd->pNextKeyComponent->pPrevKeyComponent = pIcd;
}
else
{
pIxd->pLastKey = pIcd;
}
pPrevIcd->pNextKeyComponent = pIcd;
pIcd->pPrevKeyComponent = pPrevIcd;
}
else
{
if ((pIcd->pNextKeyComponent = pIxd->pFirstKey) != NULL)
{
pIxd->pFirstKey->pPrevKeyComponent = pIcd;
}
else
{
pIxd->pLastKey = pIcd;
}
pIxd->pFirstKey = pIcd;
}
pIcd->uiKeyComponent = uiKeyComponent;
pIxd->uiNumKeyComponents++;
break;
case ATTR_DATA_COMPONENT_TAG:
if( RC_BAD( rc = pAttr->getUINT( this, &uiDataComponent)))
{
goto Exit;
}
if (!uiDataComponent)
{
rc = RC_SET( NE_XFLM_ILLEGAL_DATA_COMPONENT_NUM);
goto Exit;
}
// Insert into its place in the list of data components
pPrevIcd = NULL;
pTmpIcd = pIxd->pFirstData;
while (pTmpIcd && uiDataComponent > pTmpIcd->uiDataComponent)
{
pPrevIcd = pTmpIcd;
pTmpIcd = pTmpIcd->pNextDataComponent;
}
// Make sure not already in the list
if (pTmpIcd && pTmpIcd->uiDataComponent == uiDataComponent)
{
rc = RC_SET( NE_XFLM_DUPLICATE_DATA_COMPONENT);
goto Exit;
}
// Link after pPrevIcd
if (pPrevIcd)
{
if ((pIcd->pNextDataComponent =
pPrevIcd->pNextDataComponent) != NULL)
{
pIcd->pNextDataComponent->pPrevDataComponent = pIcd;
}
else
{
pIxd->pLastData = pIcd;
}
pPrevIcd->pNextDataComponent = pIcd;
pIcd->pPrevDataComponent = pPrevIcd;
}
else
{
if ((pIcd->pNextDataComponent = pIxd->pFirstData) != NULL)
{
pIxd->pFirstData->pPrevDataComponent = pIcd;
}
else
{
pIxd->pLastData = pIcd;
}
pIxd->pFirstData = pIcd;
}
pIcd->uiDataComponent = uiDataComponent;
pIxd->uiNumDataComponents++;
break;
default:
// Ignore all other attributes
break;
}
if( RC_BAD( rc = pAttr->getNextSibling( this, &pAttr)))
{
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
}
// If they specified a name, see if we can find it
if (puzName)
{
if (*puzName == '/' && *(puzName + 1) == 0)
{
uiNameDictNumber = ELM_ROOT_TAG;
// For now, we can only allow presence indexing on
// ELM_ROOT_TAG. That is because we don't yet
// allow specifying of data type per ICD
if (!(pIcd->uiFlags & ICD_PRESENCE))
{
rc = RC_SET( NE_XFLM_MUST_INDEX_ON_PRESENCE);
goto Exit;
}
// ELM_ROOT_TAG cannot be specified as a data
// component.
if (pIcd->uiDataComponent)
{
rc = RC_SET( NE_XFLM_ILLEGAL_DATA_COMPONENT);
goto Exit;
}
}
else
{
F_DataVector searchKey;
F_DataVector dataPart;
// Get the dictionary number - look up in the index
if (RC_BAD( rc = searchKey.setUINT( 0,
uiElementId == ELM_ELEMENT_COMPONENT_TAG
? ELM_ELEMENT_TAG
: ELM_ATTRIBUTE_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = searchKey.setUnicode( 1, puzName)))
{
goto Exit;
}
if (puzNamespace)
{
if (RC_BAD( rc = searchKey.setUnicode( 2, puzNamespace)))
{
goto Exit;
}
}
if (RC_BAD( rc = keyRetrieve( XFLM_DICT_NAME_INDEX,
&searchKey, XFLM_EXACT, &dataPart)))
{
if (rc == NE_XFLM_NOT_FOUND)
{
// This may be a built-in type which is not indexed.
if ( RC_BAD( rc = getNameTable( &pNameTable)))
{
goto Exit;
}
if ( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
this,
(bIsAttr) ? ELM_ATTRIBUTE_TAG : ELM_ELEMENT_TAG,
puzName,
NULL,
TRUE,
puzNamespace,
&uiNameDictNumber)))
{
if ( rc == NE_XFLM_NOT_FOUND)
{
rc = (RCODE)(bIsAttr
? RC_SET( NE_XFLM_UNDEFINED_ATTRIBUTE_NAME)
: RC_SET( NE_XFLM_UNDEFINED_ELEMENT_NAME));
}
goto Exit;
}
}
else
{
goto Exit;
}
}
else
{
// Data part of the retrieved key has the dictionary number
// for this collection.
if (RC_BAD( rc = dataPart.getUINT( 3, &uiNameDictNumber)))
{
if (rc == NE_XFLM_NOT_FOUND)
{
uiNameDictNumber = 0;
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
}
flmAssert( uiNameDictNumber);
}
if (pIcd->uiDictNum &&
uiNameDictNumber != pIcd->uiDictNum)
{
rc = (RCODE)(bIsAttr
? RC_SET( NE_XFLM_ATTRIBUTE_NAME_MISMATCH)
: RC_SET( NE_XFLM_ELEMENT_NAME_MISMATCH));
goto Exit;
}
pIcd->uiDictNum = uiNameDictNumber;
bHadDictNumber = TRUE;
}
// If this is a key component, make a few more checks
if (pIcd->uiKeyComponent)
{
// If no limit was set, use a default.
if (pIcd->uiFlags & ICD_SUBSTRING)
{
pIxd->uiFlags |= IXD_HAS_SUBSTRING;
}
if (!bLimitSet)
{
if (pIcd->uiFlags & ICD_SUBSTRING)
{
pIcd->uiLimit = ICD_DEFAULT_SUBSTRING_LIMIT;
}
else
{
pIcd->uiLimit = ICD_DEFAULT_LIMIT;
}
}
}
else
{
// There are certain things that cannot be set for data
// and context components. Verify that they were not set.
if (bRequiredSet)
{
rc = RC_SET( NE_XFLM_CANNOT_SET_REQUIRED);
goto Exit;
}
if (bLimitSet)
{
rc = RC_SET( NE_XFLM_CANNOT_SET_LIMIT);
goto Exit;
}
if (bIndexOnSet)
{
rc = RC_SET( NE_XFLM_CANNOT_SET_INDEX_ON);
goto Exit;
}
if (bCompareRuleSet)
{
rc = RC_SET( NE_XFLM_CANNOT_SET_COMPARE_RULES);
goto Exit;
}
if (!pIcd->uiDataComponent)
{
// Insert into its place in the list of context components
pPrevIcd = NULL;
pTmpIcd = pIxd->pFirstContext;
while (pTmpIcd && pIcd->uiCdl > pTmpIcd->uiCdl)
{
pPrevIcd = pTmpIcd;
pTmpIcd = pTmpIcd->pNextKeyComponent;
}
// Link after pPrevIcd
if (pPrevIcd)
{
if ((pIcd->pNextKeyComponent =
pPrevIcd->pNextKeyComponent) != NULL)
{
pIcd->pNextKeyComponent->pPrevKeyComponent = pIcd;
}
else
{
pIxd->pLastContext = pIcd;
}
pPrevIcd->pNextKeyComponent = pIcd;
pIcd->pPrevKeyComponent = pPrevIcd;
}
else
{
if ((pIcd->pNextKeyComponent = pIxd->pFirstContext) != NULL)
{
pIxd->pFirstContext->pPrevKeyComponent = pIcd;
}
else
{
pIxd->pLastContext = pIcd;
}
pIxd->pFirstContext = pIcd;
}
pIxd->uiNumContextComponents++;
}
}
// Make sure we had an element or attribute number specified
if (!bHadDictNumber)
{
rc = (RCODE)(bIsAttr
? RC_SET( NE_XFLM_MISSING_ATTRIBUTE_NUMBER)
: RC_SET( NE_XFLM_MISSING_ELEMENT_NUMBER));
goto Exit;
}
// Get the element or attribute's data type
if (bIsAttr)
{
F_AttrElmInfo attrInfo;
if (RC_BAD( rc = pDict->getAttribute( this, pIcd->uiDictNum, &attrInfo)))
{
goto Exit;
}
uiDataType = attrInfo.m_uiDataType;
}
else
{
if (pIcd->uiDictNum == ELM_ROOT_TAG)
{
uiDataType = XFLM_NODATA_TYPE;
}
else
{
F_AttrElmInfo elmInfo;
if (RC_BAD( rc = pDict->getElement( this, pIcd->uiDictNum, &elmInfo)))
{
goto Exit;
}
uiDataType = elmInfo.m_uiDataType;
}
}
icdSetDataType( pIcd, uiDataType);
Exit:
if (pAttr)
{
pAttr->Release();
}
if (puzName)
{
f_free( &puzName);
}
if (puzNamespace)
{
f_free( &puzNamespace);
}
if (pNameTable)
{
pNameTable->Release();
}
return( rc);
}
/***************************************************************************
Desc: Determine if a NODE is an index component.
***************************************************************************/
FSTATIC RCODE isIndexComponent(
F_Db * pDb,
F_DOMNode * pNode,
FLMBOOL * pbIsIndexComponent,
FLMUINT * puiElementNum)
{
RCODE rc = NE_XFLM_OK;
*pbIsIndexComponent = TRUE;
if( pNode->getNodeType() != ELEMENT_NODE)
{
*pbIsIndexComponent = FALSE;
goto Exit;
}
if( RC_BAD( rc = pNode->getNameId( pDb, puiElementNum)))
{
goto Exit;
}
switch (*puiElementNum)
{
case ELM_ELEMENT_COMPONENT_TAG:
case ELM_ATTRIBUTE_COMPONENT_TAG:
break;
default:
*pbIsIndexComponent = FALSE;
goto Exit;
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Compare the old index definition with the new to see if anything
changed - to determine if we really need to rebuild the index.
***************************************************************************/
FSTATIC FLMBOOL indexDefsSame(
IXD * pOldIxd,
IXD * pNewIxd
)
{
FLMBOOL bSame = FALSE;
ICD * pOldIcd;
ICD * pNewIcd;
if (pOldIxd->uiCollectionNum != pNewIxd->uiCollectionNum ||
pOldIxd->uiNumIcds != pNewIxd->uiNumIcds ||
pOldIxd->uiNumKeyComponents != pNewIxd->uiNumKeyComponents ||
pOldIxd->uiNumDataComponents != pNewIxd->uiNumDataComponents ||
~(pOldIxd->uiFlags & (IXD_OFFLINE | IXD_SUSPENDED)) !=
~(pNewIxd->uiFlags & (IXD_OFFLINE | IXD_SUSPENDED)) ||
pOldIxd->uiLanguage != pNewIxd->uiLanguage)
{
goto Exit;
}
// Traverse the ICDs and make sure they are the same
pOldIcd = pOldIxd->pIcdTree;
pNewIcd = pNewIxd->pIcdTree;
for (;;)
{
// Compare the ICDs
if (pOldIcd->uiDictNum != pNewIcd->uiDictNum ||
pOldIcd->uiFlags != pNewIcd->uiFlags ||
pOldIcd->uiCdl != pNewIcd->uiCdl ||
pOldIcd->uiKeyComponent != pNewIcd->uiKeyComponent ||
pOldIcd->uiDataComponent != pNewIcd->uiDataComponent ||
pOldIcd->uiLimit != pNewIcd->uiLimit)
{
goto Exit;
}
if (pOldIcd->pFirstChild)
{
if (!pNewIcd->pFirstChild)
{
// Old ICD has a child, new one doesn't, indexes are
// different.
goto Exit;
}
pOldIcd = pOldIcd->pFirstChild;
pNewIcd = pNewIcd->pFirstChild;
continue;
}
while (pOldIcd && !pOldIcd->pNextSibling)
{
// Old ICD has no next sibling, new one doesn't, indexes are
// different.
if (!pNewIcd || pNewIcd->pNextSibling)
{
goto Exit;
}
pOldIcd = pOldIcd->pParent;
pNewIcd = pNewIcd->pParent;
}
if (!pOldIcd)
{
// Traversed back to parent ICD for old ICD, but not
// for new ICD, indexes are different. However, this
// should never happen.
if (pNewIcd)
{
flmAssert( 0);
goto Exit;
}
break;
}
// OLD ICD has a sibling it can traverse to, new one
// doesn't, indexes are different.
if (!pNewIcd || !pNewIcd->pNextSibling)
{
goto Exit;
}
pOldIcd = pOldIcd->pNextSibling;
pNewIcd = pNewIcd->pNextSibling;
}
bSame = TRUE;
Exit:
return( bSame);
}
/***************************************************************************
Desc: Update an index definition.
***************************************************************************/
RCODE F_Dict::updateIndexDef(
F_Db * pDb,
FLMUINT64 ui64DocumentID,
FLMUINT uiIndexNum,
FLMBOOL bOpeningDict,
FLMBOOL bDeleting
)
{
RCODE rc = NE_XFLM_OK;
void * pvMark = m_dictPool.poolMark();
FLMUNICODE * puzIndexName = NULL;
F_DOMNode * pNode = NULL;
FLMUINT uiElementId;
FLMBOOL bIsIndexComponent;
FLMUINT uiComponentNum;
IXD * pIxd;
IXD * pOldIxd;
ICD * pIcd;
ICD * pLastIcd;
ICD * pTmpIcd;
FLMBOOL bLinkAsChild;
FLMBOOL bHadRequired;
FLMBOOL bSinglePath;
FLMBOOL bHasChildren;
FLMUINT uiEncId;
if (bOpeningDict)
{
flmAssert( !bDeleting);
pOldIxd = NULL;
}
else
{
if (RC_BAD( rc = getIndex( uiIndexNum, NULL, &pOldIxd, TRUE)))
{
if (rc == NE_XFLM_BAD_IX)
{
pOldIxd = NULL;
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
}
if (bDeleting)
{
flmAssert( uiIndexNum);
if (pOldIxd)
{
// Get rid of the old b-tree
if (RC_BAD( rc = pDb->m_pDatabase->lFileDelete( pDb, NULL, &pOldIxd->lfInfo,
(FLMBOOL)((pOldIxd->uiFlags & IXD_ABS_POS)
? (FLMBOOL)TRUE
: (FLMBOOL)FALSE),
(FLMBOOL)(pOldIxd->pFirstData
? (FLMBOOL)TRUE
: (FLMBOOL)FALSE))))
{
goto Exit;
}
// Remove from index fixup list if we are deleting an index.
// It is impossible to be deleting an index in a background
// thread, so if there is a fixup, it is here because the
// index was added during this transaction (in the background).
// If the transaction aborts the IXD will simply go away, and
// there will be no need to fix it up.
if (pDb->m_pIxdFixups)
{
IXD_FIXUP * pIxdFixup = pDb->m_pIxdFixups;
IXD_FIXUP * pPrevIxdFixup = NULL;
while (pIxdFixup && pIxdFixup->uiIndexNum != uiIndexNum)
{
pPrevIxdFixup = pIxdFixup;
pIxdFixup = pIxdFixup->pNext;
}
if (pIxdFixup)
{
if (pPrevIxdFixup)
{
pPrevIxdFixup->pNext = pIxdFixup->pNext;
}
else
{
pDb->m_pIxdFixups = pIxdFixup->pNext;
}
f_free( &pIxdFixup);
}
}
// On delete or modify index make sure something is in the stop list.
if (!(pDb->m_uiFlags & FDB_REPLAYING_RFL))
{
if( RC_BAD( rc = pDb->addToStopList( uiIndexNum)))
{
goto Exit;
}
}
// Unlink the old ICDs.
unlinkIcds( pOldIxd->pIcdTree);
}
// NOTE: It is possible that the index may not be in the
// index table yet, because dictDocumentDone had not been
// called to put it in there, but we are calling dictDocumentDone
// to remove it.
// Remove the tag number from the name table
m_pNameTable->removeTag( ELM_INDEX_TAG, uiIndexNum);
if (uiIndexNum >= m_uiLowestIxNum && uiIndexNum <= m_uiHighestIxNum)
{
m_ppIxdTbl [uiIndexNum - m_uiLowestIxNum] = NULL;
}
goto Exit;
}
// Allocate a new IXD
if (RC_BAD( rc = m_dictPool.poolCalloc( sizeof( IXD), (void **)&pIxd)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->getIndexDef( ui64DocumentID, &puzIndexName,
&pIxd->uiIndexNum, &pIxd->uiCollectionNum,
&pIxd->uiLanguage, &pIxd->uiFlags,
&pIxd->ui64LastDocIndexed,
&uiEncId,
&pNode, bOpeningDict, bDeleting)))
{
goto Exit;
}
if (!uiIndexNum)
{
uiIndexNum = pIxd->uiIndexNum;
}
else
{
flmAssert( uiIndexNum == pIxd->uiIndexNum);
}
pIxd->ui64IxDefNodeId = ui64DocumentID;
// Process each sub-element, setting up the path for the index
// Start at the first child
if (RC_BAD( rc = pNode->getFirstChild( pDb, (IF_DOMNode **)&pNode)))
{
// Change not-found to illegal index definition - must be at
// least one subordinate node.
if (rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET( NE_XFLM_ILLEGAL_INDEX_DEF);
}
goto Exit;
}
pLastIcd = NULL;
bLinkAsChild = TRUE;
bSinglePath = TRUE;
for (;;)
{
if (RC_BAD( rc = isIndexComponent( pDb, pNode, &bIsIndexComponent,
&uiElementId)))
{
goto Exit;
}
if (bIsIndexComponent)
{
// Allocate an ICD and link in
if (RC_BAD( rc = m_dictPool.poolCalloc( sizeof( ICD),
(void **)&pIcd)))
{
goto Exit;
}
pIcd->uiCdl = pIxd->uiNumIcds;
pIxd->uiNumIcds++;
pIcd->pIxd = pIxd;
pIcd->uiIndexNum = pIxd->uiIndexNum;
if (!pIxd->pIcdTree)
{
pIxd->pIcdTree = pIcd;
}
else if (bLinkAsChild)
{
// link as child
pLastIcd->pFirstChild = pIcd;
pIcd->pParent = pLastIcd;
if (pLastIcd->pPrevSibling)
{
bSinglePath = FALSE;
}
}
else
{
// link as sibling
pLastIcd->pNextSibling = pIcd;
if (pLastIcd->pFirstChild)
{
bSinglePath = FALSE;
}
pIcd->pPrevSibling = pLastIcd;
pIcd->pParent = pLastIcd->pParent;
}
bLinkAsChild = FALSE;
pLastIcd = pIcd;
if (RC_BAD( rc = pDb->getIndexComponentDef( this, pNode,
uiElementId, pIxd, pIcd)))
{
goto Exit;
}
// The ICD with a tag of ELM_ROOT_TAG cannot be
// linked as a child to another node. It always
// has to be the lone root ICD.
if (pIcd->uiDictNum == ELM_ROOT_TAG &&
(pIcd->pParent || pIcd->pNextSibling || pIcd->pPrevSibling))
{
rc = RC_SET( NE_XFLM_BAD_USE_OF_ELM_ROOT_TAG);
goto Exit;
}
// Make sure that this ICD does not have the same
// dictionary number as any prior sibling.
pTmpIcd = pIcd->pPrevSibling;
while (pTmpIcd)
{
if (pIcd->uiDictNum == pTmpIcd->uiDictNum &&
((pIcd->uiFlags & ICD_IS_ATTRIBUTE) ==
(pTmpIcd->uiFlags & ICD_IS_ATTRIBUTE)))
{
rc = RC_SET( NE_XFLM_DUP_SIBLING_IX_COMPONENTS);
goto Exit;
}
pTmpIcd = pTmpIcd->pPrevSibling;
}
// If the node was an attribute component, we are not interested in
// anything that might be subordinate to it - only siblings.
if (uiElementId == ELM_ATTRIBUTE_COMPONENT_TAG)
{
if ( RC_BAD( rc = pNode->hasChildren( pDb, &bHasChildren)))
{
goto Exit;
}
// Attribute components should not have children
if ( bHasChildren)
{
rc = RC_SET( NE_XFLM_ILLEGAL_INDEX_DEF);
goto Exit;
}
goto Get_Sibling;
}
// See if there is a child node
if (RC_OK( rc = pNode->getFirstChild( pDb, (IF_DOMNode **)&pNode)))
{
bLinkAsChild = TRUE;
continue;
}
if (rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
// Fall through to see if there are any sibling nodes
}
Get_Sibling:
if (RC_OK( rc = pNode->getNextSibling( pDb, (IF_DOMNode **)&pNode)))
{
continue;
}
if (rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
// No siblings, go to the parent node and see if it
// has a sibling
if (!pLastIcd || (pLastIcd = pLastIcd->pParent) == NULL)
{
break;
}
bLinkAsChild = FALSE;
if (RC_BAD( rc = pNode->getParentNode( pDb, (IF_DOMNode **)&pNode)))
{
// Should not be not-found - because we came down
// through a parent node.
flmAssert( rc != NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
goto Get_Sibling;
}
if (bSinglePath)
{
pIxd->uiFlags |= IXD_SINGLE_PATH;
}
// Look at all of the key components. Verify that we have all of the
// needed components and that none are missing. If none are set to
// ICD_REQUIRED_PIECE, set them all to ICD_REQUIRED_IN_SET
pIcd = pIxd->pFirstKey;
uiComponentNum = 1;
bHadRequired = FALSE;
while (pIcd)
{
if (pIcd->uiKeyComponent != uiComponentNum)
{
rc = RC_SET( NE_XFLM_MISSING_KEY_COMPONENT);
goto Exit;
}
if (pIcd->uiFlags & ICD_REQUIRED_PIECE)
{
pIcd->uiFlags |= ICD_REQUIRED_IN_SET;
bHadRequired = TRUE;
}
uiComponentNum++;
pIcd = pIcd->pNextKeyComponent;
}
// If we don't have at least one key component, the index
// definition is invalid
if (!pIxd->uiNumKeyComponents)
{
rc = RC_SET( NE_XFLM_ILLEGAL_INDEX_DEF);
goto Exit;
}
// If none of the key components were marked as required, mark
// them all as ICD_REQUIRED_IN_SET.
if (!bHadRequired)
{
pIcd = pIxd->pFirstKey;
while (pIcd)
{
pIcd->uiFlags |= ICD_REQUIRED_IN_SET;
pIcd = pIcd->pNextKeyComponent;
}
}
// Look at all of the data components. Verify that we have all of the
// needed components and that none are missing.
pIcd = pIxd->pFirstData;
uiComponentNum = 1;
while (pIcd)
{
if (pIcd->uiDataComponent != uiComponentNum)
{
rc = RC_SET( NE_XFLM_MISSING_DATA_COMPONENT);
goto Exit;
}
uiComponentNum++;
pIcd = pIcd->pNextDataComponent;
}
// Look at all of the leaf ICDs. They must be data components or
// key components.
pIcd = pIxd->pFirstContext;
while (pIcd)
{
// Context components cannot be leaf components - only data
// and key components can be at the leaf.
if (!pIcd->pFirstChild)
{
rc = RC_SET( NE_XFLM_ILLEGAL_INDEX_COMPONENT);
goto Exit;
}
pIcd = pIcd->pNextKeyComponent;
}
// Add to the tag table, unless we already have our quota of
// index names. Remove the tag by number first, in case
// it was renamed.
if (!bOpeningDict)
{
m_pNameTable->removeTag( ELM_INDEX_TAG, pIxd->uiIndexNum);
}
if (RC_BAD( rc = m_pNameTable->addTag( ELM_INDEX_TAG, puzIndexName, NULL,
pIxd->uiIndexNum, 0, NULL, 0,
bOpeningDict ? FALSE : TRUE)))
{
goto Exit;
}
// If we are not opening the dictionary and the indexes are
// the same, no need to change the index out
if (!bOpeningDict && pOldIxd && indexDefsSame( pOldIxd, pIxd))
{
// Discard the new IXD, it is not needed.
m_dictPool.poolReset( pvMark);
}
else
{
if (!bOpeningDict)
{
if (pOldIxd)
{
// If modifying make sure something is in the stop list.
if (!(pDb->m_uiFlags & FDB_REPLAYING_RFL))
{
if( RC_BAD( rc = pDb->addToStopList( uiIndexNum)))
{
goto Exit;
}
}
// Delete the old b-tree LFILE
if (RC_BAD( rc = pDb->m_pDatabase->lFileDelete( pDb,
NULL, &pOldIxd->lfInfo,
(FLMBOOL)((pOldIxd->uiFlags & IXD_ABS_POS)
? (FLMBOOL)TRUE
: (FLMBOOL)FALSE),
(FLMBOOL)(pOldIxd->pFirstData
? (FLMBOOL)TRUE
: (FLMBOOL)FALSE))))
{
goto Exit;
}
}
// Create a NEW LFILE for the index. If this is a new index
// definition, we have not yet created one. If this is a
// modified index definition, the old LFILE would have been
// deleted up above.
if (RC_BAD( rc = pDb->m_pDatabase->lFileCreate( pDb, &pIxd->lfInfo,
NULL, uiIndexNum, XFLM_LF_INDEX,
(FLMBOOL)((pIxd->uiFlags & IXD_ABS_POS)
? TRUE
: FALSE),
(FLMBOOL)(pIxd->pFirstData
? TRUE
: FALSE),
uiEncId)))
{
goto Exit;
}
}
// Make room in the table for the new index if necessary.
if (pIxd->uiIndexNum < m_uiLowestIxNum ||
pIxd->uiIndexNum > m_uiHighestIxNum)
{
if (RC_BAD( rc = reallocTbl( pIxd->uiIndexNum, sizeof( IXD *),
(void **)&m_ppIxdTbl,
&m_uiLowestIxNum,
&m_uiHighestIxNum, 20,
XFLM_MAX_INDEX_NUM)))
{
goto Exit;
}
}
// Link the new ICDs into their ICD chains and unlink the old ICDs
// from their ICD chains. We don't want to do either of these until
// we are sure we are going to succeed.
m_ppIxdTbl [pIxd->uiIndexNum - m_uiLowestIxNum] = pIxd;
if (RC_BAD( rc = linkIcds( pIxd->pIcdTree)))
{
goto Exit;
}
if (pOldIxd)
{
// Unlink the old ICDs.
unlinkIcds( pOldIxd->pIcdTree);
}
// Build the index, unless we are just opening the dictionary
if (!bOpeningDict)
{
if (RC_BAD( rc = pDb->buildIndex( uiIndexNum, pIxd->uiFlags)))
{
goto Exit;
}
}
}
Exit:
if (pNode)
{
pNode->Release();
}
if (puzIndexName)
{
f_free( &puzIndexName);
}
if (RC_BAD( rc))
{
m_dictPool.poolReset( pvMark);
}
return( rc);
}
/***************************************************************************
Desc: Retrieve a collection definition - get name and number.
***************************************************************************/
RCODE F_Db::getCollectionDef(
FLMUINT64 ui64DocumentID,
FLMUNICODE ** ppuzCollectionName,
FLMUINT * puiCollectionNumber,
FLMUINT * puiEncId
)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pNode = NULL;
F_CachedNode * pCachedNode;
IF_DOMNode * pAttr = NULL;
FLMBOOL bHadCollectionNumber = FALSE;
FLMBOOL bHadCollectionName = FALSE;
FLMUINT uiNameId;
// Set up defaults
if (ppuzCollectionName)
{
*ppuzCollectionName = NULL;
}
if (puiCollectionNumber)
{
*puiCollectionNumber = 0;
}
if (puiEncId)
{
*puiEncId = 0;
}
// Retrieve the root element of the collection definition
if (RC_BAD( rc = getNode( XFLM_DICT_COLLECTION, ui64DocumentID, &pNode)))
{
goto Exit;
}
flmAssert( pNode->getNodeType() == ELEMENT_NODE);
pCachedNode = pNode->m_pCachedNode;
if( !pCachedNode->hasAttributes())
{
rc = RC_SET( NE_XFLM_MISSING_COLLECTION_NUMBER);
goto Exit;
}
if( RC_BAD( rc = pNode->getFirstAttribute( this, &pAttr)))
{
goto Exit;
}
for( ;;)
{
if( RC_BAD( rc = pAttr->getNameId( this, &uiNameId)))
{
goto Exit;
}
switch( uiNameId)
{
case ATTR_NAME_TAG:
if (ppuzCollectionName)
{
if (RC_BAD( rc = pAttr->getUnicode( this, ppuzCollectionName)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalCollectionName(
*ppuzCollectionName)))
{
goto Exit;
}
}
bHadCollectionName = TRUE;
break;
case ATTR_DICT_NUMBER_TAG:
if (puiCollectionNumber)
{
if (RC_BAD( rc = pAttr->getUINT( this, puiCollectionNumber)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalCollectionNumber(
*puiCollectionNumber)))
{
goto Exit;
}
}
bHadCollectionNumber = TRUE;
break;
case ATTR_ENCRYPTION_ID_TAG:
if (puiEncId)
{
if (RC_BAD( rc = pAttr->getUINT( this, puiEncId)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalEncDefNumber(
*puiEncId)))
{
goto Exit;
}
}
break;
default:
// Ignore all other attributes
break;
}
if( RC_BAD( rc = pAttr->getNextSibling( this, &pAttr)))
{
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
}
// Make sure we had both a name and number specified
if (!bHadCollectionName)
{
rc = RC_SET( NE_XFLM_MISSING_COLLECTION_NAME);
goto Exit;
}
if (!bHadCollectionNumber)
{
rc = RC_SET( NE_XFLM_MISSING_COLLECTION_NUMBER);
goto Exit;
}
Exit:
if (pNode)
{
pNode->Release();
}
if (pAttr)
{
pAttr->Release();
}
return( rc);
}
/***************************************************************************
Desc: Parse a data dictionary collection definition.
***************************************************************************/
RCODE F_Dict::updateCollectionDef(
F_Db * pDb,
FLMUINT64 ui64DocumentID,
FLMUINT uiCollectionNum,
FLMBOOL bOpeningDict,
FLMBOOL bDeleting
)
{
RCODE rc = NE_XFLM_OK;
F_COLLECTION * pCollection;
F_COLLECTION * pOldCollection;
FLMUNICODE * puzCollectionName = NULL;
FLMUINT uiTmp;
FLMUINT uiEncId;
if (bOpeningDict)
{
flmAssert( !bDeleting);
pOldCollection = NULL;
}
else
{
if (RC_BAD( rc = getCollection( uiCollectionNum, &pOldCollection)))
{
if (rc == NE_XFLM_BAD_COLLECTION)
{
pOldCollection = NULL;
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
}
if (bDeleting)
{
flmAssert( uiCollectionNum);
if (pOldCollection)
{
if (RC_BAD( rc = pDb->m_pDatabase->lFileDelete( pDb,
pOldCollection, &pOldCollection->lfInfo, FALSE, TRUE)))
{
goto Exit;
}
}
pDb->removeCollectionNodes( uiCollectionNum,
pDb->m_ui64CurrTransID);
// NOTE: It is possible that the collection may not be in the
// collection table yet, because dictDocumentDone had not been
// called to put it in there, but we are calling dictDocumentDone
// to remove it.
// Remove the tag number from the name table
m_pNameTable->removeTag( ELM_COLLECTION_TAG, uiCollectionNum);
if (uiCollectionNum >= m_uiLowestCollectionNum &&
uiCollectionNum <= m_uiHighestCollectionNum)
{
m_ppCollectionTbl [uiCollectionNum - m_uiLowestCollectionNum] = NULL;
}
goto Exit;
}
// Allocate a new collection
if (RC_BAD( rc = m_dictPool.poolCalloc( sizeof( F_COLLECTION),
(void **)&pCollection)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->getCollectionDef( ui64DocumentID,
&puzCollectionName, &uiTmp, &uiEncId)))
{
goto Exit;
}
if (!uiCollectionNum)
{
uiCollectionNum = uiTmp;
}
else
{
flmAssert( uiCollectionNum == uiTmp);
}
if (!bOpeningDict)
{
// If this is not a new collection, get the LFILE info
// for new collection we just allocated.
if (pOldCollection)
{
f_memcpy( pCollection, pOldCollection, sizeof( F_COLLECTION));
}
else
{
flmAssert( !bDeleting);
// Create a NEW LFILE for the collection
if (RC_BAD( rc = pDb->m_pDatabase->lFileCreate( pDb,
&pCollection->lfInfo,
pCollection, uiCollectionNum,
XFLM_LF_COLLECTION,
FALSE, TRUE, uiEncId)))
{
goto Exit;
}
}
}
// Add to the tag table, unless we already have our quota of
// collection names. Remove the tag by number first, in case
// it was renamed.
if (!bOpeningDict)
{
m_pNameTable->removeTag( ELM_COLLECTION_TAG, uiCollectionNum);
}
if (RC_BAD( rc = m_pNameTable->addTag( ELM_COLLECTION_TAG, puzCollectionName,
NULL, uiCollectionNum, 0, NULL, 0,
bOpeningDict ? FALSE : TRUE)))
{
if (rc == NE_XFLM_EXISTS)
{
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
if (uiCollectionNum < m_uiLowestCollectionNum ||
uiCollectionNum > m_uiHighestCollectionNum)
{
if (RC_BAD( rc = reallocTbl( uiCollectionNum, sizeof( F_COLLECTION *),
(void **)&m_ppCollectionTbl,
&m_uiLowestCollectionNum,
&m_uiHighestCollectionNum, 20,
XFLM_MAX_COLLECTION_NUM)))
{
goto Exit;
}
}
m_ppCollectionTbl [uiCollectionNum - m_uiLowestCollectionNum] = pCollection;
Exit:
if (puzCollectionName)
{
f_free( &puzCollectionName);
}
return( rc);
}
/***************************************************************************
Desc: Retrieve a prefix definition - get name and number.
***************************************************************************/
RCODE F_Db::getPrefixDef(
F_Dict * pDict,
FLMUINT64 ui64DocumentID,
FLMUNICODE ** ppuzPrefixName,
FLMUINT * puiPrefixNumber)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pNode = NULL;
F_CachedNode * pCachedNode;
IF_DOMNode * pAttr = NULL;
FLMBOOL bHadPrefixNumber = FALSE;
FLMBOOL bHadPrefixName = FALSE;
FLMUINT uiNameId;
// Set up defaults
if (ppuzPrefixName)
{
*ppuzPrefixName = NULL;
}
if (puiPrefixNumber)
{
*puiPrefixNumber = 0;
}
// Retrieve the root element of the prefix definition
if (RC_BAD( rc = getNode( XFLM_DICT_COLLECTION, ui64DocumentID, &pNode)))
{
goto Exit;
}
flmAssert( pNode->getNodeType() == ELEMENT_NODE);
pCachedNode = pNode->m_pCachedNode;
if( !pCachedNode->hasAttributes())
{
rc = RC_SET( NE_XFLM_MISSING_PREFIX_NUMBER);
goto Exit;
}
if( RC_BAD( rc = pNode->getFirstAttribute( this, &pAttr)))
{
goto Exit;
}
for( ;;)
{
if( RC_BAD( rc = pAttr->getNameId( this, &uiNameId)))
{
goto Exit;
}
switch( uiNameId)
{
case ATTR_NAME_TAG:
{
FLMUINT uiPrefixLen;
FLMUINT uiBufferSize;
if (ppuzPrefixName)
{
if( RC_BAD( rc = pAttr->getUnicodeChars( this, &uiPrefixLen)))
{
goto Exit;
}
uiBufferSize = sizeof( FLMUNICODE) * (uiPrefixLen + 1);
if( RC_BAD( rc = pDict->m_dictPool.poolAlloc( uiBufferSize,
(void **)ppuzPrefixName)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->getUnicode( this, *ppuzPrefixName,
uiBufferSize, 0, uiPrefixLen, NULL)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalPrefixName( *ppuzPrefixName)))
{
goto Exit;
}
}
bHadPrefixName = TRUE;
break;
}
case ATTR_DICT_NUMBER_TAG:
{
if (puiPrefixNumber)
{
if (RC_BAD( rc = pAttr->getUINT( this, puiPrefixNumber)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalPrefixNumber(
*puiPrefixNumber)))
{
goto Exit;
}
}
bHadPrefixNumber = TRUE;
break;
}
default:
{
// Ignore all other attributes
break;
}
}
if( RC_BAD( rc = pAttr->getNextSibling( this, (IF_DOMNode **)&pAttr)))
{
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
}
// Make sure we had both a name and number specified
if (!bHadPrefixName)
{
rc = RC_SET( NE_XFLM_MISSING_PREFIX_NAME);
goto Exit;
}
if (!bHadPrefixNumber)
{
rc = RC_SET( NE_XFLM_MISSING_PREFIX_NUMBER);
goto Exit;
}
Exit:
if (pNode)
{
pNode->Release();
}
if (pAttr)
{
pAttr->Release();
}
return( rc);
}
/***************************************************************************
Desc: Parse a data dictionary prefix definition.
***************************************************************************/
RCODE F_Dict::updatePrefixDef(
F_Db * pDb,
FLMUINT64 ui64DocumentID,
FLMUINT uiPrefixNum,
FLMBOOL bOpeningDict,
FLMBOOL bDeleting)
{
RCODE rc = NE_XFLM_OK;
F_PREFIX * pPrefix = NULL;
F_PREFIX * pOldPrefix = NULL;
FLMUNICODE * puzPrefixName = NULL;
FLMUINT uiTmp;
void * pvMark = m_dictPool.poolMark();
if (bOpeningDict)
{
flmAssert( !bDeleting);
pOldPrefix = NULL;
}
else
{
if (RC_BAD( rc = getPrefix( uiPrefixNum, &pOldPrefix)))
{
if (rc == NE_XFLM_BAD_PREFIX)
{
pOldPrefix = NULL;
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
}
if (bDeleting)
{
flmAssert( uiPrefixNum);
// NOTE: It is possible that the prefix may not be in the
// collection table yet, because dictDocumentDone had not been
// called to put it in there, but we are calling dictDocumentDone
// to remove it.
// Remove the tag number from the name table
m_pNameTable->removeTag( ELM_PREFIX_TAG, uiPrefixNum);
if (uiPrefixNum >= m_uiLowestPrefixNum &&
uiPrefixNum <= m_uiHighestPrefixNum)
{
m_ppPrefixTbl [uiPrefixNum - m_uiLowestPrefixNum] = NULL;
}
goto Exit;
}
// Allocate a new prefix
if (RC_BAD( rc = m_dictPool.poolCalloc( sizeof( F_PREFIX),
(void **)&pPrefix)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->getPrefixDef( this, ui64DocumentID,
&puzPrefixName, &uiTmp)))
{
goto Exit;
}
if (!uiPrefixNum)
{
uiPrefixNum = uiTmp;
}
else
{
flmAssert( uiPrefixNum == uiTmp);
}
// Add to the tag table, unless we already have our quota of
// prefix names. Remove the tag by number first, in case
// it was renamed.
if (!bOpeningDict)
{
m_pNameTable->removeTag( ELM_PREFIX_TAG, uiPrefixNum);
}
if (RC_BAD( rc = m_pNameTable->addTag( ELM_PREFIX_TAG, puzPrefixName,
NULL, uiPrefixNum, 0, NULL, 0,
bOpeningDict ? FALSE : TRUE)))
{
goto Exit;
}
if (uiPrefixNum < m_uiLowestPrefixNum ||
uiPrefixNum > m_uiHighestPrefixNum)
{
if (RC_BAD( rc = reallocTbl( uiPrefixNum, sizeof( F_PREFIX *),
(void **)&m_ppPrefixTbl,
&m_uiLowestPrefixNum,
&m_uiHighestPrefixNum, 20,
XFLM_MAX_PREFIX_NUM)))
{
goto Exit;
}
}
pPrefix->ui64PrefixId = uiPrefixNum;
pPrefix->puzPrefixName = puzPrefixName;
m_ppPrefixTbl [uiPrefixNum - m_uiLowestPrefixNum] = pPrefix;
Exit:
if( RC_BAD( rc))
{
if( pvMark)
{
m_dictPool.poolReset( pvMark);
}
}
return( rc );
}
/***************************************************************************
Desc: Retrieve an encDef definition - get name and number and key
***************************************************************************/
RCODE F_Db::getEncDefDef(
F_Dict * pDict,
FLMUINT64 ui64DocumentID,
FLMUNICODE ** ppuzEncDefName,
FLMUINT * puiEncDefNumber,
FLMUINT * puiEncDefKeySize,
F_CCS ** ppCcs
)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pNode = NULL;
F_CachedNode * pCachedNode;
F_DOMNode * pAttr = NULL;
FLMBOOL bHadEncDefNumber = FALSE;
FLMBOOL bHadEncDefName = FALSE;
FLMBOOL bHadEncKey = FALSE;
FLMBOOL bHadEncKeySize = FALSE;
FLMBOOL bHadAlgorithm = FALSE;
FLMUINT uiNameId;
void * pvEncKeyBuf = NULL;
FLMUINT32 ui32EncKeyLen;
FLMBOOL bStartedUpdateTrans = FALSE;
FLMBOOL bRestartReadTrans = FALSE;
FLMBYTE * pszAlgorithm = NULL;
FLMUINT uiEncType = 0;
FLMUINT uiEncKeySize = 0;
// Set up defaults
if (ppuzEncDefName)
{
*ppuzEncDefName = NULL;
}
if (puiEncDefNumber)
{
*puiEncDefNumber = 0;
}
flmAssert( ppCcs);
if (*ppCcs)
{
(*ppCcs)->Release();
}
*ppCcs = NULL;
// Retrieve the root element of the encDef definition
if (RC_BAD( rc = getNode( XFLM_DICT_COLLECTION, ui64DocumentID, &pNode)))
{
goto Exit;
}
flmAssert( pNode->getNodeType() == ELEMENT_NODE);
pCachedNode = pNode->m_pCachedNode;
if( !pCachedNode->hasAttributes())
{
rc = RC_SET( NE_XFLM_MISSING_ENCDEF_NUMBER);
goto Exit;
}
if( RC_BAD( rc = pNode->getFirstAttribute( this, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
// Cycle through the attributes
for( ;;)
{
if( RC_BAD( rc = pAttr->getNameId( this, &uiNameId)))
{
goto Exit;
}
switch( uiNameId)
{
case ATTR_NAME_TAG:
{
FLMUINT uiEncDefLen;
FLMUINT uiBufferSize;
if (ppuzEncDefName)
{
if( RC_BAD( rc = pAttr->getUnicodeChars( this, &uiEncDefLen)))
{
goto Exit;
}
uiBufferSize = sizeof( FLMUNICODE) * (uiEncDefLen + 1);
if( RC_BAD( rc = pDict->m_dictPool.poolAlloc( uiBufferSize,
(void **)ppuzEncDefName)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->getUnicode( this, *ppuzEncDefName,
uiBufferSize, 0, uiEncDefLen, NULL)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalEncDefName( *ppuzEncDefName)))
{
goto Exit;
}
}
bHadEncDefName = TRUE;
break;
}
case ATTR_DICT_NUMBER_TAG:
{
if (puiEncDefNumber)
{
if (RC_BAD( rc = pAttr->getUINT( this, puiEncDefNumber)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalEncDefNumber(
*puiEncDefNumber)))
{
goto Exit;
}
}
bHadEncDefNumber = TRUE;
break;
}
case ATTR_ENCRYPTION_KEY_TAG:
{
FLMUINT uiBytesReturned;
if( RC_BAD( rc = pAttr->getDataLength( this, (FLMUINT *)&ui32EncKeyLen)))
{
goto Exit;
}
if( !ui32EncKeyLen)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
if( RC_BAD( rc = f_alloc( ui32EncKeyLen, &pvEncKeyBuf)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->getBinary( this, pvEncKeyBuf,
0, ui32EncKeyLen, &uiBytesReturned)))
{
goto Exit;
}
bHadEncKey = TRUE;
break;
}
case ATTR_ENCRYPTION_KEY_SIZE_TAG:
{
if (RC_BAD( rc = pAttr->getUINT( this, &uiEncKeySize)))
{
goto Exit;
}
// Note: Will validate the key size when we finish the loop.
bHadEncKeySize = TRUE;
break;
}
case ATTR_TYPE_TAG:
{
// Get the encryption Algorithm
if( RC_BAD( rc = pAttr->getUTF8( this, &pszAlgorithm)))
{
goto Exit;
}
if (RC_BAD( rc = fdictLegalEncDefType(
(char *)pszAlgorithm, &uiEncType)))
{
goto Exit;
}
bHadAlgorithm = TRUE;
break;
}
default:
{
// Ignore all other attributes
break;
}
}
if( RC_BAD( rc = pAttr->getNextSibling( this, (IF_DOMNode **)&pAttr)))
{
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
}
// Make sure we had both a name and number specified
if (!bHadEncDefName)
{
rc = RC_SET( NE_XFLM_MISSING_ENCDEF_NAME);
goto Exit;
}
if (!bHadEncDefNumber)
{
rc = RC_SET( NE_XFLM_MISSING_ENCDEF_NUMBER);
goto Exit;
}
if (bHadAlgorithm && bHadEncKeySize)
{
if (RC_BAD( rc = fdictLegalEncKeySize( uiEncType, uiEncKeySize)))
{
goto Exit;
}
}
else if (!bHadAlgorithm)
{
rc = RC_SET( NE_XFLM_MISSING_ENC_ALGORITHM);
goto Exit;
}
if (bHadEncKey)
{
if ((*ppCcs = f_new( F_CCS)) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
if (RC_BAD( rc = (*ppCcs)->init( FALSE, uiEncType)))
{
goto Exit;
}
if( RC_BAD( rc = (*ppCcs)->setKeyFromStore(
(FLMBYTE *)pvEncKeyBuf, NULL, m_pDatabase->m_pWrappingKey)))
{
goto Exit;
}
}
else
{
if (!bHadEncKeySize)
{
// Pick a key size based on the encryption algorithm.
(void)fdictGetLegalKeySize( uiEncType, &uiEncKeySize);
}
// This must be a new encryption definition that doesn't have a key yet.
// Generate a new encryption key and save it in the DOM node document.
// We will need an update transaction before we can proceed.
if ( getTransType() == XFLM_READ_TRANS)
{
// End this transaction
if (RC_BAD( rc = transCommit()))
{
goto Exit;
}
bRestartReadTrans = TRUE;
}
if ( getTransType() == XFLM_NO_TRANS)
{
if (RC_BAD( rc = transBegin( XFLM_UPDATE_TRANS)))
{
goto Exit;
}
bStartedUpdateTrans = TRUE;
}
if ((*ppCcs = f_new( F_CCS)) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
if (RC_BAD( rc = (*ppCcs)->init( FALSE, uiEncType)))
{
goto Exit;
}
TryNewKeySize:
if (RC_BAD( rc = (*ppCcs)->generateEncryptionKey( uiEncKeySize)))
{
if (!fdictGetLegalKeySize( uiEncType, &uiEncKeySize))
{
goto Exit;
}
rc = NE_XFLM_OK;
goto TryNewKeySize;
}
if (RC_BAD( rc = (*ppCcs)->getKeyToStore(
(FLMBYTE **)&pvEncKeyBuf, &ui32EncKeyLen, NULL,
m_pDatabase->m_pWrappingKey)))
{
goto Exit;
}
// Set the key in the DOM node as a binary string.
if (RC_BAD( rc = pNode->createAttribute( this,
ATTR_ENCRYPTION_KEY_TAG,
(IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->setBinary( this, pvEncKeyBuf, ui32EncKeyLen)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->addModeFlags( this,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
if (!bHadEncKeySize)
{
// Set the key size
if (RC_BAD( rc = pNode->createAttribute( this,
ATTR_ENCRYPTION_KEY_SIZE_TAG,
(IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->setUINT( this, uiEncKeySize)))
{
goto Exit;
}
}
else
{
if (RC_BAD( rc = pNode->getAttribute( this,
ATTR_ENCRYPTION_KEY_SIZE_TAG,
(IF_DOMNode **)&pAttr)))
{
goto Exit;
}
}
if (RC_BAD( rc = pAttr->addModeFlags( this,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
// End the transaction
if (bStartedUpdateTrans)
{
if (RC_BAD( rc = transCommit()))
{
goto Exit;
}
bStartedUpdateTrans = FALSE;
}
}
if (puiEncDefKeySize)
{
*puiEncDefKeySize = uiEncKeySize;
}
Exit:
if (RC_BAD( rc))
{
if (*ppCcs)
{
(*ppCcs)->Release();
*ppCcs = NULL;
}
}
if( bStartedUpdateTrans)
{
if( RC_OK( rc))
{
// Commit the update transaction
if (RC_BAD( rc = transCommit()))
{
(void)transAbort();
}
}
else
{
(void)transAbort();
}
}
if( bRestartReadTrans)
{
rc = transBegin( XFLM_READ_TRANS);
}
if( pNode)
{
pNode->Release();
}
if( pAttr)
{
pAttr->Release();
}
if( pvEncKeyBuf)
{
f_free( &pvEncKeyBuf);
}
if( pszAlgorithm)
{
f_free( &pszAlgorithm);
}
return( rc);
}
/***************************************************************************
Desc: Parse a data dictionary encryption definition.
***************************************************************************/
RCODE F_Dict::updateEncDef(
F_Db * pDb,
FLMUINT64 ui64DocumentID,
FLMUINT uiEncDefNum,
FLMBOOL bOpeningDict,
FLMBOOL bDeleting)
{
RCODE rc = NE_XFLM_OK;
F_ENCDEF * pEncDef = NULL;
F_ENCDEF * pOldEncDef;
FLMUNICODE * puzEncDefName = NULL;
FLMUINT uiTmp;
void * pvMark = m_dictPool.poolMark();
F_CCS * pCcs = NULL;
FLMUINT uiEncKeySize = 0;
if (bOpeningDict)
{
flmAssert( !bDeleting);
pOldEncDef = NULL;
}
else
{
if (RC_BAD( rc = getEncDef( uiEncDefNum, &pOldEncDef)))
{
if (rc == NE_XFLM_BAD_ENCDEF_NUM)
{
pOldEncDef = NULL;
rc = NE_XFLM_OK;
}
else
{
goto Exit;
}
}
}
if (bDeleting)
{
flmAssert( uiEncDefNum);
// NOTE: It is possible that the encdef may not be in the
// collection table yet, because dictDocumentDone had not been
// called to put it in there, but we are calling dictDocumentDone
// to remove it.
// Remove the tag number from the name table
// VISIT: Before we can delete the encryption definition tag, we need
// to be sure it is not being used. Take a look at the collection tag
// to see how they are controlled.
m_pNameTable->removeTag( ELM_ENCDEF_TAG, uiEncDefNum);
if (uiEncDefNum >= m_uiLowestEncDefNum &&
uiEncDefNum <= m_uiHighestEncDefNum)
{
m_ppEncDefTbl [uiEncDefNum - m_uiLowestEncDefNum] = NULL;
}
goto Exit;
}
if (!pOldEncDef)
{
// Allocate a new encdef
if (RC_BAD( rc = m_dictPool.poolCalloc( sizeof( F_ENCDEF),
(void **)&pEncDef)))
{
goto Exit;
}
if (RC_BAD( rc = pDb->getEncDefDef( this, ui64DocumentID,
&puzEncDefName, &uiTmp, &uiEncKeySize, &pCcs)))
{
goto Exit;
}
if (!uiEncDefNum)
{
uiEncDefNum = uiTmp;
}
else
{
flmAssert( uiEncDefNum == uiTmp);
}
// Add to the tag table, unless we already have our quota of
// encryption definition names. Remove the tag by number first, in case
// it was renamed.
if (!bOpeningDict)
{
m_pNameTable->removeTag( ELM_ENCDEF_TAG, uiEncDefNum);
}
if (RC_BAD( rc = m_pNameTable->addTag( ELM_ENCDEF_TAG, puzEncDefName,
NULL, uiEncDefNum, 0, NULL, 0,
bOpeningDict ? FALSE : TRUE)))
{
goto Exit;
}
if (uiEncDefNum < m_uiLowestEncDefNum ||
uiEncDefNum > m_uiHighestEncDefNum)
{
if (RC_BAD( rc = reallocTbl( uiEncDefNum, sizeof( F_ENCDEF *),
(void **)&m_ppEncDefTbl,
&m_uiLowestEncDefNum,
&m_uiHighestEncDefNum, 20,
XFLM_MAX_ENCDEF_NUM)))
{
goto Exit;
}
}
flmAssert(m_ppEncDefTbl [uiEncDefNum - m_uiLowestEncDefNum] == NULL);
pEncDef->ui64EncDefId = uiEncDefNum;
pEncDef->ui64DocumentId = ui64DocumentID;
pEncDef->puzEncDefName = puzEncDefName;
pEncDef->uiEncKeySize = uiEncKeySize;
pEncDef->pCcs = pCcs;
pEncDef->pCcs->AddRef();
m_ppEncDefTbl [uiEncDefNum - m_uiLowestEncDefNum] = pEncDef;
}
Exit:
if( RC_BAD( rc))
{
if( pvMark)
{
m_dictPool.poolReset( pvMark);
}
}
if (pCcs)
{
pCcs->Release();
}
return( rc );
}
/***************************************************************************
Desc: Update a definition in the in-memory dictionary - add, modify, or
delete it.
***************************************************************************/
RCODE F_Dict::updateDict(
F_Db * pDb,
FLMUINT uiDictType,
FLMUINT64 ui64DocumentID,
FLMUINT uiDictNumber,
FLMBOOL bOpeningDict,
FLMBOOL bDeleting)
{
RCODE rc = NE_XFLM_OK;
#ifdef FLM_DEBUG
if (!bOpeningDict)
{
flmAssert( pDb->m_uiFlags & FDB_UPDATED_DICTIONARY);
}
#endif
flmAssert( !pDb->m_pDatabase->m_pRfl ||
!pDb->m_pDatabase->m_pRfl->isLoggingEnabled() ||
pDb->getTransType() == XFLM_READ_TRANS);
// Commit any keys in the KREF buffers.
if (RC_BAD( rc = pDb->keysCommit( FALSE)))
{
goto Exit;
}
switch (uiDictType)
{
case ELM_ELEMENT_TAG:
if (RC_BAD( rc = updateElementDef( pDb, ui64DocumentID,
uiDictNumber, bOpeningDict, bDeleting)))
{
goto Exit;
}
break;
case ELM_ATTRIBUTE_TAG:
if (RC_BAD( rc = updateAttributeDef( pDb, ui64DocumentID,
uiDictNumber, bOpeningDict, bDeleting)))
{
goto Exit;
}
break;
case ELM_INDEX_TAG:
if (RC_BAD( rc = updateIndexDef( pDb, ui64DocumentID,
uiDictNumber, bOpeningDict, bDeleting)))
{
goto Exit;
}
break;
case ELM_COLLECTION_TAG:
if (RC_BAD( rc = updateCollectionDef( pDb,
ui64DocumentID, uiDictNumber,
bOpeningDict, bDeleting)))
{
goto Exit;
}
break;
case ELM_PREFIX_TAG:
if (RC_BAD( rc = updatePrefixDef( pDb,
ui64DocumentID, uiDictNumber,
bOpeningDict, bDeleting)))
{
goto Exit;
}
break;
case ELM_ENCDEF_TAG:
if (!pDb->m_pDatabase->m_bInLimitedMode)
{
if (RC_BAD( rc = updateEncDef( pDb,
ui64DocumentID, uiDictNumber,
bOpeningDict, bDeleting)))
{
goto Exit;
}
}
break;
default:
// May be other things in the dictionary that we don't care
// about
break;
}
// Commit any keys in the KREF buffers.
if (RC_BAD( rc = pDb->keysCommit( FALSE)))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Setup the predefined collections and indexes.
****************************************************************************/
RCODE F_Dict::setupPredefined(
FLMUINT uiDefaultLanguage)
{
RCODE rc = NE_XFLM_OK;
IXD * pIxd;
ICD * pIcd;
FLMUINT uiLoop;
ATTR_ELM_DEF * pElementDef;
ATTR_ELM_DEF * pAttributeDef;
// Set up reserved elements table
if (RC_BAD( rc = f_calloc( (XFLM_LAST_RESERVED_ELEMENT_TAG -
XFLM_FIRST_RESERVED_ELEMENT_TAG + 1) *
sizeof( ATTR_ELM_DEF),
&m_pReservedElementDefTbl)))
{
goto Exit;
}
// Set up reserved attributes table
if (RC_BAD( rc = f_calloc( (XFLM_LAST_RESERVED_ATTRIBUTE_TAG -
XFLM_FIRST_RESERVED_ATTRIBUTE_TAG + 1) *
sizeof( ATTR_ELM_DEF),
&m_pReservedAttributeDefTbl)))
{
goto Exit;
}
// Set the data types and state to active for all reserved elements and
// attributes.
for (uiLoop = 0; FlmReservedElementTags [uiLoop].pszTagName; uiLoop++)
{
pElementDef = &m_pReservedElementDefTbl [
FlmReservedElementTags [uiLoop].uiTagNum -
XFLM_FIRST_RESERVED_ELEMENT_TAG];
pElementDef->uiFlags =
(FlmReservedElementTags [uiLoop].uiDataType &
ATTR_ELM_DATA_TYPE_MASK) |
(ATTR_ELM_STATE_ACTIVE & ATTR_ELM_STATE_MASK);
}
for (uiLoop = 0; FlmReservedAttributeTags [uiLoop].pszTagName; uiLoop++)
{
FLMUINT uiTagNum = FlmReservedAttributeTags [uiLoop].uiTagNum;
pAttributeDef = &m_pReservedAttributeDefTbl[ uiTagNum -
XFLM_FIRST_RESERVED_ATTRIBUTE_TAG];
pAttributeDef->uiFlags =
(FlmReservedAttributeTags [uiLoop].uiDataType &
ATTR_ELM_DATA_TYPE_MASK) |
(ATTR_ELM_STATE_ACTIVE & ATTR_ELM_STATE_MASK);
// Special case for ATTR_XMLNS_XFLAIM_TAG and ATTR_XMLNS_TAG.
// These attributes allow applications to use "xmlns:xflaim" or
// "xmlns" in dictionary definitions without requiring the need
// to explicitly create an attribute definition for the "xmlns:xflaim"
// or "xmlns" attributes.
if( uiTagNum == ATTR_XMLNS_XFLAIM_TAG || uiTagNum == ATTR_XMLNS_TAG)
{
pAttributeDef->uiFlags |= ATTR_ELM_NS_DECL;
}
}
// Allocate memory for the predefined collections
if (RC_BAD( rc = m_dictPool.poolCalloc( sizeof( F_COLLECTION) * 3,
(void **)&m_pDictCollection)))
{
goto Exit;
}
m_pDataCollection = &m_pDictCollection[ 1];
m_pMaintCollection = &m_pDictCollection[ 2];
m_pDictCollection->lfInfo.uiLfNum = XFLM_DICT_COLLECTION;
m_pDictCollection->lfInfo.eLfType = XFLM_LF_COLLECTION;
m_pDataCollection->lfInfo.uiLfNum = XFLM_DATA_COLLECTION;
m_pDataCollection->lfInfo.eLfType = XFLM_LF_COLLECTION;
m_pMaintCollection->lfInfo.uiLfNum = XFLM_MAINT_COLLECTION;
m_pMaintCollection->lfInfo.eLfType = XFLM_LF_COLLECTION;
// Allocate IXDs for the predefined indexes.
if (RC_BAD( rc = m_dictPool.poolCalloc( sizeof( IXD) * 2,
(void **)&m_pNameIndex)))
{
goto Exit;
}
m_pNumberIndex = &m_pNameIndex [1];
// Initialize the name index IXD
pIxd = m_pNameIndex;
pIxd->uiIndexNum = XFLM_DICT_NAME_INDEX;
pIxd->uiCollectionNum = XFLM_DICT_COLLECTION;
// pIxd->pIcdTree = NULL; // Set by poolCalloc
// pIxd->pFirstKey = NULL; // Set by poolCalloc
// pIxd->pLastKey = NULL; // Set by poolCalloc
// pIxd->pFirstContext = NULL; // Set by poolCalloc
// pIxd->pLastContext = NULL; // Set by poolCalloc
// pIxd->pFirstData = NULL; // Set by poolCalloc
// pIxd->pLastData = NULL; // Set by poolCalloc
pIxd->uiNumIcds = 4;
pIxd->uiNumKeyComponents = 3;
pIxd->uiNumDataComponents = 1;
// pIxd->uiNumContextComponents = 0; // Set by poolCalloc
pIxd->uiFlags = IXD_SINGLE_PATH;
pIxd->uiLanguage = uiDefaultLanguage;
pIxd->ui64LastDocIndexed = ~((FLMUINT64)0);
pIxd->lfInfo.uiLfNum = XFLM_DICT_NAME_INDEX;
pIxd->lfInfo.eLfType = XFLM_LF_INDEX;
// Initialize the number index IXD
pIxd = m_pNumberIndex;
pIxd->uiIndexNum = XFLM_DICT_NUMBER_INDEX;
pIxd->uiCollectionNum = XFLM_DICT_COLLECTION;
// pIxd->pIcdTree = NULL; // Set by poolCalloc
// pIxd->pFirstKey = NULL; // Set by poolCalloc
// pIxd->pLastKey = NULL; // Set by poolCalloc
// pIxd->pFirstContext = NULL; // Set by poolCalloc
// pIxd->pLastContext = NULL; // Set by poolCalloc
// pIxd->pFirstData = NULL; // Set by poolCalloc
// pIxd->pLastData = NULL; // Set by poolCalloc
pIxd->uiNumIcds = 2;
pIxd->uiNumKeyComponents = 2;
// pIxd->uiNumDataComponents = 0; // Set by poolCalloc
// pIxd->uiNumContextComponents = 0; // Set by poolCalloc
pIxd->uiFlags = IXD_SINGLE_PATH;
pIxd->uiLanguage = uiDefaultLanguage;
pIxd->ui64LastDocIndexed = ~((FLMUINT64)0);
pIxd->lfInfo.uiLfNum = XFLM_DICT_NUMBER_INDEX;
pIxd->lfInfo.eLfType = XFLM_LF_INDEX;
// Set up the ICDs for the name index
if (RC_BAD( rc = m_dictPool.poolCalloc( sizeof( ICD) * 4,
(void **)&m_pNameIndex->pIcdTree)))
{
goto Exit;
}
pIcd = m_pNameIndex->pIcdTree;
m_pNameIndex->pFirstKey = pIcd;
pIcd->uiIndexNum = m_pNameIndex->uiIndexNum;
pIcd->pIxd = m_pNameIndex;
pIcd->uiDictNum = ELM_ROOT_TAG;
pIcd->uiFlags = ICD_PRESENCE | ICD_REQUIRED_PIECE;
// pIcd->uiCompareRules = 0; // Set by poolCalloc
// pIcd->pParent = NULL; // Set by poolCalloc
pIcd->pFirstChild = pIcd + 1;
// pIcd->pPrevSibling = NULL; // Set by poolCalloc
// pIcd->pNextSibling = NULL; // Set by poolCalloc
// pIcd->pPrevKeyComponent = NULL; // Set by poolCalloc
pIcd->pNextKeyComponent = pIcd + 1;
// pIcd->uiCdl = 0; // Set by poolCalloc
pIcd->uiKeyComponent = 1;
// pIcd->pPrevDataComponent = NULL; // Set by poolCalloc
// pIcd->pNextDataComponent = NULL; // Set by poolCalloc
// pIcd->uiDataComponent = 0; // Set by poolCalloc
// pIcd->uiLimit = 0; // Set by poolCalloc
icdSetDataType( pIcd, XFLM_NODATA_TYPE);
pIcd++;
pIcd->uiIndexNum = m_pNameIndex->uiIndexNum;
pIcd->pIxd = m_pNameIndex;
pIcd->uiDictNum = ATTR_NAME_TAG;
pIcd->uiFlags = ICD_VALUE | ICD_REQUIRED_PIECE | ICD_IS_ATTRIBUTE;
// pIcd->uiCompareRules = 0; // Set by poolCalloc
pIcd->pParent = m_pNameIndex->pIcdTree;
// pIcd->pFirstChild = NULL; // Set by poolCalloc
// pIcd->pPrevSibling = NULL; // Set by poolCalloc
pIcd->pNextSibling = pIcd + 1;
pIcd->pPrevKeyComponent = pIcd - 1;
pIcd->pNextKeyComponent = pIcd + 1;
pIcd->uiCdl = 1;
pIcd->uiKeyComponent = 2;
// pIcd->pPrevDataComponent = NULL; // Set by poolCalloc
// pIcd->pNextDataComponent = NULL; // Set by poolCalloc
// pIcd->uiDataComponent = 0; // Set by poolCalloc
// pIcd->uiLimit = 0; // Set by poolCalloc
icdSetDataType( pIcd, attrElmGetType(
getReservedAttributeDef( pIcd->uiDictNum)));
pIcd++;
m_pNameIndex->pLastKey = pIcd;
pIcd->uiIndexNum = m_pNameIndex->uiIndexNum;
pIcd->pIxd = m_pNameIndex;
pIcd->uiDictNum = ATTR_TARGET_NAMESPACE_TAG;
pIcd->uiFlags = ICD_VALUE | ICD_IS_ATTRIBUTE;
// pIcd->uiCompareRules = 0; // Set by poolCalloc
pIcd->pParent = m_pNameIndex->pIcdTree;
// pIcd->pFirstChild = NULL; // Set by poolCalloc
pIcd->pPrevSibling = pIcd - 1;
pIcd->pNextSibling = pIcd + 1;
pIcd->pPrevKeyComponent = pIcd - 1;
// pIcd->pNextKeyComponent = NULL; // Set by poolCalloc
pIcd->uiCdl = 2;
pIcd->uiKeyComponent = 3;
// pIcd->pPrevDataComponent = NULL; // Set by poolCalloc
// pIcd->pNextDataComponent = NULL; // Set by poolCalloc
// pIcd->uiDataComponent = 0; // Set by poolCalloc
// pIcd->uiLimit = 0; // Set by poolCalloc
icdSetDataType( pIcd, attrElmGetType(
getReservedAttributeDef( pIcd->uiDictNum)));
pIcd++;
m_pNameIndex->pFirstData = pIcd;
m_pNameIndex->pLastData = pIcd;
pIcd->uiIndexNum = m_pNameIndex->uiIndexNum;
pIcd->pIxd = m_pNameIndex;
pIcd->uiDictNum = ATTR_DICT_NUMBER_TAG;
pIcd->uiFlags = ICD_VALUE | ICD_IS_ATTRIBUTE;
// pIcd->uiCompareRules = 0; // Set by poolCalloc
pIcd->pParent = m_pNameIndex->pIcdTree;
// pIcd->pFirstChild = NULL; // Set by poolCalloc
pIcd->pPrevSibling = pIcd - 1;
// pIcd->pNextSibling = NULL; // Set by poolCalloc
// pIcd->pPrevKeyComponent = NULL; // Set by poolCalloc
// pIcd->pNextKeyComponent = NULL; // Set by poolCalloc
pIcd->uiCdl = 3;
// pIcd->uiKeyComponent = 0; // Set by poolCalloc
// pIcd->pPrevDataComponent = NULL; // Set by poolCalloc
// pIcd->pNextDataComponent = NULL; // Set by poolCalloc
pIcd->uiDataComponent = 1;
// pIcd->uiLimit = 0; // Set by poolCalloc
icdSetDataType( pIcd, attrElmGetType(
getReservedAttributeDef( pIcd->uiDictNum)));
// Set up the ICDs for the number index
if (RC_BAD( rc = m_dictPool.poolCalloc( sizeof( ICD) * 2,
(void **)&m_pNumberIndex->pIcdTree)))
{
goto Exit;
}
pIcd = m_pNumberIndex->pIcdTree;
pIcd->uiIndexNum = m_pNumberIndex->uiIndexNum;
m_pNumberIndex->pFirstKey = pIcd;
pIcd->pIxd = m_pNumberIndex;
pIcd->uiDictNum = ELM_ROOT_TAG;
pIcd->uiFlags = ICD_PRESENCE | ICD_REQUIRED_PIECE;
// pIcd->uiCompareRules = 0; // Set by poolCalloc
// pIcd->pParent = NULL; // Set by poolCalloc
pIcd->pFirstChild = pIcd + 1;
// pIcd->pPrevSibling = NULL; // Set by poolCalloc
// pIcd->pNextSibling = NULL; // Set by poolCalloc
// pIcd->pPrevKeyComponent = NULL; // Set by poolCalloc
pIcd->pNextKeyComponent = pIcd + 1;
// pIcd->uiCdl = 0; // Set by poolCalloc
pIcd->uiKeyComponent = 1;
// pIcd->pPrevDataComponent = NULL; // Set by poolCalloc
// pIcd->pNextDataComponent = NULL; // Set by poolCalloc
// pIcd->uiDataComponent = 0; // Set by poolCalloc
// pIcd->uiLimit = 0; // Set by poolCalloc
icdSetDataType( pIcd, XFLM_NODATA_TYPE);
pIcd++;
m_pNumberIndex->pLastKey = pIcd;
pIcd->uiIndexNum = m_pNumberIndex->uiIndexNum;
pIcd->pIxd = m_pNumberIndex;
pIcd->uiDictNum = ATTR_DICT_NUMBER_TAG;
pIcd->uiFlags = ICD_VALUE | ICD_REQUIRED_PIECE | ICD_IS_ATTRIBUTE;
// pIcd->uiCompareRules = 0; // Set by poolCalloc
pIcd->pParent = m_pNumberIndex->pIcdTree;
// pIcd->pFirstChild = NULL; // Set by poolCalloc
// pIcd->pPrevSibling = NULL; // Set by poolCalloc
// pIcd->pNextSibling = NULL; // Set by poolCalloc
pIcd->pPrevKeyComponent = pIcd - 1;
// pIcd->pNextKeyComponent = NULL; // Set by poolCalloc
pIcd->uiCdl = 1;
pIcd->uiKeyComponent = 2;
// pIcd->pPrevDataComponent = NULL; // Set by poolCalloc
// pIcd->pNextDataComponent = NULL; // Set by poolCalloc
// pIcd->uiDataComponent = 0; // Set by poolCalloc
// pIcd->uiLimit = 0; // Set by poolCalloc
icdSetDataType( pIcd, attrElmGetType(
getReservedAttributeDef( pIcd->uiDictNum)));
if (RC_BAD( rc = linkIcds( m_pNameIndex->pIcdTree)))
{
goto Exit;
}
if (RC_BAD( rc = linkIcds( m_pNumberIndex->pIcdTree)))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Allocate an element table.
****************************************************************************/
RCODE F_Dict::allocElementTable(
FLMUINT uiLowestElementNum,
FLMUINT uiHighestElementNum
)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCount;
// There should not already be an element table or an extended element
// table.
flmAssert( m_pElementDefTbl == NULL && m_pExtElementDefTbl == NULL &&
m_hExtElementDefMutex == F_MUTEX_NULL);
// No need for a fixed element table if we don't have any element
// numbers in that range.
if (uiHighestElementNum &&
uiLowestElementNum <= FLM_HIGH_FIXED_ELEMENT_NUM)
{
m_uiLowestElementNum = uiLowestElementNum;
if (uiHighestElementNum > FLM_HIGH_FIXED_ELEMENT_NUM)
{
m_uiHighestElementNum = FLM_HIGH_FIXED_ELEMENT_NUM;
}
else
{
m_uiHighestElementNum = uiHighestElementNum;
}
uiCount = m_uiHighestElementNum - m_uiLowestElementNum + 1;
if (RC_BAD( rc = f_calloc( uiCount * sizeof( ATTR_ELM_DEF),
&m_pElementDefTbl)))
{
goto Exit;
}
}
// See if we should allocate an extended element table
if (uiHighestElementNum >= FLM_LOW_EXT_ELEMENT_NUM)
{
FLMUINT uiNewSize = uiHighestElementNum %
MAX_EXT_ATTR_ELM_ARRAY_SIZE + 1000;
if (uiNewSize > MAX_EXT_ATTR_ELM_ARRAY_SIZE)
{
uiNewSize = MAX_EXT_ATTR_ELM_ARRAY_SIZE;
}
// Need to allocate a mutex too.
if (RC_BAD( rc = f_mutexCreate( &m_hExtElementDefMutex)))
{
goto Exit;
}
// Allocate a new array
if (RC_BAD( rc = f_calloc( sizeof( EXT_ATTR_ELM_DEF) * uiNewSize,
&m_pExtElementDefTbl)))
{
goto Exit;
}
m_uiExtElementDefTblSize = uiNewSize;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Allocate an attribute table.
****************************************************************************/
RCODE F_Dict::allocAttributeTable(
FLMUINT uiLowestAttributeNum,
FLMUINT uiHighestAttributeNum
)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCount;
// There should not already be an element table or an extended element
// table.
flmAssert( m_pAttributeDefTbl == NULL && m_pExtAttributeDefTbl == NULL &&
m_hExtAttributeDefMutex == F_MUTEX_NULL);
// No need for a fixed attribute table if we don't have any attribute
// numbers in that range.
if (uiHighestAttributeNum &&
uiLowestAttributeNum <= FLM_HIGH_FIXED_ATTRIBUTE_NUM)
{
m_uiLowestAttributeNum = uiLowestAttributeNum;
if (uiHighestAttributeNum > FLM_HIGH_FIXED_ELEMENT_NUM)
{
m_uiHighestAttributeNum = FLM_HIGH_FIXED_ELEMENT_NUM;
}
else
{
m_uiHighestAttributeNum = uiHighestAttributeNum;
}
uiCount = m_uiHighestAttributeNum - m_uiLowestAttributeNum + 1;
if (RC_BAD( rc = f_calloc( uiCount * sizeof( ATTR_ELM_DEF),
&m_pAttributeDefTbl)))
{
goto Exit;
}
}
// See if we should allocate an extended attribute table
if (uiHighestAttributeNum >= FLM_LOW_EXT_ATTRIBUTE_NUM)
{
FLMUINT uiNewSize = uiHighestAttributeNum %
MAX_EXT_ATTR_ELM_ARRAY_SIZE + 1000;
if (uiNewSize > MAX_EXT_ATTR_ELM_ARRAY_SIZE)
{
uiNewSize = MAX_EXT_ATTR_ELM_ARRAY_SIZE;
}
// Need to allocate a mutex too.
if (RC_BAD( rc = f_mutexCreate( &m_hExtAttributeDefMutex)))
{
goto Exit;
}
// Allocate a new array
if (RC_BAD( rc = f_calloc( sizeof( EXT_ATTR_ELM_DEF) * uiNewSize,
&m_pExtAttributeDefTbl)))
{
goto Exit;
}
m_uiExtAttributeDefTblSize = uiNewSize;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Allocate an index table.
****************************************************************************/
RCODE F_Dict::allocIndexTable(
FLMUINT uiLowestIndexNum,
FLMUINT uiHighestIndexNum
)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCount;
// There should not already be an index table.
flmAssert( m_ppIxdTbl == NULL);
m_uiLowestIxNum = uiLowestIndexNum;
m_uiHighestIxNum = uiHighestIndexNum;
if ((uiCount = getIndexCount( FALSE)) > 0)
{
if (RC_BAD( rc = f_calloc( uiCount * sizeof( IXD *), &m_ppIxdTbl)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Allocate a prefix table.
****************************************************************************/
RCODE F_Dict::allocPrefixTable(
FLMUINT uiLowestPrefixNum,
FLMUINT uiHighestPrefixNum
)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCount;
flmAssert( m_ppPrefixTbl == NULL);
m_uiLowestPrefixNum = uiLowestPrefixNum;
m_uiHighestPrefixNum = uiHighestPrefixNum;
if ((uiCount = getPrefixCount()) > 0)
{
if (RC_BAD( rc = f_calloc( uiCount * sizeof( F_PREFIX *), &m_ppPrefixTbl)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Allocate an encdef table.
****************************************************************************/
RCODE F_Dict::allocEncDefTable(
FLMUINT uiLowestEncDefNum,
FLMUINT uiHighestEncDefNum
)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCount;
flmAssert( m_ppEncDefTbl == NULL);
m_uiLowestEncDefNum = uiLowestEncDefNum;
m_uiHighestEncDefNum = uiHighestEncDefNum;
if ((uiCount = getEncDefCount()) > 0)
{
if (RC_BAD( rc = f_calloc( uiCount * sizeof( F_ENCDEF *), &m_ppEncDefTbl)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Allocate a collection table.
****************************************************************************/
RCODE F_Dict::allocCollectionTable(
FLMUINT uiLowestCollectionNum,
FLMUINT uiHighestCollectionNum
)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCount;
// There should not already be a collection table.
flmAssert( m_ppCollectionTbl == NULL);
m_uiLowestCollectionNum = uiLowestCollectionNum;
m_uiHighestCollectionNum = uiHighestCollectionNum;
if ((uiCount = getCollectionCount( FALSE)) > 0)
{
if (RC_BAD( rc = f_calloc( uiCount * sizeof( LFILE *),
&m_ppCollectionTbl)))
{
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Find the node IDs where we keep the next element, next attribute,
next index, and next collection numbers.
****************************************************************************/
RCODE F_Dict::createNextDictNums(
F_Db * pDb)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pNode = NULL;
F_DOMNode * pAttr = NULL;
// Create a new root element
if (RC_BAD( rc = pDb->createRootElement( XFLM_DICT_COLLECTION,
ELM_NEXT_DICT_NUMS_TAG, (IF_DOMNode **)&pNode)))
{
goto Exit;
}
if( RC_BAD( rc = pNode->addModeFlags( pDb,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
// The NODE ID of this element had better be 1, because it is the
// first thing we create in the dictionary. Plus, the
// getNextDictNumNodeIds method is counting on it being one!
if( pNode->getNodeId() != XFLM_DICTINFO_DOC_ID)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
// Create and populate the four attributes that hold next element,
// next attribute, next index, and next collection numbers.
// Freeze each of the nodes so that they can only be modified by
// FLAIM.
// Node for next element number
if (RC_BAD( rc = pNode->createAttribute( pDb,
ATTR_NEXT_ELEMENT_NUM_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->setUINT( pDb, 1)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->addModeFlags( pDb,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
// Node for next attribute number
if (RC_BAD( rc = pNode->createAttribute( pDb,
ATTR_NEXT_ATTRIBUTE_NUM_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->setUINT( pDb, 1)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->addModeFlags( pDb,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
// Node for next index number
if (RC_BAD( rc = pNode->createAttribute( pDb,
ATTR_NEXT_INDEX_NUM_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->setUINT( pDb, 1)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->addModeFlags( pDb,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
// Node for next collection number
if (RC_BAD( rc = pNode->createAttribute( pDb,
ATTR_NEXT_COLLECTION_NUM_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->setUINT( pDb, 1)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->addModeFlags( pDb,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
// Node for next prefix number
if (RC_BAD( rc = pNode->createAttribute( pDb,
ATTR_NEXT_PREFIX_NUM_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->setUINT( pDb, 1)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->addModeFlags( pDb,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
// Node for next encdef number
if (RC_BAD( rc = pNode->createAttribute( pDb,
ATTR_NEXT_ENCDEF_NUM_TAG, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->setUINT( pDb, 1)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->addModeFlags( pDb,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
Exit:
if (pNode)
{
pNode->Release();
}
if (pAttr)
{
pAttr->Release();
}
return( rc);
}
/****************************************************************************
Desc: Allocate the next dictionary number for a specific dictionary type.
****************************************************************************/
RCODE F_Dict::allocNextDictNum(
F_Db * pDb,
FLMUINT uiDictType,
FLMUINT * puiDictNumber)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pDoc = NULL;
F_DOMNode * pAttr = NULL;
FLMUINT uiAttrName;
FLMUINT uiMaxNum;
if( RC_BAD( rc = pDb->getNode(
XFLM_DICT_COLLECTION, XFLM_DICTINFO_DOC_ID, &pDoc)))
{
if (rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = NE_XFLM_OK;
}
goto Exit;
}
if( pDoc->getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
switch (uiDictType)
{
case ELM_ELEMENT_TAG:
uiAttrName = ATTR_NEXT_ELEMENT_NUM_TAG;
uiMaxNum = XFLM_MAX_ELEMENT_NUM;
break;
case ELM_ATTRIBUTE_TAG:
uiAttrName = ATTR_NEXT_ATTRIBUTE_NUM_TAG;
uiMaxNum = XFLM_MAX_ATTRIBUTE_NUM;
break;
case ELM_INDEX_TAG:
uiAttrName = ATTR_NEXT_INDEX_NUM_TAG;
uiMaxNum = XFLM_MAX_INDEX_NUM;
break;
case ELM_COLLECTION_TAG:
uiAttrName = ATTR_NEXT_COLLECTION_NUM_TAG;
uiMaxNum = XFLM_MAX_COLLECTION_NUM;
break;
case ELM_PREFIX_TAG:
uiAttrName = ATTR_NEXT_PREFIX_NUM_TAG;
uiMaxNum = XFLM_MAX_PREFIX_NUM;
break;
case ELM_ENCDEF_TAG:
uiAttrName = ATTR_NEXT_ENCDEF_NUM_TAG;
uiMaxNum = XFLM_MAX_ENCDEF_NUM;
break;
default:
// Nothing to allocate for other types. *puiDictNumber will
// return as zero.
*puiDictNumber = 0;
goto Exit;
}
if( RC_BAD( rc = pDoc->getAttribute(
pDb, uiAttrName, (IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->getUINT( pDb, puiDictNumber)))
{
goto Exit;
}
// Dictionary number better be > 0
if( !(*puiDictNumber))
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
// See if we have exceeded the limit for this type.
if( *puiDictNumber > uiMaxNum)
{
*puiDictNumber = 0;
switch( uiDictType)
{
case ELM_ELEMENT_TAG:
rc = RC_SET( NE_XFLM_NO_MORE_ELEMENT_NUMS);
break;
case ELM_ATTRIBUTE_TAG:
rc = RC_SET( NE_XFLM_NO_MORE_ATTRIBUTE_NUMS);
break;
case ELM_INDEX_TAG:
rc = RC_SET( NE_XFLM_NO_MORE_INDEX_NUMS);
break;
case ELM_COLLECTION_TAG:
rc = RC_SET( NE_XFLM_NO_MORE_COLLECTION_NUMS);
break;
case ELM_PREFIX_TAG:
rc = RC_SET( NE_XFLM_NO_MORE_PREFIX_NUMS);
break;
case ELM_ENCDEF_TAG:
rc = RC_SET( NE_XFLM_NO_MORE_ENCDEF_NUMS);
}
goto Exit;
}
// Need to increment the dictionary number for the next
// caller.
if( RC_BAD( rc = pAttr->removeModeFlags(
pDb, FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
if (RC_BAD( rc = pAttr->setUINT( pDb, *puiDictNumber + 1)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->addModeFlags( pDb,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
Exit:
if( pAttr)
{
pAttr->Release();
}
if( pDoc)
{
pDoc->Release();
}
return( rc);
}
/****************************************************************************
Desc: Check and set the next dictionary number for a specific dictionary type.
****************************************************************************/
RCODE F_Dict::setNextDictNum(
F_Db * pDb,
FLMUINT uiDictType,
FLMUINT uiDictNumber)
{
RCODE rc = NE_XFLM_OK;
F_DOMNode * pDoc = NULL;
F_DOMNode * pAttr = NULL;
FLMUINT uiAttrName;
FLMUINT uiCurrDictNumber;
if( RC_BAD( rc = pDb->getNode(
XFLM_DICT_COLLECTION, XFLM_DICTINFO_DOC_ID, &pDoc)))
{
if (rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = NE_XFLM_OK;
}
goto Exit;
}
if( pDoc->getNodeType() != ELEMENT_NODE)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
switch( uiDictType)
{
case ELM_ELEMENT_TAG:
{
if( uiDictNumber > XFLM_MAX_ELEMENT_NUM)
{
rc = RC_SET( NE_XFLM_BAD_ELEMENT_NUM);
goto Exit;
}
uiAttrName = ATTR_NEXT_ELEMENT_NUM_TAG;
break;
}
case ELM_ATTRIBUTE_TAG:
{
if (uiDictNumber > XFLM_MAX_ATTRIBUTE_NUM)
{
rc = RC_SET( NE_XFLM_BAD_ATTRIBUTE_NUM);
goto Exit;
}
uiAttrName = ATTR_NEXT_ATTRIBUTE_NUM_TAG;
break;
}
case ELM_INDEX_TAG:
{
if (uiDictNumber > XFLM_MAX_INDEX_NUM)
{
rc = RC_SET( NE_XFLM_BAD_IX);
goto Exit;
}
uiAttrName = ATTR_NEXT_INDEX_NUM_TAG;
break;
}
case ELM_COLLECTION_TAG:
{
if (uiDictNumber > XFLM_MAX_COLLECTION_NUM)
{
rc = RC_SET( NE_XFLM_BAD_COLLECTION);
goto Exit;
}
uiAttrName = ATTR_NEXT_COLLECTION_NUM_TAG;
break;
}
case ELM_PREFIX_TAG:
{
if (uiDictNumber > XFLM_MAX_PREFIX_NUM)
{
rc = RC_SET( NE_XFLM_BAD_PREFIX);
goto Exit;
}
uiAttrName = ATTR_NEXT_PREFIX_NUM_TAG;
break;
}
case ELM_ENCDEF_TAG:
{
if (uiDictNumber > XFLM_MAX_ENCDEF_NUM)
{
rc = RC_SET( NE_XFLM_BAD_ENCDEF_NUM);
goto Exit;
}
uiAttrName = ATTR_NEXT_ENCDEF_NUM_TAG;
break;
}
default:
{
// Doesn't really matter on other dictionary types
// because dictionary number is not used for anything.
goto Exit;
}
}
if( RC_BAD( rc = pDoc->getAttribute( pDb, uiAttrName,
(IF_DOMNode **)&pAttr)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->getUINT( pDb, &uiCurrDictNumber)))
{
goto Exit;
}
// Dictionary number better be > 0
if( !uiCurrDictNumber)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
// If the new dictionary number >= current next dictionary
// number, need to set the next dictionary number to one greater
// than the new dictionary number.
if( uiDictNumber >= uiCurrDictNumber)
{
if( RC_BAD( rc = pAttr->removeModeFlags(
pDb, FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->setUINT( pDb, uiDictNumber + 1)))
{
goto Exit;
}
if( RC_BAD( rc = pAttr->addModeFlags( pDb,
FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
{
goto Exit;
}
}
Exit:
if( pAttr)
{
pAttr->Release();
}
if( pDoc)
{
pDoc->Release();
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
void F_AttrElmInfo::resetInfo( void)
{
m_uiDictNum = 0;
m_uiDataType = XFLM_NODATA_TYPE;
m_uiFlags = 0;
m_uiState = ATTR_ELM_STATE_ACTIVE;
m_pFirstIcd = NULL;
if( m_pDocNode)
{
m_pDocNode->Release();
m_pDocNode = NULL;
}
if( m_pTargetNamespaceAttr)
{
m_pTargetNamespaceAttr->Release();
m_pTargetNamespaceAttr = NULL;
}
if( m_pNameAttr)
{
m_pNameAttr->Release();
m_pNameAttr = NULL;
}
}
/****************************************************************************
Desc: Read in LFH headers.
****************************************************************************/
RCODE F_Db::dictReadLFH( void)
{
RCODE rc = NE_XFLM_OK;
LFILE * pLFile;
F_COLLECTION * pCollection;
F_CachedBlock * pSCache = NULL;
FLMBOOL bReleaseCache = FALSE;
F_BLK_HDR * pBlkHdr;
FLMUINT uiBlkAddress;
FLMUINT uiPos;
FLMUINT uiEndPos;
FLMUINT uiBlkSize = m_pDatabase->m_uiBlockSize;
LFILE TmpLFile;
F_COLLECTION TmpCollection;
f_memset( &TmpLFile, 0, sizeof( LFILE));
f_memset( &TmpCollection, 0, sizeof( F_COLLECTION));
uiBlkAddress =
(FLMUINT)m_pDatabase->m_lastCommittedDbHdr.ui32FirstLFBlkAddr;
while (uiBlkAddress)
{
if (RC_BAD( rc = m_pDatabase->getBlock( this, NULL,
uiBlkAddress, NULL, &pSCache)))
{
goto Exit;
}
bReleaseCache = TRUE;
pBlkHdr = pSCache->m_pBlkHdr;
uiPos = SIZEOF_STD_BLK_HDR;
uiEndPos = blkGetEnd( uiBlkSize, SIZEOF_STD_BLK_HDR, pBlkHdr);
// Read through all of the logical file definitions in the block
for( ; uiPos + sizeof( F_LF_HDR) <= uiEndPos; uiPos += sizeof( F_LF_HDR))
{
F_LF_HDR * pLfHdr = (F_LF_HDR *)((FLMBYTE *)(pBlkHdr) + uiPos);
eLFileType eLfType = (eLFileType)pLfHdr->ui32LfType;
// Have to fix up the offsets later when they are read in
if (eLfType == XFLM_LF_INVALID)
{
continue;
}
// Populate the LFILE in the dictionary, if one has been set up.
if (eLfType == XFLM_LF_INDEX)
{
FSLFileIn( (FLMBYTE *)pLfHdr,
&TmpLFile, NULL, uiBlkAddress, uiPos);
if (RC_OK( m_pDict->getIndex( TmpLFile.uiLfNum, &pLFile,
NULL, TRUE)))
{
f_memcpy( pLFile, &TmpLFile, sizeof( LFILE));
}
// LFILE better have a non-zero root block.
if (!TmpLFile.uiRootBlk)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
}
else
{
// Better be a container
flmAssert( eLfType == XFLM_LF_COLLECTION);
FSLFileIn( (FLMBYTE *)pLfHdr,
&TmpCollection.lfInfo, &TmpCollection, uiBlkAddress, uiPos);
if (RC_OK( m_pDict->getCollection( TmpCollection.lfInfo.uiLfNum,
&pCollection, TRUE)))
{
f_memcpy( pCollection, &TmpCollection, sizeof( F_COLLECTION));
}
// LFILE better have a non-zero root block.
if (!TmpCollection.lfInfo.uiRootBlk)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
}
}
// Get the next block in the chain
uiBlkAddress = (FLMUINT)pBlkHdr->ui32NextBlkInChain;
ScaReleaseCache( pSCache, FALSE);
bReleaseCache = FALSE;
}
Exit:
if (bReleaseCache)
{
ScaReleaseCache( pSCache, FALSE);
}
return( rc );
}
/****************************************************************************
Desc: Read in all element, attribute, index, or collection definitions - as
specified in uiDictType.
****************************************************************************/
RCODE F_Db::dictReadDefs(
FLMUINT uiDictType)
{
RCODE rc = NE_XFLM_OK;
F_DataVector key;
LFILE * pLFile;
IXD * pIxd;
F_Btree * pbTree = NULL;
FLMBYTE ucKeyBuf [XFLM_MAX_KEY_SIZE];
FLMUINT uiKeyLen;
FLMUINT uiFoundDictType;
FLMUINT uiLowest;
FLMUINT uiHighest;
FLMUINT uiDictNum;
IXKeyCompare compareObject;
if (RC_BAD( rc = m_pDict->getIndex( XFLM_DICT_NUMBER_INDEX, &pLFile, &pIxd)))
{
RC_UNEXPECTED_ASSERT( rc);
goto Exit;
}
// First determine the low and high field numbers.
// If the LFILE is not yet set up, the index has not yet been
// created, so there will be no definitions to read. This will
// be the case when we are first creating the dictionary. We have
// started a transaction, and it is trying to read in the definitions
// but there are none.
flmAssert( pLFile->uiRootBlk);
// Get a btree
if (RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pbTree)))
{
goto Exit;
}
// Open the B-Tree
compareObject.setIxInfo( this, pIxd);
compareObject.setCompareNodeIds( FALSE);
compareObject.setCompareDocId( FALSE);
compareObject.setSearchKey( &key);
if (RC_BAD( rc = pbTree->btOpen( this, pLFile, FALSE, FALSE,
&compareObject)))
{
goto Exit;
}
if (RC_BAD( rc = key.setUINT( 0, uiDictType)))
{
goto Exit;
}
if (RC_BAD( rc = key.outputKey( pIxd, 0,
ucKeyBuf, sizeof( ucKeyBuf), &uiKeyLen, SEARCH_KEY_FLAG)))
{
goto Exit;
}
// Position to the first key, if any
if (RC_BAD( rc = pbTree->btLocateEntry( ucKeyBuf, sizeof( ucKeyBuf),
&uiKeyLen, XFLM_INCL, NULL)))
{
// May not have found anything.
if (rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
{
rc = NE_XFLM_OK;
}
goto Exit;
}
key.reset();
if (RC_BAD( rc = key.inputKey( pIxd, ucKeyBuf, uiKeyLen)))
{
goto Exit;
}
// See if we went past the last key of this type.
if (RC_BAD( rc = key.getUINT( 0, &uiFoundDictType)))
{
goto Exit;
}
if (uiFoundDictType != uiDictType)
{
goto Exit; // Will return NE_XFLM_OK
}
if (RC_BAD( rc = key.getUINT( 1, &uiLowest)))
{
goto Exit;
}
uiHighest = uiLowest;
// Position to the end of keys of this type
key.reset();
if (RC_BAD( rc = key.setUINT( 0, uiDictType)))
{
goto Exit;
}
if (RC_BAD( rc = key.setUINT( 1, 0xFFFFFFFF)))
{
goto Exit;
}
if (RC_BAD( rc = key.outputKey( pIxd, 0,
ucKeyBuf, sizeof( ucKeyBuf), &uiKeyLen, SEARCH_KEY_FLAG)))
{
goto Exit;
}
// Position to just past the specified key.
if (RC_BAD( rc = pbTree->btLocateEntry( ucKeyBuf, sizeof( ucKeyBuf),
&uiKeyLen, XFLM_EXCL, NULL)))
{
// May not have found anything, in which case we need to
// position to the last key in the index.
if (rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
{
if (RC_BAD( rc = pbTree->btLastEntry( ucKeyBuf, sizeof( ucKeyBuf),
&uiKeyLen)))
{
goto Exit;
}
}
else
{
goto Exit;
}
}
else
{
// Backup one key - since we will have gone just beyond
// keys of this type.
if (RC_BAD( rc = pbTree->btPrevEntry( ucKeyBuf, sizeof( ucKeyBuf),
&uiKeyLen)))
{
goto Exit;
}
}
// At this point we better be positioned on the last key of this type
key.reset();
if (RC_BAD( rc = key.inputKey( pIxd, ucKeyBuf, uiKeyLen)))
{
goto Exit;
}
if (RC_BAD( rc = key.getUINT( 0, &uiFoundDictType)))
{
goto Exit;
}
// See if we went past the last key of this type - should not
// be possible, unless there is a corruption.
if (uiFoundDictType != uiDictType)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BTREE_ERROR);
goto Exit;
}
if (RC_BAD( rc = key.getUINT( 1, &uiHighest)))
{
goto Exit;
}
// uiHighest better be >= uiLowest or we have
// b-tree corruption.
if (uiHighest < uiLowest)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_BTREE_ERROR);
goto Exit;
}
// Pre-allocate the tables
if (uiDictType == ELM_ELEMENT_TAG)
{
if (RC_BAD( rc = m_pDict->allocElementTable( uiLowest, uiHighest)))
{
goto Exit;
}
}
else if (uiDictType == ELM_ATTRIBUTE_TAG)
{
if (RC_BAD( rc = m_pDict->allocAttributeTable( uiLowest, uiHighest)))
{
goto Exit;
}
}
else if (uiDictType == ELM_INDEX_TAG)
{
if (RC_BAD( rc = m_pDict->allocIndexTable( uiLowest, uiHighest)))
{
goto Exit;
}
}
else if (uiDictType == ELM_PREFIX_TAG)
{
if (RC_BAD( rc = m_pDict->allocPrefixTable( uiLowest, uiHighest)))
{
goto Exit;
}
}
else if (uiDictType == ELM_ENCDEF_TAG)
{
if (RC_BAD( rc = m_pDict->allocEncDefTable( uiLowest, uiHighest)))
{
goto Exit;
}
}
else // (uiDictType == ELM_COLLECTION_TAG)
{
flmAssert( uiDictType == ELM_COLLECTION_TAG);
if (RC_BAD( rc = m_pDict->allocCollectionTable( uiLowest, uiHighest)))
{
goto Exit;
}
}
// Position back to the first key for this type
key.reset();
if (RC_BAD( rc = key.setUINT( 0, uiDictType)))
{
goto Exit;
}
if (RC_BAD( rc = key.outputKey( pIxd, 0,
ucKeyBuf, sizeof( ucKeyBuf),
&uiKeyLen, SEARCH_KEY_FLAG)))
{
goto Exit;
}
if (RC_BAD( rc = pbTree->btLocateEntry( ucKeyBuf, sizeof( ucKeyBuf),
&uiKeyLen, XFLM_INCL, NULL)))
{
// May not have found anything.
if (rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
{
rc = NE_XFLM_OK;
}
goto Exit;
}
// Loop through all of the keys of this dictionary type
for (;;)
{
key.reset();
if (RC_BAD( rc = key.inputKey( pIxd, ucKeyBuf, uiKeyLen)))
{
goto Exit;
}
// See if we went past the last key of this type.
if (RC_BAD( rc = key.getUINT( 0, &uiFoundDictType)))
{
goto Exit;
}
if (uiFoundDictType != uiDictType)
{
break;
}
// Get the dictionary number
if (RC_BAD( rc = key.getUINT( 1, &uiDictNum)))
{
goto Exit;
}
// No need to process any more elements or attributes if the
// dictionary number is in the extended range.
if ((uiDictType == ELM_ELEMENT_TAG &&
uiDictNum >= FLM_LOW_EXT_ELEMENT_NUM) ||
(uiDictType == ELM_ATTRIBUTE_TAG &&
uiDictNum >= FLM_LOW_EXT_ATTRIBUTE_NUM))
{
if (uiDictType == ELM_ELEMENT_TAG)
{
m_pDict->m_pNameTable->m_bLoadedAllElements = FALSE;
}
else
{
m_pDict->m_pNameTable->m_bLoadedAllAttributes = FALSE;
}
break;
}
if (RC_BAD( rc = m_pDict->updateDict( this,
uiDictType, key.getDocumentID(), 0,
TRUE, FALSE)))
{
goto Exit;
}
// Go to the next key
if (RC_BAD( rc = pbTree->btNextEntry( ucKeyBuf,
sizeof( ucKeyBuf),
&uiKeyLen)))
{
// May not have found anything.
if (rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
{
rc = NE_XFLM_OK;
break;
}
goto Exit;
}
}
Exit:
if (pbTree)
{
gv_XFlmSysData.pBtPool->btpReturnBtree( &pbTree);
}
return( rc);
}
/****************************************************************************
Desc: Open a dictionary by reading in all of the dictionary tables
from the dictionaries.
****************************************************************************/
RCODE F_Db::dictOpen( void)
{
RCODE rc = NE_XFLM_OK;
// At this point, better not be pointing to a dictionary.
flmAssert( !m_pDict);
// Should never get here for a temporary database.
flmAssert( !m_pDatabase->m_bTempDb);
// Allocate a new F_Dict object for reading the dictionary
// into memory.
if ((m_pDict = f_new F_Dict) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
// Allocate the name table
if (RC_BAD( rc = m_pDict->allocNameTable()))
{
goto Exit;
}
// Add in all of the reserved dictionary tags to the name table.
if (RC_BAD( rc = m_pDict->getNameTable()->addReservedDictTags()))
{
goto Exit;
}
// Allocate the fixed collections and indexes and set them up
if (RC_BAD( rc = m_pDict->setupPredefined(
m_pDatabase->m_uiDefaultLanguage)))
{
goto Exit;
}
// Read in the LFH's for the predefined stuff.
if (RC_BAD( rc = dictReadLFH()))
{
goto Exit;
}
// If dictionary collection is not yet set up, do nothing.
if (m_pDict->m_pDictCollection->lfInfo.uiBlkAddress &&
m_pDict->m_pDictCollection->lfInfo.uiOffsetInBlk)
{
// Read in definitions in the following order:
// 1) attribute definitions
// 2) element definitions
// 3) collection definitions
// 4) index definitions
// This guarantees that things will be defined by the
// time they are referenced.
if (RC_BAD( rc = dictReadDefs( ELM_ATTRIBUTE_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = dictReadDefs( ELM_ELEMENT_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = dictReadDefs( ELM_COLLECTION_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = dictReadDefs( ELM_INDEX_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = dictReadDefs( ELM_PREFIX_TAG)))
{
goto Exit;
}
if (RC_BAD( rc = dictReadDefs( ELM_ENCDEF_TAG)))
{
goto Exit;
}
// Must read LFHs to get the LFILE information for the
// collections and indexes we have just added.
if (RC_BAD( rc = dictReadLFH()))
{
goto Exit;
}
}
m_pDict->getNameTable()->sortTags();
if (m_pDatabase)
{
m_pDict->m_bInLimitedMode = m_pDatabase->inLimitedMode();
}
// VISIT: Should we assume limited mode if we don't have a database file ?
Exit:
if (RC_BAD( rc) && m_pDict)
{
m_pDict->Release();
m_pDict = NULL;
}
return( rc);
}
/****************************************************************************
Desc: Creates a new dictionary for a database.
This occurs on database create and on a dictionary change.
****************************************************************************/
RCODE F_Db::createNewDict( void)
{
RCODE rc = NE_XFLM_OK;
// Unlink the DB from the current F_Dict object, if any.
if (m_pDict)
{
m_pDatabase->lockMutex();
unlinkFromDict();
m_pDatabase->unlockMutex();
}
// Allocate a new F_Dict object for the new dictionary we
// are going to create.
if (RC_BAD( rc = dictOpen()))
{
goto Exit;
}
// Update the F_Db flags to indicate that the dictionary
// was updated.
m_uiFlags |= FDB_UPDATED_DICTIONARY;
// Create a special document in the dictionary to hold
// the next element, next attribute, next index, and next
// collection numbers.
if (RC_BAD( rc = m_pDict->createNextDictNums( this)))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Add data dictionary records to the data dictionary.
****************************************************************************/
RCODE F_Db::dictCreate(
const char * pszDictPath, // Name of dictionary file. This is only
// used if dictBuf is NULL. If both
// dictPath and dictBuf are NULL, the
// database will be created with an empty
// dictionary
const char * pszDictBuf) // Buffer containing dictionary in ASCII
// GEDCOM If NULL pszDictPath will be used
{
RCODE rc = NE_XFLM_OK;
IF_FileHdl * pDictFileHdl = NULL;
FLMBOOL bFileOpen = FALSE;
LFILE TempLFile;
F_COLLECTION TempCollection;
char * pszXMLBuffer = NULL;
FLMUINT64 ui64FileSize;
FLMUINT uiBytesRead;
IF_BufferIStream * pStream = NULL;
// This should never be called for a temporary database.
flmAssert( !m_pDatabase->m_bTempDb);
// Create the default data collection
if (RC_BAD(rc = m_pDatabase->lFileCreate( this, &TempCollection.lfInfo,
&TempCollection, XFLM_DATA_COLLECTION, XFLM_LF_COLLECTION, FALSE, TRUE)))
{
goto Exit;
}
// Create the dictionary collection and indexes
if (RC_BAD(rc = m_pDatabase->lFileCreate( this, &TempCollection.lfInfo,
&TempCollection,
XFLM_DICT_COLLECTION, XFLM_LF_COLLECTION, FALSE, TRUE)))
{
goto Exit;
}
if (RC_BAD( rc = m_pDatabase->lFileCreate( this,
&TempLFile, NULL, XFLM_DICT_NUMBER_INDEX, XFLM_LF_INDEX, FALSE, FALSE)))
{
goto Exit;
}
if (RC_BAD( rc = m_pDatabase->lFileCreate( this,
&TempLFile, NULL, XFLM_DICT_NAME_INDEX, XFLM_LF_INDEX, FALSE, TRUE)))
{
goto Exit;
}
// Create the maintenance collection
if (RC_BAD(rc = m_pDatabase->lFileCreate( this, &TempCollection.lfInfo,
&TempCollection,
XFLM_MAINT_COLLECTION, XFLM_LF_COLLECTION, FALSE, TRUE)))
{
goto Exit;
}
// Create a new dictionary we can work with.
if (RC_BAD( rc = createNewDict()))
{
goto Exit;
}
// If we have an XML buffer, there is no need to open the file.
if (!pszDictBuf && pszDictPath)
{
if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->openFile(
pszDictPath, FLM_IO_RDONLY, &pDictFileHdl)))
{
goto Exit;
}
bFileOpen = TRUE;
// Get the file size and allocate a buffer to hold the entire thing.
if (RC_BAD( rc = pDictFileHdl->size( &ui64FileSize)))
{
goto Exit;
}
// Add 1 to size so we can NULL terminate the string we read.
if (RC_BAD( rc = f_alloc( (FLMUINT)(ui64FileSize + 1), &pszXMLBuffer)))
{
goto Exit;
}
// Read the entire file into the buffer
if (RC_BAD( rc = pDictFileHdl->read( 0, (FLMUINT)ui64FileSize,
pszXMLBuffer, &uiBytesRead)))
{
goto Exit;
}
pszXMLBuffer [uiBytesRead] = 0;
pszDictBuf = pszXMLBuffer;
}
if (!pszDictBuf || !(*pszDictBuf))
{
// Neither a dictionary buffer or file were specified.
goto Exit;
}
// Parse through the buffer, extracting each XML document,
// add to the dictionary and F_Dict object. The import method
// reads stuff from the stream, parses it into XML documents,
// and calls documentDone when the document is complete.
// The documentDone method checks the dictionary syntax,
// adds to the dictionary, etc.
if( RC_BAD( rc = FlmAllocBufferIStream( &pStream)))
{
goto Exit;
}
if (RC_BAD( rc = pStream->openStream( pszDictBuf, 0)))
{
goto Exit;
}
if (RC_BAD( import( pStream, XFLM_DICT_COLLECTION)))
{
goto Exit;
}
m_pDict->getNameTable()->sortTags();
Exit:
if( pStream)
{
pStream->Release();
}
if( bFileOpen)
{
pDictFileHdl->closeFile();
}
if( pDictFileHdl)
{
pDictFileHdl->Release();
}
if( pszXMLBuffer)
{
f_free( pszXMLBuffer);
}
return( rc);
}