//------------------------------------------------------------------------------ // 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); }