Files
mars-flaim/xflaim/src/frecread.cpp

5719 lines
117 KiB
C++

//------------------------------------------------------------------------------
// Desc: Routines for reading records from FLXIM 4.x databases
//
// Tabs: 3
//
// Copyright (c) 2003-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: frecread.cpp 3114 2006-01-19 13:22:45 -0700 (Thu, 19 Jan 2006) dsanders $
//------------------------------------------------------------------------------
#include "flaimsys.h"
static FLMBYTE gv_ucMaxBcdINT32[] = {0x21, 0x47, 0x48, 0x36, 0x47};
static FLMBYTE gv_ucMinBcdINT32[] = {0xB2, 0x14, 0x74, 0x83, 0x64, 0x8F};
static FLMBYTE gv_ucMaxBcdUINT32[] = {0x42, 0x94, 0x96, 0x72, 0x95};
typedef struct
{
const char * pszTagName;
FLMUINT uiTagNum;
FLMUINT uiFieldType;
} FLM_4x_DICT_TAG_INFO;
FLM_4x_DICT_TAG_INFO Flm4xDictTagInfo[] =
{
{FLM_4x_FIELD_TAG_NAME, FLM_4x_FIELD_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_INDEX_TAG_NAME, FLM_4x_INDEX_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_TYPE_TAG_NAME, FLM_4x_TYPE_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_CONTAINER_TAG_NAME, FLM_4x_CONTAINER_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_LANGUAGE_TAG_NAME, FLM_4x_LANGUAGE_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_OPTIONAL_TAG_NAME, FLM_4x_OPTIONAL_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_UNIQUE_TAG_NAME, FLM_4x_UNIQUE_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_KEY_TAG_NAME, FLM_4x_KEY_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_REFS_TAG_NAME, FLM_4x_REFS_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_AREA_TAG_NAME, FLM_4x_AREA_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_STATE_TAG_NAME, FLM_4x_STATE_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_BLOB_TAG_NAME, FLM_4x_BLOB_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_THRESHOLD_TAG_NAME, FLM_4x_THRESHOLD_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_SUFFIX_TAG_NAME, FLM_4x_SUFFIX_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_SUBDIRECTORY_TAG_NAME, FLM_4x_SUBDIRECTORY_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_RESERVED_TAG_NAME, FLM_4x_RESERVED_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_SUBNAME_TAG_NAME, FLM_4x_SUBNAME_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_NAME_TAG_NAME, FLM_4x_NAME_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_BASE_TAG_NAME, FLM_4x_BASE_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_CASE_TAG_NAME, FLM_4x_CASE_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_COMBINATIONS_TAG_NAME, FLM_4x_COMBINATIONS_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_COUNT_TAG_NAME, FLM_4x_COUNT_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_POSITIONING_TAG_NAME, FLM_4x_POSITIONING_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_PAIRED_TAG_NAME, FLM_4x_PAIRED_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_PARENT_TAG_NAME, FLM_4x_PARENT_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_POST_TAG_NAME, FLM_4x_POST_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_REQUIRED_TAG_NAME, FLM_4x_REQUIRED_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_USE_TAG_NAME, FLM_4x_USE_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_FILTER_TAG_NAME, FLM_4x_FILTER_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_LIMIT_TAG_NAME, FLM_4x_LIMIT_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_DICT_TAG_NAME, FLM_4x_DICT_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_RECINFO_TAG_NAME, FLM_4x_RECINFO_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_DRN_TAG_NAME, FLM_4x_DRN_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_DICT_SEQ_TAG_NAME, FLM_4x_DICT_SEQ_TAG, FLM_4x_TEXT_TYPE},
{FLM_4x_LAST_CONTAINER_INDEXED_TAG_NAME, FLM_4x_LAST_CONTAINER_INDEXED_TAG, FLM_4x_NUMBER_TYPE},
{FLM_4x_LAST_DRN_INDEXED_TAG_NAME, FLM_4x_LAST_DRN_INDEXED_TAG, FLM_4x_NUMBER_TYPE},
{FLM_4x_ONLINE_TRANS_ID_TAG_NAME, FLM_4x_ONLINE_TRANS_ID_TAG, FLM_4x_NUMBER_TYPE},
{NULL, 0}
};
/***************************************************************************
Desc:
****************************************************************************/
F_4xReader::F_4xReader()
{
m_tmpPool.poolInit( 32 * 1024);
m_pSuperHdl = NULL;
m_pLckFile = NULL;
m_uiMaxFileSize = 0;
m_pLFileTbl = NULL;
m_uiLFileCnt = 0;
m_uiFieldTblSize = 0;
m_puiFieldTbl = NULL;
m_ppBlockTbl = NULL;
m_uiBlockTblSize = 0;
m_uiDefaultContainer = 0;
m_pNameTable = NULL;
f_memset( &m_fileHdr, 0, sizeof( F_4x_FILE_HDR));
f_memset( &m_logHdr, 0, sizeof( F_4x_LOG_HDR));
}
/***************************************************************************
Desc:
****************************************************************************/
F_4xReader::~F_4xReader()
{
closeDatabase();
m_tmpPool.poolFree();
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::openDatabase(
char * pszPath)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucReadBuf = NULL;
FLMBYTE * pucPrefix;
FLMBYTE * pucFileHdr;
FLMBYTE * pucLogHdr;
FLMUINT uiBytesRead;
FLMUINT uiTmp;
F_FileHdl * pFileHdl = NULL;
flmAssert( !m_pSuperHdl);
if( (m_pSuperHdl = f_new F_SuperFileHdl) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
if( RC_BAD( rc = m_pSuperHdl->Setup( NULL, pszPath, NULL)))
{
goto Exit;
}
// We must have exclusive access.
if( RC_BAD( rc = createLckFile( pszPath)))
{
goto Exit;
}
// Read and verify the file and log headers.
if( RC_BAD( rc = m_pSuperHdl->GetFileHdl( 0, FALSE,
(IF_FileHdl **)&pFileHdl)))
{
goto Exit;
}
if( RC_BAD( rc = f_alloc( 2048, &pucReadBuf)))
{
goto Exit;
}
// Read the fixed information area
if( RC_BAD( rc = pFileHdl->Read( 0, 2048, pucReadBuf, &uiBytesRead)))
{
goto Exit;
}
*pucReadBuf = 0xFF;
pucPrefix = pucReadBuf;
pucFileHdr = &pucReadBuf[ FLM_4x_FLAIM_HEADER_START];
// Make sure we have a valid prefix
if( pucPrefix[ 1] != f_toascii('W') ||
pucPrefix[ 2] != f_toascii('P') ||
pucPrefix[ 3] != f_toascii('C'))
{
rc = RC_SET( NE_XFLM_NOT_FLAIM);
goto Exit;
}
// Extract the file header info
m_fileHdr.uiBlockSize = (FLMUINT)FB2UW( &pucFileHdr[ FLM_4x_DB_BLOCK_SIZE]);
m_fileHdr.uiAppMajorVer = pucPrefix[ 10];
m_fileHdr.uiAppMinorVer = pucPrefix[ 11];
m_fileHdr.uiDefaultLanguage = pucFileHdr[ FLM_4x_DB_DEFAULT_LANGUAGE];
m_fileHdr.uiVersionNum =
((FLMUINT16)(pucFileHdr[ FLM_4x_VER_POS] - ASCII_ZERO) * 100 +
(FLMUINT16)(pucFileHdr[ FLM_4x_MINOR_VER_POS] - ASCII_ZERO) * 10 +
(FLMUINT16)(pucFileHdr[ FLM_4x_SMINOR_VER_POS] - ASCII_ZERO));
// Is the block size valid?
if( m_fileHdr.uiBlockSize != 4096 &&
m_fileHdr.uiBlockSize != 8192)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
// Supported version?
switch( m_fileHdr.uiVersionNum)
{
case FLM_VER_4_0:
case FLM_VER_4_3:
case FLM_VER_4_31:
case FLM_VER_4_50:
case FLM_VER_4_51:
break;
default:
rc = RC_SET( NE_XFLM_UNSUPPORTED_VERSION);
goto Exit;
}
// Get other log header elements.
m_fileHdr.uiFirstLFHBlkAddr =
(FLMUINT)FB2UD( &pucFileHdr[ FLM_4x_DB_1ST_LFH_ADDR]);
if( pucFileHdr[ FLM_4x_FLAIM_NAME_POS ] != f_toascii( 'F') ||
pucFileHdr[ FLM_4x_FLAIM_NAME_POS + 1 ] != f_toascii( 'L') ||
pucFileHdr[ FLM_4x_FLAIM_NAME_POS + 2 ] != f_toascii( 'A') ||
pucFileHdr[ FLM_4x_FLAIM_NAME_POS + 3 ] != f_toascii( 'I') ||
pucFileHdr[ FLM_4x_FLAIM_NAME_POS + 4 ] != f_toascii( 'M'))
{
rc = RC_SET( NE_XFLM_NOT_FLAIM);
goto Exit;
}
// Set up the uiSigBitsInBlkSize member of the file
// header
m_fileHdr.uiSigBitsInBlkSize = 0;
uiTmp = m_fileHdr.uiBlockSize;
while( !(uiTmp & 0x0001))
{
m_fileHdr.uiSigBitsInBlkSize++;
uiTmp >>= 1;
}
// Get the log file header information
pucLogHdr = &pucReadBuf[ FLM_4x_DB_LOG_HEADER_START];
// Verify the checksums in the log header
if( lgHdrCheckSum( pucLogHdr, TRUE) != 0)
{
rc = RC_SET( NE_XFLM_BLOCK_CRC);
goto Exit;
}
m_logHdr.uiCurrTransID =
(FLMUINT)FB2UD( &pucLogHdr[ FLM_4x_LOG_CURR_TRANS_ID]);
m_logHdr.uiLogicalEOF =
(FLMUINT)FB2UD( &pucLogHdr[ FLM_4x_LOG_LOGICAL_EOF]);
m_logHdr.uiFirstAvailBlkAddr =
(FLMUINT)FB2UD( &pucLogHdr[ FLM_4x_LOG_PF_AVAIL_BLKS]);
m_logHdr.uiAvailBlkCount =
(FLMUINT)FB2UD( &pucLogHdr[ FLM_4x_LOG_PF_NUM_AVAIL_BLKS]);
// Get the maximum file size
if( m_fileHdr.uiVersionNum >= FLM_VER_4_3)
{
m_uiMaxFileSize = (FLMUINT)(FB2UW(&((pucLogHdr)[
FLM_4x_LOG_MAX_FILE_SIZE]))) << 16;
}
else
{
m_uiMaxFileSize = 0x7FF00000;
}
// Make sure that no recovery needs to be done.
if( (FLMUINT)FB2UD( &pucLogHdr[ FLM_4x_LOG_ROLLBACK_EOF]) !=
m_fileHdr.uiBlockSize ||
(FLMUINT)FB2UD( &pucLogHdr[ FLM_4x_LOG_PL_FIRST_CP_BLOCK_ADDR]))
{
rc = RC_SET( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
// Set the block size
m_pSuperHdl->ReleaseFile( (FLMUINT)0, TRUE);
m_pSuperHdl->SetBlockSize( m_fileHdr.uiBlockSize);
// Set up the block table
m_uiBlockTblSize = 1024;
if( RC_BAD( rc = f_calloc(
sizeof( F_Block *) * m_uiBlockTblSize, &m_ppBlockTbl)))
{
m_uiBlockTblSize = 0;
goto Exit;
}
// Set the default container
m_uiDefaultContainer = FLM_4x_DATA_CONTAINER;;
// Read the LFile table
if( RC_BAD( rc = readLFiles()))
{
goto Exit;
}
// Read the dictionary
if( RC_BAD( rc = readDictionary()))
{
goto Exit;
}
Exit:
if( pFileHdl)
{
m_pSuperHdl->ReleaseFile( (FLMUINT)0, TRUE);
}
if( pucReadBuf)
{
f_free( &pucReadBuf);
}
if( RC_BAD( rc))
{
closeDatabase();
}
return( rc);
}
/********************************************************************
Desc:
*********************************************************************/
FLMUINT F_4xReader::lgHdrCheckSum(
FLMBYTE * pucLogHdr,
FLMBOOL bCompare)
{
FLMUINT uiCnt;
FLMUINT uiTempSum;
FLMUINT uiCurrCheckSum;
FLMUINT uiTempSum2;
FLMUINT uiBytesToChecksum;
uiBytesToChecksum = (FB2UW( &pucLogHdr[
FLM_4x_LOG_FLAIM_VERSION]) < FLM_VER_4_3)
? 88
: 156;
if( (uiCurrCheckSum = (FLMUINT)FB2UW(
&pucLogHdr[ FLM_4x_LOG_HDR_CHECKSUM])) == 0xFFFF)
{
uiCurrCheckSum = 0;
}
if( bCompare && !uiCurrCheckSum)
{
return( 0);
}
for( uiTempSum = 0 - (FLMUINT)FB2UW( &pucLogHdr[ FLM_4x_LOG_HDR_CHECKSUM]),
uiCnt = 1 + uiBytesToChecksum / sizeof( FLMUINT16); --uiCnt != 0;)
{
uiTempSum += (FLMUINT)FB2UW( pucLogHdr);
pucLogHdr += sizeof( FLMUINT16);
}
if( (0 == (uiTempSum2 = (uiTempSum & 0xFFFF))) || (uiTempSum2 == 0xFFFF))
{
uiTempSum2 = 1;
}
return( (FLMUINT)(((bCompare) && (uiTempSum2 == uiCurrCheckSum))
? (FLMUINT)0
: uiTempSum2) );
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::createLckFile(
char * pszFilePath)
{
RCODE rc = NE_XFLM_OK;
char szLockPath[ F_PATH_MAX_SIZE];
char szDbBaseName[ F_FILENAME_SIZE];
char * pszFileExt;
F_FileHdl * pLockFileHdl = NULL;
// Extract the 8.3 name and put a .lck extension on it to create
// the full path for the .lck file.
if( RC_BAD( rc = gv_pFileSystem->pathReduce(
pszFilePath, szLockPath, szDbBaseName)))
{
goto Exit;
}
pszFileExt = &szDbBaseName[ 0];
while( (*pszFileExt) && (*pszFileExt != '.'))
{
pszFileExt++;
}
f_strcpy( pszFileExt, ".lck");
if (RC_BAD( rc = gv_pFileSystem->pathAppend( szLockPath, szDbBaseName)))
{
goto Exit;
}
if( (pLockFileHdl = f_new F_FileHdl) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
#ifndef FLM_UNIX
pLockFileHdl->setupFileHdl( 0, TRUE);
#else
// On Unix, we do not want to delete the file because it
// will succeed even if someone else has the file open.
pLockFileHdl->setupFileHdl( 0, FALSE);
#endif
if( RC_BAD( pLockFileHdl->Create( szLockPath,
XFLM_IO_RDWR | XFLM_IO_EXCL | XFLM_IO_SH_DENYRW)))
{
#ifndef FLM_UNIX
if (RC_BAD( gv_pFileSystem->Delete( szLockPath)))
{
rc = RC_SET( NE_XFLM_IO_ACCESS_DENIED);
goto Exit;
}
else if (RC_BAD( pLockFileHdl->Create( szLockPath,
XFLM_IO_RDWR | XFLM_IO_EXCL | XFLM_IO_SH_DENYRW)))
{
rc = RC_SET( NE_XFLM_IO_ACCESS_DENIED);
goto Exit;
}
#else
if( RC_BAD( pLockFileHdl->Open( szLockPath,
XFLM_IO_RDWR | XFLM_IO_SH_DENYRW)))
{
rc = RC_SET( NE_XFLM_IO_ACCESS_DENIED);
goto Exit;
}
#endif
}
#ifdef FLM_UNIX
if( RC_BAD( pLockFileHdl->Lock()))
{
rc = RC_SET( NE_XFLM_IO_ACCESS_DENIED);
goto Exit;
}
#endif
m_pLckFile = pLockFileHdl;
pLockFileHdl = NULL;
Exit:
if (pLockFileHdl)
{
pLockFileHdl->Close();
pLockFileHdl->Release();
}
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
void F_4xReader::closeDatabase( void)
{
FLMUINT uiLoop;
m_tmpPool.poolReset( NULL);
if( m_pLckFile)
{
m_pLckFile->Release();
m_pLckFile = NULL;
}
if( m_pSuperHdl)
{
m_pSuperHdl->Release();
}
if( m_pLFileTbl)
{
f_free( &m_pLFileTbl);
m_pLFileTbl = NULL;
}
m_uiLFileCnt = 0;
if( m_puiFieldTbl)
{
f_free( &m_puiFieldTbl);
m_puiFieldTbl = NULL;
}
m_uiFieldTblSize = 0;
if( m_ppBlockTbl)
{
for( uiLoop = 0; uiLoop < m_uiBlockTblSize; uiLoop++)
{
if( m_ppBlockTbl[ uiLoop])
{
m_ppBlockTbl[ uiLoop]->Release();
}
}
f_free( &m_ppBlockTbl);
}
m_uiBlockTblSize = 0;
if( m_pNameTable)
{
m_pNameTable->Release();
m_pNameTable = NULL;
}
m_uiMaxFileSize = 0;
f_memset( &m_fileHdr, 0, sizeof( F_4x_FILE_HDR));
f_memset( &m_logHdr, 0, sizeof( F_4x_LOG_HDR));
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::readLFiles( void)
{
RCODE rc = NE_XFLM_OK;
F_Block * pBlock = NULL;
FLMBYTE * pucBlk;
FLMUINT uiBlkAddress;
FLMUINT uiPos;
FLMUINT uiEndPos;
FLMUINT uiEstCount;
FLMUINT uiLFileCnt;
FLMUINT uiLFHCnt;
FLMUINT uiBlkSize = m_fileHdr.uiBlockSize;
F_4x_LFILE TmpLFile;
F_4x_LFILE * pLFile;
F_4x_LFILE * pLFiles = NULL;
f_memset( &TmpLFile, 0, sizeof( F_4x_LFILE));
for( uiEstCount = 0, uiLFileCnt = 4,
uiBlkAddress = m_fileHdr.uiFirstLFHBlkAddr;
uiBlkAddress != FLM_4x_BT_END;)
{
if( RC_BAD( rc = readBlock( uiBlkAddress, &pBlock)))
{
goto Exit;
}
pucBlk = pBlock->m_pucBlk;
uiPos = FLM_4x_BH_OVHD;
if( (uiEndPos = (FLMUINT)FB2UW(
&pucBlk[ FLM_4x_BH_ELM_END])) <= FLM_4x_BH_OVHD)
{
uiEndPos = FLM_4x_BH_OVHD;
uiLFHCnt = 0;
}
else
{
if( uiEndPos > uiBlkSize)
{
uiEndPos = uiBlkSize;
}
uiLFHCnt = (FLMUINT)((uiEndPos - FLM_4x_BH_OVHD) / FLM_4x_LFH_SIZE);
uiEndPos = (FLMUINT)(FLM_4x_BH_OVHD + uiLFHCnt * FLM_4x_LFH_SIZE);
}
// May allocate too many like the inactive ones but OK for now.
// Allocate an additional 2 for the default data and dict containers.
if( !uiEstCount)
{
uiEstCount = uiLFHCnt + uiLFileCnt;
if( uiEstCount)
{
if( RC_BAD( rc = f_calloc(
uiEstCount * sizeof( F_4x_LFILE), &pLFiles)))
{
goto Exit;
}
}
}
else if( uiLFHCnt)
{
uiEstCount += uiLFHCnt;
if( RC_BAD(rc = f_recalloc( uiEstCount * sizeof( F_4x_LFILE),
&pLFiles)))
{
goto Exit;
}
}
// Read through all of the logical file definitions in the block
for( ; uiPos < uiEndPos; uiPos += FLM_4x_LFH_SIZE)
{
FLMUINT uiLfNum;
// Have to fix up the offsets later when they are read in
TmpLFile.uiBlkAddress = uiBlkAddress;
TmpLFile.uiOffsetInBlk = uiPos;
if( (TmpLFile.uiLfType =
(FLMUINT)pucBlk[ uiPos + FLM_4x_LFH_TYPE_OFFSET]) == FLM_4x_LF_INVALID)
{
TmpLFile.uiLfType = FLM_4x_LF_INVALID;
continue;
}
TmpLFile.uiLfNum =
(FLMUINT)FB2UW( &pucBlk[ uiPos + FLM_4x_LFH_LF_NUMBER_OFFSET]);
TmpLFile.uiRootBlk =
(FLMUINT)FB2UD( &pucBlk[ uiPos + FLM_4x_LFH_ROOT_BLK_OFFSET]);
TmpLFile.uiNextDrn =
(FLMUINT) FB2UD( &pucBlk[ uiPos + FLM_4x_LFH_NEXT_DRN_OFFSET]);
uiLfNum = TmpLFile.uiLfNum;
if( uiLfNum == FLM_4x_DATA_CONTAINER)
{
pLFile = pLFiles + FLM_4x_LFILE_DATA_CONTAINER_OFFSET;
}
else if( uiLfNum == FLM_4x_DICT_CONTAINER)
{
pLFile = pLFiles + FLM_4x_LFILE_DICT_CONTAINER_OFFSET;
}
else if( uiLfNum == FLM_4x_DICT_INDEX)
{
pLFile = pLFiles + FLM_4x_LFILE_DICT_INDEX_OFFSET;
}
else if( uiLfNum == FLM_4x_TRACKER_CONTAINER)
{
pLFile = pLFiles + FLM_4x_LFILE_TRACKER_CONTAINER_OFFSET;
}
else
{
pLFile = pLFiles + uiLFileCnt++;
}
f_memcpy( pLFile, &TmpLFile, sizeof( F_4x_LFILE));
}
// Get the next block in the chain
uiBlkAddress = (FLMUINT)FB2UD( &pucBlk[ FLM_4x_BH_NEXT_BLK]);
}
m_pLFileTbl = pLFiles;
m_uiLFileCnt = uiLFileCnt;
pLFiles = NULL;
Exit:
if( pBlock)
{
pBlock->Release();
}
if( pLFiles)
{
f_free( &pLFiles);
}
return( rc );
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::getLFile(
FLMUINT uiLFile,
F_4x_LFILE ** ppLFile)
{
RCODE rc = NE_XFLM_OK;
F_4x_LFILE * pLFile = NULL;
FLMUINT uiLoop;
if( uiLFile == FLM_4x_DATA_CONTAINER)
{
pLFile = &m_pLFileTbl[ FLM_4x_LFILE_DATA_CONTAINER_OFFSET];
}
else if( uiLFile == FLM_4x_DICT_CONTAINER)
{
pLFile = &m_pLFileTbl[ FLM_4x_LFILE_DICT_CONTAINER_OFFSET];
}
else if( uiLFile == FLM_4x_TRACKER_CONTAINER)
{
pLFile = &m_pLFileTbl[ FLM_4x_LFILE_TRACKER_CONTAINER_OFFSET];
}
else
{
for( uiLoop = 0; uiLoop < m_uiLFileCnt; uiLoop++)
{
if( m_pLFileTbl[ uiLoop].uiLfNum == uiLFile)
{
pLFile = &m_pLFileTbl[ uiLoop];
break;
}
}
}
if( !pLFile)
{
rc = RC_SET( NE_XFLM_BAD_COLLECTION);
goto Exit;
}
*ppLFile = pLFile;
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::getNextDrn(
FLMUINT uiContainer,
FLMUINT * puiDrn)
{
RCODE rc = NE_XFLM_OK;
BTSK stackBuf[ FLM_4x_BH_MAX_LEVELS ];
BTSK * pStack = stackBuf;
FLMBYTE * pucElm;
FLMBOOL bUsedStack = FALSE;
F_4x_LFILE * pLFile;
if( RC_BAD( rc = getLFile( uiContainer, &pLFile)))
{
goto Exit;
}
bUsedStack = TRUE;
initStack( &stackBuf[ 0]);
if( RC_BAD( rc = btSearchEnd( pLFile,
FLM_4x_DRN_LAST_MARKER, &pStack)))
{
goto Exit;
}
if( pLFile->uiRootBlk == FLM_4x_BT_END)
{
*puiDrn = pLFile->uiNextDrn;
}
else
{
if( pLFile->uiLfNum !=
FB2UW( &pStack->pBlk->m_pucBlk[ FLM_4x_BH_LOG_FILE_NUM]))
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
pucElm = FLM_4x_CURRENT_ELM( pStack);
pucElm += FLM_4x_BBE_GETR_KL( pucElm) + FLM_4x_BBE_KEY;
*puiDrn = FB2UD( pucElm);
}
Exit:
if( bUsedStack)
{
releaseStack( stackBuf);
}
return( rc);
}
/***************************************************************************
Desc: Search the right-most end of the b-tree.
****************************************************************************/
RCODE F_4xReader::btSearchEnd(
F_4x_LFILE * pLFile,
FLMUINT uiDrn,
BTSK ** ppStack)
{
RCODE rc = NE_XFLM_OK;
BTSK * pStack = *ppStack;
FLMBYTE ucKey[ FLM_4x_DIN_KEY_SIZ];
FLMUINT uiBlkAddr;
if( RC_BAD( rc = getRootBlock( pLFile, pStack)))
{
goto Exit;
}
longToByte( uiDrn, ucKey);
for(;;)
{
if( pStack->uiLevel)
{
pStack->uiCurElm = pStack->uiBlkEnd;
btPrevElm( pStack, pLFile);
}
else
{
if( pStack->uiBlkType != FLM_4x_BHT_NON_LEAF_DATA)
{
if( RC_BAD( rc = btScan( pStack, ucKey)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = btScanNonLeafData( pStack, uiDrn)))
{
goto Exit;
}
}
}
if( !pStack->uiLevel)
{
break;
}
uiBlkAddr = childBlkAddr( pStack);
pStack++;
if( RC_BAD( rc = getBlock( pLFile, uiBlkAddr, pStack)))
{
goto Exit;
}
}
*ppStack = pStack;
Exit:
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::readBlock(
FLMUINT uiBlkAddr,
F_Block ** ppBlock)
{
RCODE rc = NE_XFLM_OK;
F_Block * pBlock = NULL;
F_Block * pReuseBlock = NULL;
F_Block ** ppTblSlot = NULL;
if( *ppBlock)
{
(*ppBlock)->Release();
*ppBlock = NULL;
}
if( m_ppBlockTbl)
{
ppTblSlot = getHashBucket( uiBlkAddr);
pBlock = *ppTblSlot;
if( pBlock)
{
if( FLM_4x_GET_BH_ADDR( pBlock->m_pucBlk) != uiBlkAddr)
{
if( pBlock->getRefCount() == 1)
{
pReuseBlock = *ppTblSlot;
}
else
{
(*ppTblSlot)->Release();
}
pBlock = NULL;
*ppTblSlot = NULL;
}
else
{
pBlock->AddRef();
}
}
}
if( !pBlock)
{
if( pReuseBlock)
{
pBlock = pReuseBlock;
pReuseBlock = NULL;
}
else
{
if( (pBlock = f_new F_Block) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
}
if( RC_BAD( rc = pBlock->allocBlockBuf( m_fileHdr.uiBlockSize)))
{
goto Exit;
}
if( RC_BAD( rc = m_pSuperHdl->ReadBlock( uiBlkAddr,
m_fileHdr.uiBlockSize, pBlock->m_pucBlk, NULL)))
{
if( rc == NE_XFLM_IO_END_OF_FILE)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
// Verify the block checksum
if( RC_BAD( rc = blkCheckSum(
pBlock->m_pucBlk, uiBlkAddr, m_fileHdr.uiBlockSize)))
{
goto Exit;
}
// See if we even got the block we thought we wanted
if( FLM_4x_GET_BH_ADDR( pBlock->m_pucBlk) != uiBlkAddr)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
flmAssert( *ppTblSlot == NULL);
*ppTblSlot = pBlock;
pBlock->AddRef();
}
flmAssert( *ppTblSlot == pBlock);
*ppBlock = pBlock;
pBlock = NULL;
Exit:
if( pBlock)
{
pBlock->Release();
}
if( pReuseBlock)
{
pReuseBlock->Release();
}
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::blkCheckSum(
FLMBYTE * pucBlkPtr,
FLMUINT uiBlkAddress,
FLMUINT uiBlkSize)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiCnt;
FLMUINT uiAdds;
FLMUINT uiXORs;
FLMUINT uiCurrCheckSum;
FLMUINT uiNewCheckSum;
FLMUINT uiEncryptSize;
FLMBYTE * pucSaveBlkPtr = pucBlkPtr;
// Check the block length against the max. block size
uiEncryptSize = (FLMUINT)getEncryptSize( pucBlkPtr);
if( uiEncryptSize > uiBlkSize || uiEncryptSize < FLM_4x_BH_OVHD)
{
rc = RC_SET( NE_XFLM_BLOCK_CRC);
goto Exit;
}
uiCurrCheckSum = (FLMUINT)(((FLMUINT)pucBlkPtr[
FLM_4x_BH_CHECKSUM_HIGH] << 8) +
(FLMUINT)pucBlkPtr[ FLM_4x_BH_CHECKSUM_LOW]);
uiAdds = 0 - (pucBlkPtr[ FLM_4x_BH_CHECKSUM_LOW] +
pucBlkPtr[ FLM_4x_BH_CHECKSUM_HIGH]);
uiXORs = pucBlkPtr[ FLM_4x_BH_CHECKSUM_LOW] ^
pucBlkPtr[ FLM_4x_BH_CHECKSUM_HIGH];
if( uiBlkAddress != FLM_4x_BT_END)
{
uiAdds += (FLMBYTE)uiBlkAddress;
uiXORs ^= (FLMBYTE)uiBlkAddress;
}
for( uiCnt = uiEncryptSize; uiCnt--;)
{
uiAdds += *pucBlkPtr;
uiXORs ^= *(pucBlkPtr++);
}
uiNewCheckSum = (((uiAdds << 8) + uiXORs) & 0xFFFF);
if( uiBlkAddress == FLM_4x_BT_END )
{
FLMBYTE byXor;
FLMBYTE byAdd;
FLMBYTE byDelta;
// If there is a one byte value that will satisfy both
// sides of the checksum, the checksum is OK and that value
// is the first byte value.
byXor = (FLMBYTE) uiNewCheckSum;
byAdd = (FLMBYTE) (uiNewCheckSum >> 8);
byDelta = byXor ^ pucSaveBlkPtr[ FLM_4x_BH_CHECKSUM_LOW];
// This is the big check, if byDelta is also what is
// off with the add portion of the checksum, we have
// a good value.
if( ((FLMBYTE) (byAdd + byDelta)) ==
pucSaveBlkPtr[ FLM_4x_BH_CHECKSUM_HIGH])
{
// Set the low checksum value with the computed value.
pucSaveBlkPtr[ FLM_4x_BH_CHECKSUM_LOW] = byDelta;
goto Exit;
}
}
else
{
// This has the side effect of setting the low block address byte
// in the block thus getting rid of the low checksum byte.
//
// NOTE: We are allowing the case where the calculated checksum is
// zero and the stored checksum is one because we used to change
// a calculated zero to a one in old databases and store the one.
// This is probably a somewhat rare case (1 out of 65536 checksums
// will be zero), so forgiving it will be OK most of the time.
// So that those don't cause us to report block checksum errors,
// we just allow it - checksumming isn't a perfect check anyway.
if( uiNewCheckSum == uiCurrCheckSum ||
((!uiNewCheckSum) && (uiCurrCheckSum == 1)))
{
pucSaveBlkPtr[ FLM_4x_BH_CHECKSUM_LOW] = (FLMBYTE)uiBlkAddress;
goto Exit;
}
}
// Otherwise, we have a checksum error.
rc = RC_SET( NE_XFLM_BLOCK_CRC);
Exit:
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::retrieveRec(
FLMUINT uiContainer,
FLMUINT uiDrn,
FLMUINT uiFlags,
F_Record ** ppRecord)
{
RCODE rc = NE_XFLM_OK;
BTSK stackBuf[ FLM_4x_BH_MAX_LEVELS];
BTSK * pStack = NULL;
F_4x_LFILE * pLFile;
initStack( &stackBuf[ 0]);
pStack = stackBuf;
if( uiDrn >= (FLM_4x_DRN_LAST_MARKER - 1))
{
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
goto Exit;
}
if( RC_BAD( rc = getLFile( uiContainer, &pLFile)))
{
goto Exit;
}
if( uiFlags & XFLM_INCL)
{
// Search the for the record
if( RC_BAD( rc = btSearch( pLFile, uiDrn, &pStack)))
{
goto Exit;
}
if( byteToLong( pStack->ucKeyBuf) == FLM_4x_DRN_LAST_MARKER)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
flmAssert( byteToLong( pStack->ucKeyBuf) >= uiDrn);
}
else if( uiFlags & XFLM_EXCL)
{
// Search the for the record
if( RC_BAD( rc = btSearch( pLFile, uiDrn + 1, &pStack)))
{
goto Exit;
}
if( byteToLong( pStack->ucKeyBuf) == FLM_4x_DRN_LAST_MARKER)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
flmAssert( byteToLong( pStack->ucKeyBuf) > uiDrn);
}
else
{
// Search the for the record
if( RC_BAD( rc = btSearch( pLFile, uiDrn, &pStack)))
{
if( rc == NE_XFLM_EOF_HIT)
{
rc = RC_SET( NE_XFLM_NOT_FOUND);
}
goto Exit;
}
if( !pStack->uiKeyLen ||
byteToLong( pStack->ucKeyBuf) != uiDrn)
{
rc = RC_SET( NE_XFLM_NOT_FOUND);
goto Exit;
}
}
// Read the record
if( RC_BAD( rc = readRecElements( pStack, pLFile, ppRecord)))
{
goto Exit;
}
Exit:
releaseStack( stackBuf);
return( rc);
}
/***************************************************************************
Desc:
*****************************************************************************/
RCODE F_4xReader::retrieveNextRec(
F_Record ** ppRecord)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiDrn = 0;
FLMUINT uiContainer = m_uiDefaultContainer;
if( *ppRecord)
{
uiDrn = (*ppRecord)->getID();
uiContainer = (*ppRecord)->getContainerID();
}
if( RC_BAD( rc = retrieveRec( uiContainer, uiDrn, XFLM_EXCL, ppRecord)))
{
goto Exit;
}
Exit:
return( rc);
}
/**************************************************************************
Desc:
**************************************************************************/
void F_4xReader::releaseStack(
BTSK * pStack)
{
FLMUINT uiNumLevels = FLM_4x_BH_MAX_LEVELS;
while( uiNumLevels)
{
if( pStack->pBlk)
{
pStack->pBlk->Release();
pStack->pBlk = NULL;
}
uiNumLevels--;
pStack++;
}
}
/**************************************************************************
Desc:
**************************************************************************/
RCODE F_4xReader::readRecElements(
BTSK * pStack,
F_4x_LFILE * pLFile,
F_Record ** ppRecord)
{
RCODE rc = NE_XFLM_OK;
F_Record * pRecord = NULL;
FLMBYTE * pucCurElm;
void * pvMark = m_tmpPool.poolMark();
FLMUINT uiElmRecLen;
FLMUINT uiFieldLen;
FLMUINT uiFieldCount;
FLMUINT uiTrueDataSpace;
FLMUINT uiFieldPos;
TFIELD * pField;
FLDGROUP * pFldGroup = NULL;
FLDGROUP * pFirstFldGroup = NULL;
DATAPIECE * pDataPiece;
LOCKED_BLOCK * pLockedBlock = NULL;
FSTATE state;
// Initialize variables
state.uiLevel = 0;
uiFieldCount = 0;
uiTrueDataSpace = 0;
uiFieldPos = NUM_FIELDS_IN_ARRAY;
// Check to make sure we are positioned at the first element.
pucCurElm = FLM_4x_CURRENT_ELM( pStack);
if( !FLM_4x_BBE_IS_FIRST( pucCurElm))
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
// Loop on each element in the record
for( ;;)
{
// Setup all variables to process the current element
uiElmRecLen = FLM_4x_BBE_GET_RL( pucCurElm);
if( !uiElmRecLen)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
break;
}
pucCurElm += FLM_4x_BBE_REC_OFS( pucCurElm);
state.uiPosInElm = 0;
// Loop on each field within this element.
while( state.uiPosInElm < uiElmRecLen)
{
state.pElement = pucCurElm;
if( RC_BAD( rc = getFldOverhead( &state)))
{
goto Exit;
}
uiFieldLen = state.uiFieldLen;
// Old record info data - skip past for now
if( !state.uiTagNum)
{
state.uiPosInElm += uiFieldLen;
continue;
}
if( !pRecord)
{
// Create a new data record or use the existing data record.
if( *ppRecord)
{
// Reuse the existing F_Record object.
pRecord = *ppRecord;
*ppRecord = NULL;
pRecord->clear();
}
else
{
if( (pRecord = f_new F_Record) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
}
pRecord->setContainerID(
FB2UW( &pStack->pBlk->m_pucBlk[ FLM_4x_BH_LOG_FILE_NUM]));
pRecord->setID( byteToLong( pStack->ucKeyBuf));
}
// Check if out of fields in the tempoary field group
if( uiFieldPos >= NUM_FIELDS_IN_ARRAY)
{
FLDGROUP * pTempFldGroup;
uiFieldPos = 0;
// Allocate the first field group from the pool.
if( RC_BAD( rc = m_tmpPool.poolAlloc(
sizeof( FLDGROUP), (void **)&pTempFldGroup)))
{
goto Exit;
}
pTempFldGroup->pNext = NULL;
if( pFldGroup)
{
pFldGroup->pNext = pTempFldGroup;
}
else
{
pFirstFldGroup = pTempFldGroup;
}
pFldGroup = pTempFldGroup;
}
flmAssert( state.uiFieldType != FLM_4x_UNKNOWN_TYPE);
uiFieldCount++;
pField = &pFldGroup->pFields[ uiFieldPos++];
pField->uiLevel = state.uiLevel;
pField->uiFieldID = state.uiTagNum;
pField->uiFieldType = state.uiFieldType;
pField->uiFieldLen = state.uiFieldLen;
pDataPiece = &pField->DataPiece;
if( uiFieldLen)
{
FLMUINT uiDataPos = 0;
if( state.uiFieldLen > 4)
{
// Binary data needs to account for alignment issues.
if( state.uiFieldType == FLM_4x_BINARY_TYPE)
{
if( state.uiFieldLen >= 255)
{
// Align so that the data is aligned - not the length
uiTrueDataSpace += 2;
uiTrueDataSpace = ((uiTrueDataSpace + FLM_ALLOC_ALIGN) &
(~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF));
uiTrueDataSpace -= 2;
}
else
{
uiTrueDataSpace = ((uiTrueDataSpace + FLM_ALLOC_ALIGN) &
(~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF));
}
}
uiTrueDataSpace += state.uiFieldLen;
// For read only records, greater than 255 bytes are
// stored length preceded.
if( state.uiFieldLen >= 255)
{
uiTrueDataSpace += 2;
}
}
// Value may start in the next element.
while( uiDataPos < uiFieldLen)
{
// Need to read next element for the value portion?
if( state.uiPosInElm >= uiElmRecLen)
{
if( FLM_4x_BBE_IS_LAST( FLM_4x_CURRENT_ELM( pStack)))
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
// If we are going to the next block, lock down this block
// beacause data pointers are pointing to it.
if( RC_BAD( blkNextElm( pStack)))
{
LOCKED_BLOCK * pLastLockedBlock = pLockedBlock;
if( RC_BAD( rc = m_tmpPool.poolAlloc(
sizeof( LOCKED_BLOCK), (void **)&pLockedBlock)))
{
goto Exit;
}
pLockedBlock->pBlock = pStack->pBlk;
pLockedBlock->pBlock->AddRef();
pLockedBlock->pNext = pLastLockedBlock;
if( RC_BAD( rc = btNextElm( pStack, pLFile)))
{
goto Exit;
}
}
pucCurElm = FLM_4x_CURRENT_ELM( pStack);
uiElmRecLen = FLM_4x_BBE_GET_RL( pucCurElm);
pucCurElm += FLM_4x_BBE_REC_OFS( pucCurElm);
state.uiPosInElm = 0;
}
// Compare number of bytes left if value <= # bytes left in element
if( (uiFieldLen - uiDataPos) <=
(uiElmRecLen - state.uiPosInElm))
{
FLMUINT uiDelta = uiFieldLen - uiDataPos;
pDataPiece->pData = &pucCurElm[ state.uiPosInElm];
pDataPiece->uiLength = uiDelta;
state.uiPosInElm += uiDelta;
pDataPiece->pNext = NULL;
break;
}
else
{
// Take what is there and get next element to grab some more.
FLMUINT uiBytesToMove = uiElmRecLen - state.uiPosInElm;
DATAPIECE * pNextDataPiece;
pDataPiece->pData = &pucCurElm[ state.uiPosInElm];
pDataPiece->uiLength = uiBytesToMove;
state.uiPosInElm += uiBytesToMove;
uiDataPos += uiBytesToMove;
if( RC_BAD( rc = m_tmpPool.poolAlloc(
sizeof( DATAPIECE), (void **)&pNextDataPiece)))
{
goto Exit;
}
pDataPiece->pNext = pNextDataPiece;
pDataPiece = pNextDataPiece;
}
}
}
}
// Done?
if( FLM_4x_BBE_IS_LAST( FLM_4x_CURRENT_ELM( pStack)))
{
break;
}
// Position to next element
if( RC_BAD( blkNextElm( pStack)))
{
LOCKED_BLOCK * pLastLockedBlock = pLockedBlock;
if( RC_BAD( rc = m_tmpPool.poolAlloc(
sizeof( LOCKED_BLOCK), (void **)&pLockedBlock)))
{
goto Exit;
}
pLockedBlock->pBlock = pStack->pBlk;
pLockedBlock->pBlock->AddRef();
pLockedBlock->pNext = pLastLockedBlock;
if( RC_BAD( rc = btNextElm( pStack, pLFile)))
{
goto Exit;
}
}
// Corruption Check.
pucCurElm = FLM_4x_CURRENT_ELM( pStack);
if( FLM_4x_BBE_IS_FIRST( pucCurElm))
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
}
if( pRecord)
{
void * pvField;
if( RC_BAD( rc = pRecord->preallocSpace( uiTrueDataSpace)))
{
goto Exit;
}
pFldGroup = pFirstFldGroup;
for( uiFieldPos = 0; uiFieldCount--; uiFieldPos++)
{
if( uiFieldPos >= NUM_FIELDS_IN_ARRAY)
{
uiFieldPos = 0;
if( (pFldGroup = pFldGroup->pNext) == NULL)
{
break;
}
}
pField = &pFldGroup->pFields[ uiFieldPos];
if( RC_BAD( rc = pRecord->insertLast( pField->uiLevel, pField->uiFieldID,
pField->uiFieldType, &pvField)))
{
goto Exit;
}
if( pField->uiFieldLen)
{
FLMBYTE * pDataPtr; // Points to where the data will go.
pDataPiece = &pField->DataPiece;
pDataPtr = pRecord->getImportDataPtr( pvField,
pField->uiFieldType, pField->uiFieldLen);
if( !pDataPtr)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
do
{
f_memcpy( pDataPtr, pDataPiece->pData, pDataPiece->uiLength);
pDataPtr += pDataPiece->uiLength;
pDataPiece = pDataPiece->pNext;
}
while( pDataPiece);
}
}
}
if( *ppRecord)
{
flmAssert( 0);
(*ppRecord)->Release();
}
*ppRecord = pRecord;
pRecord = NULL;
Exit:
// Release all locked down blocks except the current block.
while( pLockedBlock)
{
pLockedBlock->pBlock->Release();
pLockedBlock = pLockedBlock->pNext;
}
m_tmpPool.poolReset( pvMark);
if( pRecord)
{
pRecord->Release();
}
return( rc);
}
/**************************************************************************
Desc:
**************************************************************************/
RCODE F_4xReader::getFldOverhead(
FSTATE * pState)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pFieldOvhd = &pState->pElement[ pState->uiPosInElm];
FLMBYTE * pElement = pState->pElement;
FLMBOOL bDoesntHaveFieldDef = TRUE;
FLMUINT uiFieldLen;
FLMUINT uiFieldType = 0;
FLMUINT uiTagNum;
FLMBYTE ucTemp;
if( FLM_4x_FOP_IS_STANDARD( pFieldOvhd))
{
if( FLM_4x_FSTA_LEVEL( pFieldOvhd))
{
pState->uiLevel++;
}
uiFieldLen = FLM_4x_FSTA_FLD_LEN( pFieldOvhd);
uiTagNum = FLM_4x_FSTA_FLD_NUM( pFieldOvhd);
pFieldOvhd += FLM_4x_FSTA_OVHD;
}
else if( FLM_4x_FOP_IS_OPEN( pFieldOvhd))
{
if( FLM_4x_FOPE_LEVEL( pFieldOvhd))
{
pState->uiLevel++;
}
ucTemp = (FLMBYTE)(FLM_4x_FOP_GET_FLD_FLAGS( pFieldOvhd++));
uiTagNum = (FLMUINT)*pFieldOvhd++;
if( FLM_4x_FOP_2BYTE_FLDNUM( ucTemp))
{
uiTagNum += ((FLMUINT) *pFieldOvhd++) << 8;
}
uiFieldLen = (FLMUINT) *pFieldOvhd++;
if( FLM_4x_FOP_2BYTE_FLDLEN( ucTemp))
{
uiFieldLen += ((FLMUINT) *pFieldOvhd++) << 8;
}
}
else if( FLM_4x_FOP_IS_NO_VALUE( pFieldOvhd))
{
if( FLM_4x_FNOV_LEVEL( pFieldOvhd))
{
pState->uiLevel++;
}
ucTemp = (FLMBYTE)(FLM_4x_FOP_GET_FLD_FLAGS( pFieldOvhd++));
uiTagNum = (FLMUINT)*pFieldOvhd++;
if( FLM_4x_FOP_2BYTE_FLDNUM( ucTemp))
{
uiTagNum += ((FLMUINT) *pFieldOvhd++) << 8;
}
uiFieldLen = uiFieldType = 0;
}
else if( FLM_4x_FOP_IS_SET_LEVEL( pFieldOvhd))
{
pState->uiLevel -= FLM_4x_FSLEV_GET( pFieldOvhd++);
pState->uiPosInElm = (FLMUINT)( pFieldOvhd - pElement);
rc = getFldOverhead( pState);
goto Exit;
}
else if( FLM_4x_FOP_IS_TAGGED( pFieldOvhd))
{
bDoesntHaveFieldDef = FALSE;
if( FLM_4x_FTAG_LEVEL( pFieldOvhd))
{
pState->uiLevel++;
}
ucTemp = (FLMBYTE)(FLM_4x_FOP_GET_FLD_FLAGS( pFieldOvhd));
uiFieldType = (FLMUINT)(FLM_4x_FTAG_FLD_TYPE( pFieldOvhd));
pFieldOvhd += FLM_4x_FTAG_OVHD;
uiTagNum = (FLMUINT) *pFieldOvhd++;
if( FLM_4x_FOP_2BYTE_FLDNUM( ucTemp))
{
uiTagNum += ((FLMUINT) *pFieldOvhd++) << 8;
}
uiTagNum ^= 0x8000;
uiFieldLen = (FLMUINT)*pFieldOvhd++;
if( FLM_4x_FOP_2BYTE_FLDLEN( ucTemp))
{
uiFieldLen += ((FLMUINT) *pFieldOvhd++) << 8;
}
}
else if( FLM_4x_FOP_IS_RECORD_INFO( pFieldOvhd))
{
bDoesntHaveFieldDef = FALSE;
ucTemp = *pFieldOvhd++;
uiFieldLen = *pFieldOvhd++;
if( FLM_4x_FOP_2BYTE_FLDLEN( ucTemp))
{
uiFieldLen += ((FLMUINT) *pFieldOvhd++) << 8;
}
uiTagNum = 0;
}
else
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
if( bDoesntHaveFieldDef)
{
if( RC_BAD( rc = getFieldType( uiTagNum, &uiFieldType)))
{
goto Exit;
}
}
pState->uiFieldType = uiFieldType;
pState->uiFieldLen = uiFieldLen;
pState->uiPosInElm = (FLMUINT)(pFieldOvhd - pElement);
pState->uiTagNum = uiTagNum;
Exit:
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
FLMUINT F_4xReader::childBlkAddr(
BTSK * pStack)
{
FLMBYTE * pucChildBlkPtr;
FLMUINT uiElmOvhd = pStack->uiElmOvhd;
if( uiElmOvhd == FLM_4x_BNE_DATA_OVHD)
{
pucChildBlkPtr = FLM_4x_BLK_ELM_ADDR(
pStack, pStack->uiCurElm + FLM_4x_BNE_DATA_CHILD_BLOCK);
return( FB2UD( pucChildBlkPtr));
}
else
{
// Corruption
flmAssert( 0);
return( 0);
}
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::btSearch(
F_4x_LFILE * pLFile,
FLMUINT uiDrn,
BTSK ** ppStack)
{
RCODE rc = NE_XFLM_OK;
BTSK * pStack = *ppStack;
FLMBYTE ucKey[ FLM_4x_DIN_KEY_SIZ];
FLMUINT uiBlkAddr;
// Get the root block
if( RC_BAD( rc = getRootBlock( pLFile, pStack)))
{
goto Exit;
}
longToByte( uiDrn, ucKey);
// Read each block going down the b-tree.
// Save state information in the stack.
for(;;)
{
if( pStack->uiBlkType != FLM_4x_BHT_NON_LEAF_DATA)
{
if( RC_BAD( rc = btScan( pStack, ucKey)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = btScanNonLeafData( pStack, uiDrn)))
{
goto Exit;
}
}
if( !pStack->uiLevel)
{
break;
}
uiBlkAddr = childBlkAddr( pStack);
pStack++;
if( RC_BAD( rc = getBlock( pLFile, uiBlkAddr, pStack)))
{
goto Exit;
}
}
*ppStack = pStack;
Exit:
return( rc);
}
/***************************************************************************
Desc: Scan a b-tree block for a matching key at any b-tree block level.
****************************************************************************/
RCODE F_4xReader::btScan(
BTSK * pStack,
FLMBYTE * pucSearchKey)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucCurElm;
FLMBYTE * pBlk;
FLMBYTE * pucKeyBuf;
FLMBYTE * pElmKey;
FLMUINT uiRecLen = 0;
FLMUINT uiPrevKeyCnt;
FLMUINT uiElmKeyLen;
FLMUINT uiBlkType;
FLMUINT uiElmOvhd;
FLMUINT uiBytesMatched;
uiBlkType = pStack->uiBlkType;
flmAssert( uiBlkType != FLM_4x_BHT_NON_LEAF_DATA);
pucKeyBuf = pStack->ucKeyBuf;
pBlk = pStack->pBlk->m_pucBlk;
uiElmOvhd = pStack->uiElmOvhd;
pStack->uiCurElm = FLM_4x_BH_OVHD;
pStack->uiKeyLen = 0;
pStack->uiPKC = 0;
pStack->uiPrevElmPKC = 0;
uiBytesMatched = 0;
for( ;;)
{
pucCurElm = &pBlk[ pStack->uiCurElm];
uiElmKeyLen = FLM_4x_BBE_GETR_KL( pucCurElm);
// Read in RAW mode - doesn't do all bit checking
if( (uiPrevKeyCnt = (FLM_4x_BBE_GETR_PKC( pucCurElm))) >
FLM_4x_BBE_PKC_MAX)
{
uiElmKeyLen += (uiPrevKeyCnt & FLM_4x_BBE_KL_HBITS) <<
FLM_4x_BBE_KL_SHIFT_BITS;
uiPrevKeyCnt &= FLM_4x_BBE_PKC_MAX;
}
// Should not have a non-zero PKC if we are on the first element
// of a block
if( uiPrevKeyCnt && pStack->uiCurElm == FLM_4x_BH_OVHD)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
// Get the record portion length when on the leaf blocks.
if( uiBlkType == FLM_4x_BHT_LEAF)
{
uiRecLen = FLM_4x_BBE_GET_RL( pucCurElm);
}
pStack->uiPrevElmPKC = pStack->uiPKC;
// The zero length key is the terminating
// element in a right-most block.
if( (pStack->uiKeyLen = uiPrevKeyCnt + uiElmKeyLen) == 0)
{
pStack->uiPrevElmPKC = f_min( uiBytesMatched, FLM_4x_BBE_PKC_MAX);
pStack->uiPKC = 0;
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
// Handle special case of left-end compression maxing out.
if( uiPrevKeyCnt == FLM_4x_BBE_PKC_MAX &&
FLM_4x_BBE_PKC_MAX < uiBytesMatched)
{
uiBytesMatched = FLM_4x_BBE_PKC_MAX;
}
// Check out this element to see if the key matches.
if( uiPrevKeyCnt == uiBytesMatched)
{
pElmKey = &pucCurElm[ uiElmOvhd];
for(;;)
{
// All bytes of the search key are matched?
if( uiBytesMatched == FLM_4x_DIN_KEY_SIZ)
{
pStack->uiPKC = f_min( uiBytesMatched, FLM_4x_BBE_PKC_MAX);
if( pStack->uiKeyLen != FLM_4x_DIN_KEY_SIZ)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
// Current key is equal to the search key.
f_memcpy( pucKeyBuf, pucSearchKey, FLM_4x_DIN_KEY_SIZ);
goto Exit;
}
if( uiBytesMatched == pStack->uiKeyLen)
{
pStack->uiPKC = f_min( uiBytesMatched, FLM_4x_BBE_PKC_MAX);
goto Next_Element;
}
// Compare the next byte in the search key and element
if( pucSearchKey[ uiBytesMatched] != *pElmKey)
{
break;
}
uiBytesMatched++;
pElmKey++;
}
pStack->uiPKC = f_min( uiBytesMatched, FLM_4x_BBE_PKC_MAX);
// Check if we are done comparing
if( pucSearchKey[ uiBytesMatched] < *pElmKey)
{
if( uiBytesMatched)
{
flmAssert( uiBytesMatched <= FLM_4x_DIN_KEY_SIZ);
f_memcpy( pucKeyBuf, pucSearchKey, uiBytesMatched);
}
flmAssert( pStack->uiKeyLen <= FLM_4x_DIN_KEY_SIZ);
f_memcpy( &pucKeyBuf[ uiBytesMatched], pElmKey,
pStack->uiKeyLen - uiBytesMatched);
goto Exit;
}
}
else if( uiPrevKeyCnt < uiBytesMatched)
{
// Current key > search key. Set pucKeyBuf and break out.
pStack->uiPKC = uiPrevKeyCnt;
if( uiPrevKeyCnt)
{
flmAssert( uiPrevKeyCnt <= FLM_4x_DIN_KEY_SIZ);
f_memcpy( pucKeyBuf, pucSearchKey, uiPrevKeyCnt);
}
flmAssert( uiPrevKeyCnt + uiElmKeyLen <= FLM_4x_DIN_KEY_SIZ);
f_memcpy( &pucKeyBuf[ uiPrevKeyCnt],
&pucCurElm[ uiElmOvhd], uiElmKeyLen);
if( byteToLong( pucKeyBuf) == FLM_4x_BT_END)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
}
goto Exit;
}
Next_Element:
// Position to the next element
pStack->uiCurElm += uiElmKeyLen + ((uiBlkType == FLM_4x_BHT_LEAF )
? (FLM_4x_BBE_KEY + uiRecLen)
: (FLM_4x_BNE_IS_DOMAIN( pucCurElm)
? (FLM_4x_BNE_DOMAIN_LEN + uiElmOvhd)
: uiElmOvhd));
// Most common check first.
if( pStack->uiCurElm < pStack->uiBlkEnd)
{
continue;
}
if( pStack->uiCurElm == pStack->uiBlkEnd)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
// Marched off the end of the block
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Binary search into a non-leaf data record block.
****************************************************************************/
RCODE F_4xReader::btScanNonLeafData(
BTSK * pStack,
FLMUINT uiDrn)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucBlk = pStack->pBlk->m_pucBlk;
FLMUINT uiLow = 0;
FLMUINT uiMid;
FLMUINT uiHigh = ((pStack->uiBlkEnd - FLM_4x_BH_OVHD) >> 3) - 1;
FLMUINT uiTblSize = uiHigh;
FLMUINT uiCurDrn;
for(;;)
{
uiMid = (uiLow + uiHigh) >> 1;
uiCurDrn = byteToLong( &pucBlk[ FLM_4x_BH_OVHD + (uiMid << 3)]);
if( !uiCurDrn)
{
// Special case - at the end of a rightmost block.
break;
}
if( uiDrn == uiCurDrn)
{
// Remember a data record can span multiple blocks (same DRN).
while( uiMid)
{
uiCurDrn = byteToLong(
&pucBlk[ FLM_4x_BH_OVHD + ((uiMid - 1) << 3)]);
if( uiDrn != uiCurDrn)
{
break;
}
uiMid--;
}
break;
}
// Down to one item if too high then position to next item.
if( uiLow >= uiHigh)
{
if( (uiDrn > uiCurDrn) && uiMid < uiTblSize)
{
uiMid++;
}
break;
}
// If too high then try lower section
if( uiDrn < uiCurDrn)
{
// First item too high?
if( !uiMid)
{
break;
}
uiHigh = uiMid - 1;
}
else
{
if( uiMid == uiTblSize)
{
uiMid++;
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
uiLow = uiMid + 1;
}
}
// Set curElm and the key buffer.
pStack->uiCurElm = FLM_4x_BH_OVHD + (uiMid << 3);
longToByte( uiCurDrn, pStack->ucKeyBuf);
Exit:
return( rc);
}
/****************************************************************************
Desc: Goto the next element within the block
****************************************************************************/
RCODE F_4xReader::blkNextElm(
BTSK * pStack)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucElm;
FLMUINT uiElmSize;
pucElm = &pStack->pBlk->m_pucBlk[ pStack->uiCurElm];
if( pStack->uiBlkType == FLM_4x_BHT_LEAF)
{
uiElmSize = FLM_4x_BBE_LEN( pucElm);
if( pStack->uiCurElm + FLM_4x_BBE_LEM_LEN < pStack->uiBlkEnd)
{
if( ((pStack->uiCurElm += uiElmSize) +
FLM_4x_BBE_LEM_LEN < pStack->uiBlkEnd) == 0)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
}
else
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
}
else
{
if( pStack->uiBlkType != FLM_4x_BHT_NON_LEAF_DATA)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
uiElmSize = FLM_4x_BNE_DATA_OVHD;
if( pStack->uiCurElm < pStack->uiBlkEnd)
{
// Check if this is not the last element within the block
if( (pStack->uiCurElm += uiElmSize) >= pStack->uiBlkEnd)
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
}
else
{
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Go to the next element in the logical b-tree
****************************************************************************/
RCODE F_4xReader::btNextElm(
BTSK * pStack,
F_4x_LFILE * pLFile)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucCurElm;
FLMUINT uiLFile;
uiLFile = FB2UW( &pStack->pBlk->m_pucBlk[ FLM_4x_BH_LOG_FILE_NUM]);
if( pStack->uiCurElm < FLM_4x_BH_OVHD)
{
pStack->uiCurElm = FLM_4x_BH_OVHD;
}
else
{
if( RC_BAD( rc = blkNextElm( pStack)))
{
if( rc == NE_XFLM_EOF_HIT)
{
FLMBYTE * pucBlk = FLM_4x_BLK_ELM_ADDR( pStack, FLM_4x_BH_NEXT_BLK);
FLMUINT uiBlkNum = FB2UD( pucBlk);
if( uiBlkNum != FLM_4x_BT_END)
{
// Current element was last element in the block - goto next block */
if( RC_BAD( rc = getBlock( pLFile, uiBlkNum, pStack)))
{
goto Exit;
}
pucBlk = pStack->pBlk->m_pucBlk;
pStack->uiBlkEnd = (FLMUINT)FB2UW( &pucBlk[ FLM_4x_BH_ELM_END ]);
pStack->uiCurElm = FLM_4x_BH_OVHD;
btAdjustStack( pStack, pLFile, TRUE);
}
}
}
}
pucCurElm = FLM_4x_CURRENT_ELM( pStack);
// Copy the key
f_memcpy( pStack->ucKeyBuf, pucCurElm, FLM_4x_DIN_KEY_SIZ);
Exit:
return(rc );
}
/***************************************************************************
Desc: Go to the previous element in the logical b-tree
****************************************************************************/
RCODE F_4xReader::btPrevElm(
BTSK * pStack,
F_4x_LFILE * pLFile)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiBlkAddr;
FLMUINT uiTargetElm;
FLMUINT uiPrevElm = 0;
FLMUINT uiPrevKeyCnt = 0;
FLMUINT uiElmKeyLen = 0;
FLMUINT uiElmOvhd = pStack->uiElmOvhd;
FLMBYTE * pucCurElm;
FLMBYTE * pucBlk;
// Check if we are at or before the first element in the block
if( pStack->uiCurElm <= FLM_4x_BH_OVHD)
{
pucBlk = pStack->pBlk->m_pucBlk;
// We're at or before the first element, so read in the previous
// block and go to the last element
if( (uiBlkAddr = (FLMUINT)FB2UD( &pucBlk[
FLM_4x_BH_PREV_BLK])) == FLM_4x_BT_END)
{
// We are at the end
rc = RC_SET( NE_XFLM_EOF_HIT);
goto Exit;
}
else
{
if( RC_BAD( rc = getBlock( pLFile, uiBlkAddr, pStack)))
{
// Set uiBlkEnd and uiCurElm.
// Adjust the parent block to the previous element
pucBlk = pStack->pBlk->m_pucBlk;
pStack->uiCurElm = pStack->uiBlkEnd;
btAdjustStack( pStack, pLFile, FALSE);
goto Exit;
}
}
}
// Move down 1 before the current element
if( pStack->uiBlkType == FLM_4x_BHT_NON_LEAF_DATA)
{
pStack->uiCurElm -= FLM_4x_BNE_DATA_OVHD;
pucBlk = pStack->pBlk->m_pucBlk;
pucCurElm = &pucBlk[ pStack->uiCurElm];
f_memcpy( pStack->ucKeyBuf, pucCurElm, FLM_4x_DIN_KEY_SIZ);
goto Exit;
}
// Set up to point to first element in the block
uiTargetElm = pStack->uiCurElm;
pStack->uiCurElm = FLM_4x_BH_OVHD;
pucBlk = pStack->pBlk->m_pucBlk;
while( pStack->uiCurElm < uiTargetElm)
{
pucCurElm = &pucBlk[ pStack->uiCurElm];
uiPrevKeyCnt = (FLMUINT)(FLM_4x_BBE_GET_PKC( pucCurElm));
uiElmKeyLen = (FLMUINT)(FLM_4x_BBE_GET_KL( pucCurElm));
if( uiElmKeyLen + uiPrevKeyCnt > FLM_4x_DIN_KEY_SIZ)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
if( uiElmKeyLen)
{
flmAssert( uiPrevKeyCnt + uiElmKeyLen <= FLM_4x_DIN_KEY_SIZ);
f_memcpy( &pStack->ucKeyBuf[ uiPrevKeyCnt],
&pucCurElm[ uiElmOvhd], uiElmKeyLen);
}
uiPrevElm = pStack->uiCurElm;
if( RC_BAD( rc = blkNextElm( pStack)))
{
if( rc != NE_XFLM_EOF_HIT)
{
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
}
pStack->uiKeyLen = uiPrevKeyCnt + uiElmKeyLen;
pStack->uiCurElm = uiPrevElm;
flmAssert( pStack->uiKeyLen == FLM_4x_DIN_KEY_SIZ);
Exit:
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::btAdjustStack(
BTSK * pStack,
F_4x_LFILE * pLFile,
FLMBOOL bMovedNext)
{
RCODE rc = NE_XFLM_OK;
pStack--;
if( RC_BAD( rc = getBlock( pLFile, pStack->uiBlkAddr, pStack)))
{
goto Exit;
}
if( bMovedNext)
{
if( RC_BAD( rc = btNextElm( pStack, pLFile)))
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = btPrevElm( pStack, pLFile)))
{
goto Exit;
}
}
Exit:
pStack++;
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::getNameTable(
F_4xNameTable ** ppNameTable)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bAllocated = FALSE;
if( !m_pNameTable)
{
if( (m_pNameTable = f_new F_4xNameTable) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
bAllocated = TRUE;
if( RC_BAD( rc = m_pNameTable->setupNameTable( this)))
{
goto Exit;
}
}
flmAssert( *ppNameTable == NULL);
m_pNameTable->AddRef();
*ppNameTable = m_pNameTable;
Exit:
if( RC_BAD( rc) && bAllocated)
{
m_pNameTable->Release();
m_pNameTable = NULL;
}
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
F_Record::F_Record()
{
m_uiContainerID = 0;
m_uiRecordID = 0;
m_pool.poolInit( sizeof( m_fieldList));
m_pFirstFld = m_pLastFld = NULL;
resetFieldList();
m_pDataBuf = NULL;
m_uiDataBufOffset = 0;
m_uiDataBufLength = 0;
}
/***************************************************************************
Desc:
****************************************************************************/
F_Record::~F_Record()
{
m_pool.poolFree();
if( m_pDataBuf)
{
f_free( &m_pDataBuf);
}
}
/***************************************************************************
Desc:
****************************************************************************/
void F_Record::resetFieldList( void)
{
FLMUINT uiLoop;
FIELD * pCurField;
FIELD * pPrevField = NULL;
for( uiLoop = 0; uiLoop < FLM_4x_FIELD_LIST_SIZE; uiLoop++)
{
pCurField = &m_fieldList[ uiLoop];
pCurField->ui16FieldID = 0xFFFF;
pCurField->pPrev = pPrevField;
pCurField->pNext = &m_fieldList[ uiLoop + 1];
pPrevField = pCurField;
}
pCurField->pNext = NULL;
m_pAvailFld = &m_fieldList[ 0];
}
/***************************************************************************
Desc:
****************************************************************************/
void F_Record::clear()
{
m_uiDataBufOffset = 0;
resetFieldList();
m_pool.poolReset( NULL);
m_pFirstFld = NULL;
m_pLastFld = NULL;
m_uiContainerID = 0;
m_uiRecordID = 0;
}
/***************************************************************************
Desc:
****************************************************************************/
FIELD * F_Record::lastSubTreeField(
FIELD * pField)
{
FIELD * pTempField = (FIELD *)lastChild( pField);
FIELD * pLastChild = NULL;
FLMUINT uiStartLevel = pField->ui8Level;
// Step down through the tree
for( ; pTempField && pTempField->ui8Level > uiStartLevel;
pTempField = nextField( pTempField))
{
pLastChild = pTempField;
}
return( pLastChild);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::insertLast(
FLMUINT uiLevel,
FLMUINT uiFieldID,
FLMUINT uiDataType,
void ** ppvField)
{
RCODE rc = NE_XFLM_OK;
FIELD * pField = NULL;
// Insert new field following current last field
if( RC_BAD( rc = createField( m_pLastFld, &pField)))
{
goto Exit;
}
// Set up the new field and set as the current field
pField->ui16FieldID = (FLMUINT16) uiFieldID;
pField->ui8Level = (FLMUINT8) uiLevel;
pField->ui8Type = (FLMUINT8) uiDataType;
if( ppvField)
{
*ppvField = pField;
}
Exit:
#ifdef FLM_DEBUG
if ( pField)
{
flmAssert( pField->pNext != pField);
flmAssert( pField->pPrev != pField);
flmAssert( pField->ui16FieldID != 0xFFFF);
}
#endif
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
FIELD * F_Record::nextSiblingField(
FIELD * pField)
{
FLMUINT8 ui8Level = pField->ui8Level;
while( (pField = nextField( pField)) != NULL &&
pField->ui8Level > ui8Level)
{
;
}
return( (pField && pField->ui8Level == ui8Level)
? pField
: NULL);
}
/***************************************************************************
Desc:
****************************************************************************/
void * F_Record::prevSibling(
void * pvField)
{
if( !pvField)
{
return( NULL);
}
FIELD * pField = (FIELD *)pvField;
FLMUINT8 ui8Level = pField->ui8Level;
while( (pField = prevField( pField)) != NULL &&
pField->ui8Level > ui8Level)
{
;
}
return( (pField && pField->ui8Level == ui8Level)
? pField
: NULL);
}
/***************************************************************************
Desc:
****************************************************************************/
void * F_Record::lastChild(
void * pvField)
{
FIELD * pField = (FIELD *)pvField;
FIELD * pLastField = NULL;
if( !pField)
{
return( NULL);
}
for( pField = firstChildField( pField);
pField;
pField = nextSiblingField( pField))
{
pLastField = pField;
}
return( pLastField);
}
/***************************************************************************
Desc:
****************************************************************************/
void * F_Record::parent(
void * pvField)
{
FIELD * pField = (FIELD *) pvField;
FLMUINT8 ui8Level;
if( !pField)
{
return( NULL);
}
ui8Level = pField->ui8Level;
while( (pField = prevField( pField)) != NULL &&
pField->ui8Level >= ui8Level)
{
;
}
return( pField);
}
/***************************************************************************
Desc:
****************************************************************************/
FLMBYTE * F_Record::getImportDataPtr(
void * pvField,
FLMUINT uiDataType,
FLMUINT uiLength)
{
FLMBYTE * pucData = NULL;
getNewDataPtr( (FIELD *)pvField, uiDataType, uiLength, &pucData);
((FIELD *)pvField)->ui8Type = (FLMUINT8) uiDataType;
return( pucData);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::preallocSpace(
FLMUINT uiDataSize)
{
RCODE rc = NE_XFLM_OK;
m_uiDataBufOffset = 0;
if( m_uiDataBufLength >= uiDataSize)
{
goto Exit;
}
if( !m_pDataBuf)
{
m_uiDataBufLength = 0;
if( RC_BAD( rc = f_alloc( uiDataSize, &m_pDataBuf)))
{
goto Exit;
}
m_uiDataBufLength = uiDataSize;
}
else
{
if( RC_BAD( rc = f_realloc( uiDataSize, &m_pDataBuf)))
{
goto Exit;
}
m_uiDataBufLength = uiDataSize;
}
Exit:
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
void * F_Record::find(
void * pvField,
FLMUINT uiFieldID,
FLMUINT uiOccur,
FLMBOOL bSearchForest)
{
if( uiOccur == 0)
{
uiOccur = 1;
}
if( pvField)
{
FLMUINT uiStartLevel = ((FIELD *)pvField)->ui8Level;
do
{
if( (uiFieldID ==
((FIELD *)pvField)->ui16FieldID) && (--uiOccur < 1))
{
return( pvField);
}
}
while( (pvField = (FIELD *)(pvField
? ((FIELD *)pvField)->pNext
: NULL)) != NULL &&
((((FIELD *)pvField)->ui8Level > uiStartLevel) ||
(bSearchForest && ((FIELD *)pvField)->ui8Level ==
uiStartLevel)));
}
return( NULL);
}
/***************************************************************************
Desc:
****************************************************************************/
void * F_Record::find(
void * pvField,
FLMUINT * puiPathArray,
FLMUINT uiOccur,
FLMBOOL bSearchForest)
{
void * pvSaveField;
FLMUINT * puiPath;
FLMUINT uiLevel;
// Handle empty record
if( !pvField)
{
return( NULL);
}
if( !uiOccur)
{
uiOccur = 1;
}
uiLevel = ((FIELD *)pvField)->ui8Level;
for(;;)
{
puiPath = puiPathArray + ( ((FIELD *)pvField)->ui8Level - uiLevel);
pvSaveField = pvField;
if( *puiPath == ((FIELD *)pvField)->ui16FieldID)
{
if( *(puiPath + 1) == 0 && (--uiOccur < 1))
{
return( pvField);
}
// Go down level for rest of path
if( ( pvField = firstChild( pvField)) != NULL)
{
continue;
}
pvField = pvSaveField;
}
// Find next sibling/uncle/end
do
{
pvField = (FIELD *)(pvField ? ((FIELD *)pvField)->pNext : NULL);
}
while( pvField != NULL
&& ((FIELD *)pvField)->ui8Level > ((FIELD *)pvSaveField)->ui8Level);
// Are we at the end?
if( !pvField ||
((FIELD *)pvField)->ui8Level < uiLevel ||
(bSearchForest && ((FIELD *)pvField)->ui8Level == uiLevel))
{
break;
}
}
return( NULL);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::createField(
FIELD * pCurField,
FIELD ** ppNewField)
{
RCODE rc = NE_XFLM_OK;
FIELD * pNewField;
if( m_pAvailFld)
{
pNewField = m_pAvailFld;
m_pAvailFld = m_pAvailFld->pNext;
if( m_pAvailFld)
m_pAvailFld->pPrev = NULL;
pNewField->pPrev = NULL;
pNewField->pNext = NULL;
}
else
{
if( RC_BAD( rc = m_pool.poolAlloc( sizeof( FIELD), (void **)&pNewField)))
{
goto Exit;
}
}
if( !pCurField && m_pLastFld)
{
pCurField = m_pLastFld;
}
if( pCurField)
{
pNewField->pNext = pCurField->pNext;
pNewField->pPrev = pCurField;
if( pCurField->pNext)
{
pCurField->pNext->pPrev = pNewField;
}
pCurField->pNext = pNewField;
}
if( !m_pFirstFld)
{
m_pFirstFld = pNewField;
}
if( !m_pLastFld || pCurField == m_pLastFld)
{
m_pLastFld = pNewField;
}
pNewField->uiDataLength = 0;
pNewField->uiDataOffset = 0;
*ppNewField = pNewField;
Exit:
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::getNewDataPtr(
FIELD * pField,
FLMUINT uiDataType,
FLMUINT uiNewLength,
FLMBYTE ** ppDataPtr)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pDataPtr;
FLMUINT uiTemp;
if( pField->uiDataLength)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
goto Exit;
}
if( uiNewLength <= sizeof( FLMUINT))
{
pDataPtr = (FLMBYTE *) &(pField->uiDataOffset);
}
else
{
// If this is a binary field it must start on an aligned byte.
if( uiDataType == FLM_4x_BINARY_TYPE &&
(m_uiDataBufOffset & FLM_ALLOC_ALIGN) != 0)
{
uiTemp = (FLM_ALLOC_ALIGN + 1) - (m_uiDataBufOffset & FLM_ALLOC_ALIGN);
m_uiDataBufOffset += uiTemp;
}
if( uiNewLength + m_uiDataBufOffset > m_uiDataBufLength)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_FAILURE);
goto Exit;
}
pDataPtr = m_pDataBuf + m_uiDataBufOffset;
pField->uiDataOffset = m_uiDataBufOffset;
m_uiDataBufOffset += uiNewLength;
}
pField->uiDataLength = uiNewLength;
*ppDataPtr = pDataPtr;
Exit:
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::getINT(
void * pvField,
FLMINT * piNumber)
{
return( pvField
? storage2INT( getDataType( pvField), getDataLength( pvField),
getDataPtr( (FIELD *)pvField), piNumber)
: RC_SET( NE_XFLM_NOT_FOUND));
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::getUINT(
void * pvField,
FLMUINT * puiNumber)
{
return( pvField
? storage2UINT( getDataType( pvField), getDataLength( pvField),
getDataPtr( (FIELD *)pvField), puiNumber)
: RC_SET( NE_XFLM_NOT_FOUND));
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::getUINT32(
void * pvField,
FLMUINT32 * pui32Number)
{
return( pvField
? storage2UINT32( getDataType( pvField), getDataLength( pvField),
getDataPtr( (FIELD *)pvField), pui32Number)
: RC_SET( NE_XFLM_NOT_FOUND));
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::getUnicode(
void * pvField,
FLMUNICODE * pUnicode,
FLMUINT * puiBufLen)
{
return( pvField
? getUnicode( getDataType( pvField), getDataLength( pvField),
getDataPtr( (FIELD *) pvField), puiBufLen, pUnicode)
: RC_SET( NE_XFLM_NOT_FOUND));
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::getNative(
void * pvField,
char * pszString,
FLMUINT * puiBufLen)
{
return( pvField
? storage2Native( getDataType( pvField), getDataLength( pvField),
getDataPtr( (FIELD *) pvField), puiBufLen, pszString)
: RC_SET( NE_XFLM_NOT_FOUND));
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::getBinary(
void * pvField,
void * pvBuf,
FLMUINT * puiBufLen)
{
if( pvField)
{
*puiBufLen = f_min( *puiBufLen, getDataLength( pvField));
f_memcpy( pvBuf, getDataPtr( (FIELD *)pvField), *puiBufLen);
return( NE_XFLM_OK);
}
return( RC_SET( NE_XFLM_NOT_FOUND));
}
/***************************************************************************
Desc:
****************************************************************************/
FLMBYTE * F_Record::getDataPtr(
FIELD * pField)
{
if( !pField->uiDataLength)
{
return( NULL);
}
else if( pField->uiDataLength <= sizeof( FLMUINT))
{
return (FLMBYTE *) &(pField->uiDataOffset);
}
return( m_pDataBuf + pField->uiDataOffset);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::storage2INT(
FLMUINT uiType,
FLMUINT uiBufLength,
FLMBYTE * pBuf,
FLMINT * piNum)
{
RCODE rc = NE_XFLM_OK;
BCD_TYPE bcd = {0};
if( RC_BAD( rc = bcd2Num( uiType, uiBufLength, pBuf, &bcd)))
{
goto Exit;
}
if( bcd.bNegFlag)
{
*piNum = -((FLMINT)bcd.uiNum);
if( !((bcd.uiNibCnt < 11) ||
(bcd.uiNibCnt == 11 &&
(!bcd.pucPtr || (f_memcmp( bcd.pucPtr,
gv_ucMinBcdINT32, 6) <= 0)))))
{
rc = RC_SET( NE_XFLM_CONV_NUM_UNDERFLOW);
goto Exit;
}
}
else
{
*piNum = (FLMINT)bcd.uiNum;
if( !((bcd.uiNibCnt < 10) ||
(bcd.uiNibCnt == 10 &&
(!bcd.pucPtr || (f_memcmp( bcd.pucPtr,
gv_ucMaxBcdINT32, 5) <= 0)))))
{
rc = RC_SET( NE_XFLM_CONV_NUM_OVERFLOW);
goto Exit;
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::storage2UINT(
FLMUINT uiType,
FLMUINT uiBufLength,
FLMBYTE * pBuf,
FLMUINT * puiNum)
{
RCODE rc = NE_XFLM_OK;
BCD_TYPE bcd = {0};
if( RC_BAD( rc = bcd2Num( uiType, uiBufLength, pBuf, &bcd)))
{
goto Exit;
}
*puiNum = bcd.uiNum;
if( bcd.bNegFlag)
{
rc = RC_SET( NE_XFLM_CONV_NUM_UNDERFLOW);
goto Exit;
}
else if( bcd.uiNibCnt == 10)
{
if( !(!bcd.pucPtr ||
(f_memcmp( bcd.pucPtr, gv_ucMaxBcdUINT32, 5) <= 0)))
{
rc = RC_SET( NE_XFLM_CONV_NUM_OVERFLOW);
goto Exit;
}
}
else if( bcd.uiNibCnt > 10)
{
rc = RC_SET( NE_XFLM_CONV_NUM_OVERFLOW);
goto Exit;
}
Exit:
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::storage2UINT32(
FLMUINT uiType,
FLMUINT uiBufLength,
FLMBYTE * pBuf,
FLMUINT32 * pui32Num)
{
RCODE rc = NE_XFLM_OK;
BCD_TYPE bcd = {0};
if( RC_BAD( rc = bcd2Num( uiType, uiBufLength, pBuf, &bcd)))
{
goto Exit;
}
*pui32Num = (FLMUINT32)bcd.uiNum;
if( bcd.bNegFlag)
{
rc = RC_SET( NE_XFLM_CONV_NUM_UNDERFLOW);
goto Exit;
}
else if( bcd.uiNibCnt == 10)
{
if( !(!bcd.pucPtr ||
(f_memcmp( bcd.pucPtr, gv_ucMaxBcdUINT32, 5) <= 0)))
{
rc = RC_SET( NE_XFLM_CONV_NUM_OVERFLOW);
goto Exit;
}
}
else if( bcd.uiNibCnt > 10)
{
rc = RC_SET( NE_XFLM_CONV_NUM_OVERFLOW);
goto Exit;
}
Exit:
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::bcd2Num(
FLMUINT uiType,
FLMUINT uiBufLength,
FLMBYTE * pBuf,
BCD_TYPE * bcd)
{
RCODE rc = NE_XFLM_OK;
if( !pBuf)
{
rc = RC_SET( NE_XFLM_CONV_NULL_SRC);
goto Exit;
}
switch( uiType)
{
case FLM_4x_NUMBER_TYPE:
{
FLMUINT uiTotalNum = 0;
FLMUINT uiByte;
FLMUINT uiNibCnt;
bcd->pucPtr = pBuf;
// Get each nibble and use to create the number
#define FLM_MAX_NIB_CNT 11
for( bcd->bNegFlag =
(FLMBOOL)(uiNibCnt = ((*pBuf & 0xF0) == 0xB0) ? 1 : 0);
uiNibCnt <= FLM_MAX_NIB_CNT;
uiNibCnt++ )
{
uiByte = (uiNibCnt & 0x01)
? (FLMUINT)(0x0F & *pBuf++)
: (FLMUINT)(*pBuf >> 4);
if( uiByte == 0x0F)
{
break;
}
// Multiply by 10 and add n
// NOTE: 10y = 8y + 2y = (y << 3) + (y << 1)
// faster than using the long multiply (10 * y)
uiTotalNum = (uiTotalNum << 3) + (uiTotalNum << 1) + uiByte;
}
bcd->uiNibCnt = uiNibCnt;
bcd->uiNum = uiTotalNum;
break;
}
case FLM_4x_TEXT_TYPE:
{
FLMUINT uiNumber = 0;
// If it is a TEXT Value, convert to a numeric value
// WARNING: The text is not null terminated
while( uiBufLength--)
{
if( *pBuf < ASCII_ZERO || *pBuf > ASCII_NINE)
{
break;
}
uiNumber = (uiNumber * 10) + (*pBuf - ASCII_ZERO);
pBuf++;
}
bcd->uiNum = uiNumber;
bcd->uiNibCnt = 0;
bcd->bNegFlag = FALSE;
break;
}
case FLM_4x_CONTEXT_TYPE :
{
if( uiBufLength == sizeof( FLMUINT32))
{
bcd->uiNum = (FLMUINT)( FB2UD( pBuf));
bcd->bNegFlag = 0;
// Now set the uiNibCnt, the uiNibCnt will not be totally
// accurate, but it's close enough to get the value out...
if( bcd->uiNum < FLM_MAX_UINT8)
{
bcd->uiNibCnt = 3;
}
else if( bcd->uiNum < FLM_MAX_UINT16)
{
bcd->uiNibCnt = 5;
}
else
{
bcd->uiNibCnt = 9;
}
}
break;
}
default :
{
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_ILLEGAL);
goto Exit;
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc:
****************************************************************************/
RCODE F_Record::getUnicode(
FLMUINT uiType,
FLMUINT uiBufLength,
FLMBYTE * pBuffer,
FLMUINT * puiStrBufLen,
FLMUNICODE * puzStrBuf)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE ucChar;
FLMUINT uiBytesProcessed = 0;
FLMUINT uiBytesOutput = 0;
FLMBOOL bOutputData = FALSE;
FLMUINT uiMaxOutLen;
FLMBYTE ucObjType;
FLMUINT uiObjLength = 0;
FLMBYTE tempBuf[ 80];
FLMBYTE chrSet, chrVal;
FLMUNICODE newChrVal;
// If the value is a number, convert to text first
if( uiType != FLM_4x_TEXT_TYPE)
{
if( !pBuffer)
{
uiBufLength = 0;
}
else
{
if( uiType == FLM_4x_NUMBER_TYPE)
{
uiBufLength = sizeof( tempBuf);
if( RC_BAD( rc = numToText( pBuffer, tempBuf, &uiBufLength)))
{
goto Exit;
}
}
else if( uiType == FLM_4x_TEXT_TYPE)
{
uiBufLength = sizeof( tempBuf);
if( RC_BAD( rc = contextToText( pBuffer, tempBuf, &uiBufLength)))
{
goto Exit;
}
}
else
{
rc = RC_SET( NE_XFLM_CONV_ILLEGAL);
goto Exit;
}
pBuffer = &tempBuf[ 0];
}
}
uiMaxOutLen = *puiStrBufLen;
if( puzStrBuf != NULL && uiMaxOutLen > 1)
{
bOutputData = TRUE;
uiMaxOutLen -= 2;
}
// Parse through the string outputting data to the buffer as we go
while( uiBytesProcessed < uiBufLength)
{
// Determine what we are pointing at
ucChar = *pBuffer;
ucObjType = (FLMBYTE)textObjType( ucChar);
switch( ucObjType)
{
case FLM_4x_ASCII_CHAR_CODE:
{
uiObjLength = 1;
if( bOutputData)
{
if( (uiMaxOutLen < 2) || (uiBytesOutput > uiMaxOutLen - 2))
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto GetUNICODE_Output;
}
*puzStrBuf++ = ucChar;
}
uiBytesOutput += 2;
break;
}
case FLM_4x_CHAR_SET_CODE:
{
uiObjLength = 2;
if( bOutputData)
{
if( (uiMaxOutLen < 2) || (uiBytesOutput > uiMaxOutLen - 2))
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto GetUNICODE_Output;
}
// Convert WP to UNICODE
chrSet = ucChar & 0x3F;
chrVal = *(pBuffer + 1);
if( RC_BAD( rc = flmWPToUnicode(
(((FLMUINT16)chrSet) << 8) | chrVal, &newChrVal)))
{
RC_UNEXPECTED_ASSERT( rc);
goto Exit;
}
if( bOutputData)
{
if( (uiMaxOutLen < 2) || (uiBytesOutput > uiMaxOutLen - 2))
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto GetUNICODE_Output;
}
*puzStrBuf++ = newChrVal;
}
}
uiBytesOutput += 2;
break;
}
case FLM_4x_WHITE_SPACE_CODE:
{
uiObjLength = 1;
if( bOutputData)
{
if( (uiMaxOutLen < 2) || (uiBytesOutput > uiMaxOutLen - 2))
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto GetUNICODE_Output;
}
if( ucChar == (FLM_4x_WHITE_SPACE_CODE | 0x0C))
{
*puzStrBuf = 9;
}
else if( ucChar == (FLM_4x_WHITE_SPACE_CODE | 0x0D))
{
*puzStrBuf = 10;
}
else if( ucChar == (FLM_4x_WHITE_SPACE_CODE | 0x07))
{
*puzStrBuf = 13;
}
else
{
*puzStrBuf = 0x20;
}
puzStrBuf++;
}
uiBytesOutput += 2;
break;
}
case FLM_4x_EXT_CHAR_CODE:
{
uiObjLength = 3;
if( bOutputData)
{
if( (uiMaxOutLen < 2) || (uiBytesOutput > uiMaxOutLen - 2))
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto GetUNICODE_Output;
}
// Convert back from WP to UNICODE
chrSet = *(pBuffer + 1);
chrVal = *(pBuffer + 2);
if( RC_BAD( rc = flmWPToUnicode(
(((FLMUINT16)chrSet) << 8) | chrVal, &newChrVal)))
{
RC_UNEXPECTED_ASSERT( rc);
goto Exit;
}
if( bOutputData)
{
if( (uiMaxOutLen < 2) || (uiBytesOutput > uiMaxOutLen - 2))
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto GetUNICODE_Output;
}
*puzStrBuf++ = newChrVal;
}
}
uiBytesOutput += 2;
break;
}
case FLM_4x_OEM_CODE:
{
uiObjLength = 2;
break;
}
case FLM_4x_UNICODE_CODE:
{
uiObjLength = 3;
if( bOutputData)
{
if( (uiMaxOutLen < 2) || (uiBytesOutput > uiMaxOutLen - 2))
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto GetUNICODE_Output;
}
*puzStrBuf++ = (*(pBuffer + 1) << 8) + *(pBuffer + 2);
}
uiBytesOutput += 2;
break;
}
case FLM_4x_UNK_EQ_1_CODE:
{
uiObjLength = 2;
if( bOutputData)
{
if( (uiMaxOutLen < 2) || (uiBytesOutput > uiMaxOutLen - 2))
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto GetUNICODE_Output;
}
*puzStrBuf++ = *(pBuffer+1);
}
uiBytesOutput += 2;
break;
}
default:
{
flmAssert( 0);
uiBytesProcessed = uiBufLength;
break;
}
}
pBuffer += uiObjLength;
uiBytesProcessed += uiObjLength;
}
GetUNICODE_Output:
if( bOutputData)
{
*puzStrBuf = 0;
}
*puiStrBufLen = uiBytesOutput;
Exit:
return( rc);
}
/***************************************************************************
Desc: Convert a storage text string into a native string
***************************************************************************/
RCODE F_Record::storage2Native(
FLMUINT uiType,
FLMUINT uiBufLength,
FLMBYTE * pBuffer,
FLMUINT * puiOutBufLenRV,
char * pOutBuffer)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * ptr = pBuffer;
FLMBYTE * pucOut;
FLMBYTE ucChar;
FLMUINT uiBytesProcessed;
FLMUINT uiBytesOutput;
FLMUINT uiValLength = uiBufLength;
FLMBOOL bOutputData = FALSE;
FLMUINT uiMaxOutLen = 0;
FLMBYTE ucObjType;
FLMUINT uiObjLength = 0;
FLMBYTE TempBuf[ 80];
// If needed, try and convert the data to text
if( uiType != FLM_4x_TEXT_TYPE)
{
if( !ptr)
{
uiValLength = 0;
}
else if( uiType == FLM_4x_NUMBER_TYPE)
{
uiValLength = sizeof( TempBuf);
if( RC_BAD( rc = numToText( ptr, TempBuf, &uiValLength)))
{
goto Exit;
}
ptr = &TempBuf[ 0];
}
else if( uiType == FLM_4x_CONTEXT_TYPE)
{
uiValLength = sizeof( TempBuf);
if( RC_BAD( rc = contextToText( ptr, TempBuf, &uiValLength)))
{
goto Exit;
}
ptr = &TempBuf[ 0];
}
else
{
rc = RC_SET( NE_XFLM_CONV_ILLEGAL);
goto Exit;
}
}
if( pOutBuffer != NULL && *puiOutBufLenRV)
{
bOutputData = TRUE;
uiMaxOutLen = *puiOutBufLenRV - 1;
}
uiBytesProcessed = 0;
uiBytesOutput = 0;
pucOut = (FLMBYTE *)pOutBuffer;
// Parse through the string outputting data to the buffer
// as we go
while( uiBytesProcessed < uiValLength)
{
// Determine what we are pointing at
ucChar = *ptr;
ucObjType = (FLMBYTE)textObjType( ucChar);
switch( ucObjType)
{
case FLM_4x_ASCII_CHAR_CODE:
{
uiObjLength = 1;
if( bOutputData)
{
if( uiBytesOutput < uiMaxOutLen)
*pucOut++ = f_tonative( ucChar);
else
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Native_Output;
}
}
uiBytesOutput++;
break;
}
case FLM_4x_CHAR_SET_CODE:
{
uiObjLength = 2;
if( bOutputData)
{
if( uiBytesOutput < uiMaxOutLen)
{
if( (ucChar & (~ucObjType)) == 0)
{
*pucOut++ = f_tonative( *(ptr + 1));
}
else
{
*pucOut++ = 0xFF;
}
}
else
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Native_Output;
}
}
uiBytesOutput++;
break;
}
case FLM_4x_WHITE_SPACE_CODE:
{
uiObjLength = 1;
if( bOutputData)
{
if( uiBytesOutput < uiMaxOutLen)
{
ucChar &= (~FLM_4x_WHITE_SPACE_MASK);
if( (ucChar == 0x03) ||
(ucChar == 0x04) ||
(ucChar == 0x05))
{
ucChar = ASCII_DASH;
}
else if( ucChar == 0x0C)
{
ucChar = ASCII_TAB;
}
else if( ucChar == 0x0D)
{
ucChar = 0x0A;
}
else if( ucChar == 0x07)
{
ucChar = 0x0D;
}
else
{
ucChar = 0x20;
}
*pucOut++ = f_tonative( ucChar);
}
else
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Native_Output;
}
}
uiBytesOutput++;
break;
}
case FLM_4x_UNK_EQ_1_CODE:
{
uiObjLength = 2;
// Skip it if it is not a NATIVE code
if( (ucChar & (~ucObjType)) == 0x02)
{
if( bOutputData)
{
if( uiBytesOutput < uiMaxOutLen)
{
*pucOut++ = f_tonative( *(ptr + 1));
}
else
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Native_Output;
}
}
uiBytesOutput++;
}
break;
}
case FLM_4x_EXT_CHAR_CODE:
{
uiObjLength = 3;
if( bOutputData)
{
if( uiBytesOutput < uiMaxOutLen)
{
*pucOut += 0xFF;
}
else
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Native_Output;
}
}
uiBytesOutput++;
break;
}
case FLM_4x_OEM_CODE:
{
uiObjLength = 2;
if( bOutputData)
{
if( uiBytesOutput < uiMaxOutLen)
{
*pucOut++ = f_tonative( *(ptr + 1));
}
else
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Native_Output;
}
}
uiBytesOutput++;
break;
}
case FLM_4x_UNICODE_CODE:
{
uiObjLength = 3;
if( bOutputData)
{
if( uiBytesOutput < uiMaxOutLen )
{
*pucOut++ = 0xFF;
}
else
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Native_Output;
}
}
uiBytesOutput++;
break;
}
default:
{
flmAssert( 0);
break;
}
}
ptr += uiObjLength;
uiBytesProcessed += uiObjLength;
}
// Add a terminating NULL character, but DO NOT increment the
// uiBytesOutput counter
Native_Output:
if( bOutputData)
{
*pucOut = 0;
}
*puiOutBufLenRV = uiBytesOutput;
Exit:
return( rc);
}
/***************************************************************************
Desc: Convert a storage number into a storage text string
***************************************************************************/
RCODE F_Record::numToText(
FLMBYTE * pucNum,
FLMBYTE * pucOutBuffer,
FLMUINT * puiBufLen)
{
RCODE rc = NE_XFLM_OK;
FLMBYTE * pucOutput;
FLMBYTE ucChar;
FLMBYTE ucOutChar;
FLMUINT uiBytesOutput;
FLMBOOL bOutputData;
FLMUINT uiMaxOutLen;
FLMBOOL bFirstNibble;
uiMaxOutLen = *puiBufLen;
bOutputData = ((pucOutBuffer != NULL) && uiMaxOutLen) ? TRUE : FALSE;
uiBytesOutput = 0;
pucOutput = pucOutBuffer;
// Parse through the string outputting data to the buffer
// as we go
if( !pucNum)
{
goto Exit;
}
bFirstNibble = TRUE;
for( ;;)
{
if( bFirstNibble)
{
ucChar = (FLMBYTE)(*pucNum >> 4);
}
else
{
ucChar = (FLMBYTE)(*pucNum++ & 0x0F);
}
bFirstNibble = !bFirstNibble;
if( ucChar <= 9)
{
ucOutChar = (FLMBYTE)( ASCII_ZERO + ucChar);
}
else if( ucChar == 0x0F)
{
break;
}
else
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
if( bOutputData)
{
if( uiBytesOutput < uiMaxOutLen)
{
*pucOutput++ = ucOutChar;
}
else
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
}
uiBytesOutput++;
}
Exit:
*puiBufLen = uiBytesOutput;
return( rc);
}
/***************************************************************************
Desc: Convert a context value into a storage text string
***************************************************************************/
RCODE F_Record::contextToText(
FLMBYTE * pucValue,
FLMBYTE * pucOutBuffer,
FLMUINT * puiBufLen)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiMaxOutLen;
FLMUINT uiStrLen;
FLMUINT uiBytesOutput = 0;
FLMBOOL bOutputData;
FLMBYTE ucTmpBuf[ 32];
uiMaxOutLen = *puiBufLen;
bOutputData = ((pucOutBuffer != NULL) && uiMaxOutLen) ? TRUE : FALSE;
if( !pucValue)
{
goto Exit;
}
f_sprintf( (char *)ucTmpBuf, "%u", FB2UD( pucValue));
uiStrLen = f_strlen( ucTmpBuf) + 1;
uiBytesOutput = f_min( uiStrLen, uiMaxOutLen);
if( bOutputData)
{
f_memcpy( pucOutBuffer, ucTmpBuf, uiBytesOutput);
pucOutBuffer[ uiBytesOutput - 1] = 0;
}
if( uiMaxOutLen < uiBytesOutput)
{
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
goto Exit;
}
Exit:
*puiBufLen = uiBytesOutput;
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::getRootBlock(
F_4x_LFILE * pLFile,
BTSK * pStack)
{
RCODE rc = NE_XFLM_OK;
F_Block * pBlock = NULL;
if( RC_BAD( rc = readBlock( pLFile->uiRootBlk, &pBlock)))
{
goto Exit;
}
if( !(FLM_4x_BH_IS_ROOT_BLK( pBlock->m_pucBlk)) ||
(pLFile->uiLfNum != FB2UW( &pBlock->m_pucBlk[
FLM_4x_BH_LOG_FILE_NUM])))
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
// Set up the stack
blkToStack( &pBlock, pStack);
Exit:
if( pBlock)
{
pBlock->Release();
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::getBlock(
F_4x_LFILE * pLFile,
FLMUINT uiBlkAddr,
BTSK * pStack)
{
RCODE rc = NE_XFLM_OK;
F_Block * pBlock = NULL;
if( RC_BAD( rc = readBlock( uiBlkAddr, &pBlock)))
{
goto Exit;
}
if( pLFile->uiLfNum != FB2UW( &pBlock->m_pucBlk[
FLM_4x_BH_LOG_FILE_NUM]))
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
goto Exit;
}
// Set up the stack
blkToStack( &pBlock, pStack);
Exit:
if( pBlock)
{
pBlock->Release();
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
void F_4xReader::blkToStack(
F_Block ** ppBlock,
BTSK * pStack)
{
FLMBYTE * pucBlk = (*ppBlock)->m_pucBlk;
FLMUINT uiBlkType;
uiBlkType = (FLMUINT)(FLM_4x_BH_GET_TYPE( pucBlk));
pStack->uiBlkType = uiBlkType;
if( uiBlkType == FLM_4x_BHT_LEAF)
{
pStack->uiElmOvhd = FLM_4x_BBE_KEY;
}
else if( uiBlkType == FLM_4x_BHT_NON_LEAF_DATA)
{
pStack->uiElmOvhd = FLM_4x_BNE_DATA_OVHD;
}
else if( uiBlkType == FLM_4x_BHT_NON_LEAF)
{
pStack->uiElmOvhd = FLM_4x_BNE_KEY_START;
}
else if( uiBlkType == FLM_4x_BHT_NON_LEAF_COUNTS)
{
pStack->uiElmOvhd = FLM_4x_BNE_KEY_COUNTS_START;
}
else
{
flmAssert( 0);
pStack->uiElmOvhd = FLM_4x_BNE_KEY_START;
}
pStack->uiKeyLen = 0;
pStack->uiPKC = 0;
pStack->uiPrevElmPKC = 0;
pStack->uiCurElm = FLM_4x_BH_OVHD;
pStack->uiBlkEnd = (FLMUINT)FB2UW( &pucBlk[ FLM_4x_BH_ELM_END]);
pStack->uiLevel = (FLMUINT)pucBlk[ FLM_4x_BH_LEVEL ];
if( pStack->pBlk)
{
pStack->pBlk->Release();
}
pStack->pBlk = *ppBlock;
*ppBlock = NULL;
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::getFieldType(
FLMUINT uiFieldNum,
FLMUINT * puiType)
{
RCODE rc = NE_XFLM_OK;
if( uiFieldNum < m_uiFieldTblSize)
{
if( (*puiType = m_puiFieldTbl[ uiFieldNum - 1]) ==
FLM_4x_UNKNOWN_TYPE)
{
rc = RC_SET( NE_XFLM_BAD_ELEMENT_NUM);
goto Exit;
}
}
else
{
// Check if the field is a FLAIM dictionary field.
// Most of these fields are TEXT fields.
if( (uiFieldNum >= FLM_4x_DICT_FIELD_NUMS) &&
(uiFieldNum <= FLM_4x_LAST_DICT_FIELD_NUM))
{
*puiType = FLM_4x_TEXT_TYPE;
}
else if( uiFieldNum >= FLM_4x_UNREGISTERED_TAGS)
{
*puiType = FLM_4x_TEXT_TYPE;
}
else
{
rc = RC_SET( NE_XFLM_BAD_ELEMENT_NUM);
goto Exit;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::readDictionary( void)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiType;
FLMUINT uiFieldNum;
F_Record * pRec = NULL;
void * pvField;
if( m_puiFieldTbl)
{
f_free( &m_puiFieldTbl);
}
m_uiFieldTblSize = 0;
if( RC_BAD( rc = f_alloc( FLM_4x_RESERVED_TAG_NUMS,
&m_puiFieldTbl)))
{
goto Exit;
}
m_uiFieldTblSize = FLM_4x_RESERVED_TAG_NUMS;
f_memset( m_puiFieldTbl, FLM_4x_UNKNOWN_TYPE, m_uiFieldTblSize);
setDefaultContainer( FLM_4x_DICT_CONTAINER);
for( ;;)
{
if( RC_BAD( rc = retrieveNextRec( &pRec)))
{
if( rc != NE_XFLM_EOF_HIT)
{
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
if( pRec->getFieldID( pRec->root()) == FLM_4x_FIELD_TAG)
{
pvField = pRec->firstChild( pRec->root());
if( RC_BAD( rc = getTypeTag( pRec, pvField, &uiType)))
{
goto Exit;
}
uiFieldNum = pRec->getID();
flmAssert( uiFieldNum < FLM_4x_RESERVED_TAG_NUMS);
m_puiFieldTbl[ uiFieldNum - 1] = uiType;
}
}
Exit:
if( pRec)
{
pRec->Release();
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_4xReader::getTypeTag(
F_Record * pRec,
void * pvField,
FLMUINT * puiType)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiType;
FLMUINT uiBufLen;
char szTmpBuf[ 64];
uiBufLen = sizeof( szTmpBuf);
if( RC_BAD( rc = pRec->getNative( pvField, szTmpBuf, &uiBufLen)))
{
goto Exit;
}
if( f_strnicmp( szTmpBuf, "text", 4) == 0)
{
uiType = FLM_4x_TEXT_TYPE;
}
else if( f_strnicmp( szTmpBuf, "numb", 4) == 0)
{
uiType = FLM_4x_NUMBER_TYPE;
}
else if( f_strnicmp( szTmpBuf, "bina", 4) == 0)
{
uiType = FLM_4x_BINARY_TYPE;
}
else if( f_strnicmp( szTmpBuf, "cont", 4) == 0)
{
uiType = FLM_4x_CONTEXT_TYPE;
}
else if( f_strnicmp( szTmpBuf, "blob", 4) == 0)
{
uiType = FLM_4x_BLOB_TYPE;
}
else
{
rc = RC_SET( NE_XFLM_SYNTAX);
goto Exit;
}
*puiType = uiType;
Exit:
return( rc);
}
/****************************************************************************
Desc: Constructor
****************************************************************************/
F_4xNameTable::F_4xNameTable()
{
m_pool.poolInit( 1024);
m_ppSortedByTagName = NULL;
m_ppSortedByTagNum = NULL;
m_ppSortedByTagTypeAndName = NULL;
m_uiTblSize = 0;
m_uiNumTags = 0;
m_bTablesSorted = FALSE;
}
/****************************************************************************
Desc: Destructor
****************************************************************************/
F_4xNameTable::~F_4xNameTable()
{
clearTable();
m_pool.poolFree();
}
/****************************************************************************
Desc: Free everything in the table
****************************************************************************/
void F_4xNameTable::clearTable( void)
{
m_pool.poolFree();
m_pool.poolInit( 1024);
// NOTE: Only one allocation is used for m_ppSortedByTagName,
// m_ppSortedByTagNum, and m_ppSortedByTagTypeAndName - there is no
// need to free m_ppSortedByTagNum and m_ppSortedByTagTypeAndName.
if (m_ppSortedByTagName)
{
f_free( &m_ppSortedByTagName);
m_ppSortedByTagNum = NULL;
m_ppSortedByTagTypeAndName = NULL;
m_uiTblSize = 0;
m_uiNumTags = 0;
}
}
/****************************************************************************
Desc: Compare two tag names. Name1 can be NATIVE or UNICODE. If a
non-NULL UNICODE string is passed, it will be used. Otherwise,
the NATIVE string will be used.
Note: Comparison is case insensitive for the ASCII characters A-Z.
****************************************************************************/
FLMINT F_4xNameTable::tagNameCompare(
const FLMUNICODE * puzName1, // If NULL, use pszName1 for comparison
const char * pszName1,
const FLMUNICODE * puzName2)
{
FLMUNICODE uzChar1;
FLMUNICODE uzChar2;
if (puzName1)
{
for (;;)
{
uzChar1 = *puzName1;
uzChar2 = *puzName2;
// Convert to lower case for comparison.
if (uzChar1 >= 'A' && uzChar1 <= 'Z')
{
uzChar1 = uzChar1 - 'A' + 'a';
}
if (uzChar2 >= 'A' && uzChar2 <= 'Z')
{
uzChar2 = uzChar2 - 'A' + 'a';
}
if (!uzChar1 || !uzChar2 || uzChar1 != uzChar2)
{
break;
}
puzName1++;
puzName2++;
}
}
else
{
for (;;)
{
uzChar1 = (FLMUNICODE)*pszName1;
uzChar2 = *puzName2;
// Convert to lower case for comparison.
if (uzChar1 >= 'A' && uzChar1 <= 'Z')
{
uzChar1 = uzChar1 - 'A' + 'a';
}
if (uzChar2 >= 'A' && uzChar2 <= 'Z')
{
uzChar2 = uzChar2 - 'A' + 'a';
}
if (!uzChar1 || !uzChar2 || uzChar1 != uzChar2)
{
break;
}
pszName1++;
puzName2++;
}
}
if (uzChar1)
{
return( (FLMINT)((uzChar2 && uzChar1 < uzChar2)
? (FLMINT)-1
: (FLMINT)1));
}
else if (uzChar2)
{
return( -1);
}
else
{
return( 0);
}
}
/****************************************************************************
Desc: Lookup a tag by tag name. Tag name is passed in as a UNICODE
string or a NATIVE string. If a non-NULL UNICODE string is
passed in, it will be used. Otherwise, the NATIVE string will
be used.
****************************************************************************/
FLM_4x_TAG_INFO * F_4xNameTable::findTagByName(
const FLMUNICODE * puzTagName,
const char * pszTagName,
FLMUINT * puiInsertPos)
{
FLM_4x_TAG_INFO * pTagInfo = NULL;
FLMUINT uiTblSize;
FLMUINT uiLow;
FLMUINT uiMid;
FLMUINT uiHigh;
FLMINT iCmp;
// Do binary search in the table
if ((uiTblSize = m_uiNumTags) == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = --uiTblSize;
uiLow = 0;
for (;;)
{
uiMid = (uiLow + uiHigh) / 2;
iCmp = tagNameCompare( puzTagName, pszTagName,
m_ppSortedByTagName [uiMid]->puzTagName);
if (iCmp == 0)
{
// Found Match
pTagInfo = m_ppSortedByTagName [uiMid];
if (puiInsertPos)
{
*puiInsertPos = uiMid;
}
goto Exit;
}
// Check if we are done
if (uiLow >= uiHigh)
{
// Done, item not found
if (puiInsertPos)
{
*puiInsertPos = (iCmp < 0)
? uiMid
: uiMid + 1;
}
goto Exit;
}
if (iCmp < 0)
{
if (uiMid == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = uiMid - 1;
}
else
{
if (uiMid == uiTblSize)
{
if (puiInsertPos)
{
*puiInsertPos = uiMid + 1;
}
goto Exit;
}
uiLow = uiMid + 1;
}
}
Exit:
return( pTagInfo);
}
/****************************************************************************
Desc: Lookup a tag by tag number.
****************************************************************************/
FLM_4x_TAG_INFO * F_4xNameTable::findTagByNum(
FLMUINT uiTagNum,
FLMUINT * puiInsertPos)
{
FLM_4x_TAG_INFO * pTagInfo = NULL;
FLMUINT uiTblSize;
FLMUINT uiLow;
FLMUINT uiMid;
FLMUINT uiHigh;
FLMUINT uiTblTagNum;
// Do binary search in the table
if ((uiTblSize = m_uiNumTags) == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = --uiTblSize;
uiLow = 0;
for (;;)
{
uiMid = (uiLow + uiHigh) / 2;
uiTblTagNum = m_ppSortedByTagNum [uiMid]->uiTagNum;
if (uiTagNum == uiTblTagNum)
{
// Found Match
pTagInfo = m_ppSortedByTagNum [uiMid];
if (puiInsertPos)
{
*puiInsertPos = uiMid;
}
goto Exit;
}
// Check if we are done
if (uiLow >= uiHigh)
{
// Done, item not found
if (puiInsertPos)
{
*puiInsertPos = (uiTagNum < uiTblTagNum)
? uiMid
: uiMid + 1;
}
goto Exit;
}
if (uiTagNum < uiTblTagNum)
{
if (uiMid == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = uiMid - 1;
}
else
{
if (uiMid == uiTblSize)
{
if (puiInsertPos)
{
*puiInsertPos = uiMid + 1;
}
goto Exit;
}
uiLow = uiMid + 1;
}
}
Exit:
return( pTagInfo);
}
/****************************************************************************
Desc: Lookup a tag by tag type and tag name. Tag name is passed
in as a UNICODE string or a NATIVE string. If a non-NULL
UNICODE string is passed in, it will be used. Otherwise, the
NATIVE string will be used.
****************************************************************************/
FLM_4x_TAG_INFO * F_4xNameTable::findTagByTypeAndName(
const FLMUNICODE * puzTagName,
const char * pszTagName,
FLMUINT uiType,
FLMUINT * puiInsertPos)
{
FLM_4x_TAG_INFO * pTagInfo = NULL;
FLMUINT uiTblType;
FLMUINT uiTblSize;
FLMUINT uiLow;
FLMUINT uiMid;
FLMUINT uiHigh;
FLMINT iCmp;
// Do binary search in the table
if ((uiTblSize = m_uiNumTags) == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = --uiTblSize;
uiLow = 0;
for (;;)
{
uiMid = (uiLow + uiHigh) / 2;
uiTblType = m_ppSortedByTagTypeAndName [uiMid]->uiType;
if (uiType < uiTblType)
{
iCmp = -1;
}
else if (uiType > uiTblType)
{
iCmp = 1;
}
else if ((iCmp = tagNameCompare( puzTagName, pszTagName,
m_ppSortedByTagTypeAndName [uiMid]->puzTagName)) == 0)
{
// Found Match
pTagInfo = m_ppSortedByTagTypeAndName [uiMid];
if (puiInsertPos)
{
*puiInsertPos = uiMid;
}
goto Exit;
}
// Check if we are done
if (uiLow >= uiHigh)
{
// Done, item not found
if (puiInsertPos)
{
*puiInsertPos = (iCmp < 0)
? uiMid
: uiMid + 1;
}
goto Exit;
}
if (iCmp < 0)
{
if (uiMid == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = uiMid - 1;
}
else
{
if (uiMid == uiTblSize)
{
if (puiInsertPos)
{
*puiInsertPos = uiMid + 1;
}
goto Exit;
}
uiLow = uiMid + 1;
}
}
Exit:
return( pTagInfo);
}
/****************************************************************************
Desc: Copy a tag name to a UNICODE or NATIVE buffer. Truncate if
necessary. If a non-NULL UNICODE string is passed in, it will
be populated. Otherwise, the NATIVE string will be populated.
****************************************************************************/
void F_4xNameTable::copyTagName(
FLMUNICODE * puzDestTagName,
char * pszDestTagName,
FLMUINT uiDestBufSize, // Bytes, must be enough for null terminator
FLMUNICODE * puzSrcTagName)
{
if (puzDestTagName)
{
// Decrement name buffer size by sizeof( FLMUNICODE) to allow for a
// terminating NULL character. uiDestBufSize better be at list big
// enough for a null terminating character.
flmAssert( uiDestBufSize >= sizeof( FLMUNICODE));
uiDestBufSize -= sizeof( FLMUNICODE);
// Copy the name to the NATIVE buffer. Non-Ascii UNICODE characters
// will be returned as question marks (?).
while (uiDestBufSize >= sizeof( FLMUNICODE) && *puzSrcTagName)
{
*puzDestTagName++ = *puzSrcTagName;
uiDestBufSize -= sizeof( FLMUNICODE);
puzSrcTagName++;
}
*puzDestTagName = 0;
}
else
{
// Decrement name buffer size by one to allow for a terminating
// NULL character. uiDestBufSize better be at list big
// enough for a null terminating character.
flmAssert( uiDestBufSize);
uiDestBufSize--;
// Copy the name to the NATIVE buffer. Non-Ascii UNICODE characters
// will be returned as question marks (?).
while (uiDestBufSize && *puzSrcTagName)
{
if (*puzSrcTagName <= 127)
{
*pszDestTagName++ = (char)*puzSrcTagName;
}
else
{
*pszDestTagName++ = '?';
}
uiDestBufSize--;
puzSrcTagName++;
}
*pszDestTagName = 0;
}
}
/***************************************************************************
Desc: Sort an array of SCACHE pointers by their block address.
****************************************************************************/
void F_4xNameTable::sortTagTbl(
FLM_4x_TAG_INFO ** ppTagInfoTbl,
FLMUINT uiLowerBounds,
FLMUINT uiUpperBounds,
FLM_4x_TAG_COMPARE_FUNC fnTagCompare)
{
FLMUINT uiLBPos;
FLMUINT uiUBPos;
FLMUINT uiMIDPos;
FLMUINT uiLeftItems;
FLMUINT uiRightItems;
FLM_4x_TAG_INFO * pCurTagInfo;
FLMINT iCompare;
Iterate_Larger_Half:
uiUBPos = uiUpperBounds;
uiLBPos = uiLowerBounds;
uiMIDPos = (uiUpperBounds + uiLowerBounds + 1) / 2;
pCurTagInfo = ppTagInfoTbl [uiMIDPos ];
for (;;)
{
while (uiLBPos == uiMIDPos || // Don't compare with target
((iCompare =
fnTagCompare( ppTagInfoTbl [uiLBPos], pCurTagInfo)) < 0))
{
if (uiLBPos >= uiUpperBounds)
{
break;
}
uiLBPos++;
}
while (uiUBPos == uiMIDPos || // Don't compare with target
(((iCompare =
fnTagCompare( pCurTagInfo, ppTagInfoTbl [uiUBPos])) < 0)))
{
if (!uiUBPos)
{
break;
}
uiUBPos--;
}
if (uiLBPos < uiUBPos ) // Interchange and continue loop.
{
// Exchange [uiLBPos] with [uiUBPos].
tagInfoSwap( ppTagInfoTbl, uiLBPos, uiUBPos);
uiLBPos++; // Scan from left to right.
uiUBPos--; // Scan from right to left.
}
else // Past each other - done
{
break;
}
}
// Check for swap( LB, MID ) - cases 3 and 4
if( uiLBPos < uiMIDPos )
{
// Exchange [uiLBPos] with [uiMIDPos]
tagInfoSwap( ppTagInfoTbl, uiMIDPos, uiLBPos);
uiMIDPos = uiLBPos;
}
else if( uiMIDPos < uiUBPos )
{
// Exchange [uUBPos] with [uiMIDPos]
tagInfoSwap( ppTagInfoTbl, uiMIDPos, uiUBPos);
uiMIDPos = uiUBPos;
}
// Check the left piece.
uiLeftItems = (uiLowerBounds + 1 < uiMIDPos )
? uiMIDPos - uiLowerBounds // 2 or more
: 0;
uiRightItems = (uiMIDPos + 1 < uiUpperBounds )
? uiUpperBounds - uiMIDPos // 2 or more
: 0;
if( uiLeftItems < uiRightItems )
{
// Recurse on the LEFT side and goto the top on the RIGHT side.
if (uiLeftItems )
{
sortTagTbl( ppTagInfoTbl, uiLowerBounds, uiMIDPos - 1, fnTagCompare);
}
uiLowerBounds = uiMIDPos + 1;
goto Iterate_Larger_Half;
}
else if (uiLeftItems ) // Compute a truth table to figure out this check.
{
// Recurse on the RIGHT side and goto the top for the LEFT side.
if (uiRightItems )
{
sortTagTbl( ppTagInfoTbl, uiMIDPos + 1, uiUpperBounds, fnTagCompare);
}
uiUpperBounds = uiMIDPos - 1;
goto Iterate_Larger_Half;
}
}
/****************************************************************************
Desc: Allocate a new tag info structure and set it up.
****************************************************************************/
RCODE F_4xNameTable::allocTag(
const FLMUNICODE * puzTagName,
const char * pszTagName,
FLMUINT uiTagNum,
FLMUINT uiType,
FLMUINT uiSubType,
FLM_4x_TAG_INFO ** ppTagInfo)
{
RCODE rc = NE_XFLM_OK;
void * pvMark;
FLM_4x_TAG_INFO * pTagInfo;
FLMUINT uiNameSize;
FLMUNICODE * puzTmp;
// Create a new tag info structure.
pvMark = m_pool.poolMark();
if( RC_BAD( rc = m_pool.poolAlloc( sizeof( FLM_4x_TAG_INFO),
(void **)&pTagInfo)))
{
goto Exit;
}
// Allocate the space for the tag name.
if (puzTagName)
{
uiNameSize = (f_unilen( puzTagName) + 1) * sizeof( FLMUNICODE);
if( RC_BAD( rc = m_pool.poolAlloc( uiNameSize,
(void **)&pTagInfo->puzTagName)))
{
goto Exit;
}
f_memcpy( pTagInfo->puzTagName, puzTagName, uiNameSize);
}
else
{
uiNameSize = (f_strlen( pszTagName) + 1) * sizeof( FLMUNICODE);
if( RC_BAD( rc = m_pool.poolAlloc( uiNameSize,
(void **)&pTagInfo->puzTagName)))
{
goto Exit;
}
puzTmp = pTagInfo->puzTagName;
while (*pszTagName)
{
*puzTmp++ = (FLMUNICODE)*pszTagName;
pszTagName++;
}
*puzTmp = 0;
}
pTagInfo->uiTagNum = uiTagNum;
pTagInfo->uiType = uiType;
pTagInfo->uiSubType = uiSubType;
Exit:
if (RC_BAD( rc))
{
m_pool.poolReset( pvMark);
pTagInfo = NULL;
}
*ppTagInfo = pTagInfo;
return( rc);
}
/****************************************************************************
Desc: Allocate the sort tables.
****************************************************************************/
RCODE F_4xNameTable::reallocSortTables(
FLMUINT uiNewTblSize)
{
RCODE rc = NE_XFLM_OK;
FLM_4x_TAG_INFO ** ppNewTbl;
if( RC_BAD( rc = f_alloc(
sizeof( FLM_4x_TAG_INFO *) * uiNewTblSize * 3, &ppNewTbl)))
{
goto Exit;
}
// Copy the old tables into the new.
if (m_uiNumTags)
{
f_memcpy( ppNewTbl, m_ppSortedByTagName,
sizeof( FLM_4x_TAG_INFO *) * m_uiNumTags);
f_memcpy( &ppNewTbl [uiNewTblSize], m_ppSortedByTagNum,
sizeof( FLM_4x_TAG_INFO *) * m_uiNumTags);
f_memcpy( &ppNewTbl [uiNewTblSize + uiNewTblSize],
m_ppSortedByTagTypeAndName,
sizeof( FLM_4x_TAG_INFO *) * m_uiNumTags);
f_free( &m_ppSortedByTagName);
}
m_ppSortedByTagName = ppNewTbl;
m_ppSortedByTagNum = &ppNewTbl [uiNewTblSize];
m_ppSortedByTagTypeAndName = &ppNewTbl [uiNewTblSize + uiNewTblSize];
m_uiTblSize = uiNewTblSize;
Exit:
return( rc);
}
/****************************************************************************
Desc: Get a tag name, number, etc. using tag number ordering.
Tag name is returned as a UNICODE string or NATIVE string. If a
non-NULL UNICODE string is passed in, it will be used.
Otherwise, the NATIVE string will be used.
****************************************************************************/
FLMBOOL F_4xNameTable::getNextTagNumOrder(
FLMUINT * puiNextPos,
FLMUNICODE * puzTagName,
char * pszTagName,
FLMUINT uiNameBufSize,
FLMUINT * puiTagNum, // May be NULL
FLMUINT * puiType, // May be NULL
FLMUINT * puiSubType) // May be NULL
{
FLM_4x_TAG_INFO * pTagInfo = NULL;
if (!m_bTablesSorted)
{
sortTags();
}
if (*puiNextPos < m_uiNumTags)
{
pTagInfo = m_ppSortedByTagNum [*puiNextPos];
if (puiTagNum)
{
*puiTagNum = pTagInfo->uiTagNum;
}
if (puiType)
{
*puiType = pTagInfo->uiType;
}
if (puiSubType)
{
*puiSubType = pTagInfo->uiSubType;
}
if( puzTagName || pszTagName)
{
copyTagName( puzTagName, pszTagName, uiNameBufSize,
pTagInfo->puzTagName);
}
// Returned *puiNextPos should be the next one to retrieve.
(*puiNextPos)++;
}
else
{
// Nothing more in list, but initialize return variables anyway.
if (puzTagName)
{
*puzTagName = 0;
}
if (pszTagName)
{
*pszTagName = 0;
}
if (puiTagNum)
{
*puiTagNum = 0;
}
if (puiType)
{
*puiType = 0;
}
if (puiSubType)
{
*puiSubType = 0;
}
}
return( (FLMBOOL)(pTagInfo ? (FLMBOOL)TRUE : (FLMBOOL)FALSE));
}
/****************************************************************************
Desc: Get a tag name, number, etc. using tag name ordering.
Tag name is returned as a UNICODE string or NATIVE string. If a
non-NULL UNICODE string is passed in, it will be used.
Otherwise, the NATIVE string will be used.
****************************************************************************/
FLMBOOL F_4xNameTable::getNextTagNameOrder(
FLMUINT * puiNextPos,
FLMUNICODE * puzTagName,
char * pszTagName,
FLMUINT uiNameBufSize,
FLMUINT * puiTagNum, // May be NULL
FLMUINT * puiType, // May be NULL
FLMUINT * puiSubType) // May be NULL
{
FLM_4x_TAG_INFO * pTagInfo = NULL;
if (!m_bTablesSorted)
{
sortTags();
}
if (*puiNextPos < m_uiNumTags)
{
pTagInfo = m_ppSortedByTagName [*puiNextPos];
if (puiTagNum)
{
*puiTagNum = pTagInfo->uiTagNum;
}
if (puiType)
{
*puiType = pTagInfo->uiType;
}
if (puiSubType)
{
*puiSubType = pTagInfo->uiSubType;
}
if( puzTagName || pszTagName)
{
copyTagName( puzTagName, pszTagName, uiNameBufSize,
pTagInfo->puzTagName);
}
// Returned *puiNextPos should be the next one to retrieve.
(*puiNextPos)++;
}
else
{
// Nothing more in list, but initialize return variables anyway.
if (puzTagName)
{
*puzTagName = 0;
}
if (pszTagName)
{
*pszTagName = 0;
}
if (puiTagNum)
{
*puiTagNum = 0;
}
if (puiType)
{
*puiType = 0;
}
if (puiSubType)
{
*puiSubType = 0;
}
}
return( (FLMBOOL)(pTagInfo ? (FLMBOOL)TRUE : (FLMBOOL)FALSE));
}
/****************************************************************************
Desc: Get a tag name and number from type. Tag name is returned as a
UNICODE string or NATIVE string. If a non-NULL UNICODE string is
passed in, it will be used. Otherwise, the NATIVE string
will be used.
****************************************************************************/
FLMBOOL F_4xNameTable::getFromTagType(
FLMUINT uiType,
FLMUINT * puiNextPos, // To get first, initialize to zero.
FLMUNICODE * puzTagName,
char * pszTagName,
FLMUINT uiNameBufSize, // In bytes - must be at least sizeof( FLMUNICODE)
FLMUINT * puiTagNum, // May be NULL
FLMUINT * puiSubType) // May be NULL
{
FLM_4x_TAG_INFO * pTagInfo = NULL;
if (!m_bTablesSorted)
{
sortTags();
}
if (*puiNextPos == 0)
{
// A value of zero indicates we should try to find the first
// one.
(void)findTagByTypeAndName( NULL, "", uiType, puiNextPos);
if (*puiNextPos < m_uiNumTags &&
m_ppSortedByTagTypeAndName [*puiNextPos]->uiType != uiType)
{
(*puiNextPos)++;
}
}
if (*puiNextPos < m_uiNumTags &&
m_ppSortedByTagTypeAndName [*puiNextPos]->uiType == uiType)
{
pTagInfo = m_ppSortedByTagTypeAndName [*puiNextPos];
if (puiTagNum)
{
*puiTagNum = pTagInfo->uiTagNum;
}
if (puiSubType)
{
*puiSubType = pTagInfo->uiSubType;
}
if( puzTagName || pszTagName)
{
copyTagName( puzTagName, pszTagName, uiNameBufSize,
pTagInfo->puzTagName);
}
// Returned *puiNextPos should be the next one to retrieve, so that
// it is not zero.
(*puiNextPos)++;
}
else
{
// Type was not found, but initialize return variables anyway.
if (puzTagName)
{
*puzTagName = 0;
}
if (pszTagName)
{
*pszTagName = 0;
}
if (puiTagNum)
{
*puiTagNum = 0;
}
if (puiSubType)
{
*puiSubType = 0;
}
}
return( (FLMBOOL)(pTagInfo ? (FLMBOOL)TRUE : (FLMBOOL)FALSE));
}
/****************************************************************************
Desc: Get a tag name from its tag number. Tag name is returned as a
UNICODE string or NATIVE string. If a non-NULL UNICODE string
is passed in, it will be used. Otherwise, the NATIVE string
will be used.
****************************************************************************/
FLMBOOL F_4xNameTable::getFromTagNum(
FLMUINT uiTagNum,
FLMUNICODE * puzTagName,
char * pszTagName,
FLMUINT uiNameBufSize, // In bytes, at least enough for null char.
FLMUINT * puiType, // May be NULL
FLMUINT * puiSubType) // May be NULL
{
FLM_4x_TAG_INFO * pTagInfo;
if (!m_bTablesSorted)
{
sortTags();
}
if ((pTagInfo = findTagByNum( uiTagNum)) != NULL)
{
if (puiType)
{
*puiType = pTagInfo->uiType;
}
if (puiSubType)
{
*puiSubType = pTagInfo->uiSubType;
}
if( puzTagName || pszTagName)
{
copyTagName( puzTagName, pszTagName, uiNameBufSize,
pTagInfo->puzTagName);
}
}
else
{
// Tag number was not found, but initialize return variables anyway.
if (puzTagName)
{
*puzTagName = 0;
}
if (pszTagName)
{
*pszTagName = 0;
}
if (puiType)
{
*puiType = 0;
}
if (puiSubType)
{
*puiSubType = 0;
}
}
return( (FLMBOOL)(pTagInfo ? (FLMBOOL)TRUE : (FLMBOOL)FALSE));
}
/****************************************************************************
Desc: Get a tag number and type from its tag name. Tag name is passed
in as a UNICODE string or NATIVE string. If a non-NULL UNICODE
string is passed in, it will be used. Otherwise, the NATIVE
string will be used.
****************************************************************************/
FLMBOOL F_4xNameTable::getFromTagName(
const FLMUNICODE * puzTagName,
const char * pszTagName,
FLMUINT * puiTagNum, // Cannot be NULL
FLMUINT * puiType, // May be NULL
FLMUINT * puiSubType) // May be NULL
{
FLM_4x_TAG_INFO * pTagInfo;
if (!m_bTablesSorted)
{
sortTags();
}
if ((pTagInfo = findTagByName( puzTagName, pszTagName)) != NULL)
{
flmAssert( puiTagNum);
*puiTagNum = pTagInfo->uiTagNum;
if (puiType)
{
*puiType = pTagInfo->uiType;
}
if (puiSubType)
{
*puiSubType = pTagInfo->uiSubType;
}
}
else
{
// Tag name was not found, but initialize return variables anyway.
*puiTagNum = 0;
if (puiType)
{
*puiType = 0;
}
if (puiSubType)
{
*puiSubType = 0;
}
}
return( (FLMBOOL)(pTagInfo ? (FLMBOOL)TRUE : (FLMBOOL)FALSE));
}
/****************************************************************************
Desc: Get a tag number from its tag name and type. Tag name is passed
in as a UNICODE or NATIVE string. If a non-NULL UNICODE string is
passed in, it will be used. Otherwise, the NATIVE string will
be used.
****************************************************************************/
FLMBOOL F_4xNameTable::getFromTagTypeAndName(
const FLMUNICODE * puzTagName,
const char * pszTagName,
FLMUINT uiType,
FLMUINT * puiTagNum, // Cannot be NULL
FLMUINT * puiSubType) // May be NULL
{
FLM_4x_TAG_INFO * pTagInfo;
if (!m_bTablesSorted)
{
sortTags();
}
if ((pTagInfo = findTagByTypeAndName( puzTagName, pszTagName,
uiType)) != NULL)
{
flmAssert( puiTagNum);
*puiTagNum = pTagInfo->uiTagNum;
if (puiSubType)
{
*puiSubType = pTagInfo->uiSubType;
}
}
else
{
// Tag name was not found, but initialize return variables anyway.
*puiTagNum = 0;
if (puiSubType)
{
*puiSubType = 0;
}
}
return( (FLMBOOL)(pTagInfo ? (FLMBOOL)TRUE : (FLMBOOL)FALSE));
}
/****************************************************************************
Desc: Insert a tag info structure into the sorted tables at the
specified positions.
****************************************************************************/
RCODE F_4xNameTable::insertTagInTables(
FLM_4x_TAG_INFO * pTagInfo,
FLMUINT uiTagNameTblInsertPos,
FLMUINT uiTagTypeAndNameTblInsertPos,
FLMUINT uiTagNumTblInsertPos)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiLoop;
// See if we need to resize the tables. Start at 256. Double each
// time up to 2048. Then just add 2048 at a time.
if (m_uiNumTags == m_uiTblSize)
{
FLMUINT uiNewSize;
if (!m_uiTblSize)
{
uiNewSize = 256;
}
else if (m_uiTblSize < 2048)
{
uiNewSize = m_uiTblSize * 2;
}
else
{
uiNewSize = m_uiTblSize + 2048;
}
if (RC_BAD( rc = reallocSortTables( uiNewSize)))
{
goto Exit;
}
}
// Insert into the sorted-by-name table
uiLoop = m_uiNumTags;
while (uiLoop > uiTagNameTblInsertPos)
{
m_ppSortedByTagName [uiLoop] = m_ppSortedByTagName [uiLoop - 1];
uiLoop--;
}
m_ppSortedByTagName [uiTagNameTblInsertPos] = pTagInfo;
// Insert into the sorted-by-number table
uiLoop = m_uiNumTags;
while (uiLoop > uiTagNumTblInsertPos)
{
m_ppSortedByTagNum [uiLoop] = m_ppSortedByTagNum [uiLoop - 1];
uiLoop--;
}
m_ppSortedByTagNum [uiTagNumTblInsertPos] = pTagInfo;
// Insert into the sorted-by-tag-name-and-type table
uiLoop = m_uiNumTags;
while (uiLoop > uiTagTypeAndNameTblInsertPos)
{
m_ppSortedByTagTypeAndName [uiLoop] =
m_ppSortedByTagTypeAndName [uiLoop - 1];
uiLoop--;
}
m_ppSortedByTagTypeAndName [uiTagTypeAndNameTblInsertPos] = pTagInfo;
// Increment the total number of tags
m_uiNumTags++;
Exit:
return( rc);
}
/****************************************************************************
Desc: Add a tag to the table. Tag name is passed in as a UNICODE
string or NATIVE string. If a non-NULL UNICODE string is passed
in, it will be used. Otherwise, the NATIVE string will be used.
****************************************************************************/
RCODE F_4xNameTable::addTag(
const FLMUNICODE * puzTagName,
const char * pszTagName,
FLMUINT uiTagNum,
FLMUINT uiType,
FLMUINT uiSubType,
FLMBOOL bCheckDuplicates)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiTagNameTblInsertPos;
FLMUINT uiTagTypeAndNameTblInsertPos;
FLMUINT uiTagNumTblInsertPos;
FLM_4x_TAG_INFO * pTagInfo;
// Must have a non-NULL tag name. Use UNICODE string if it is
// non-NULL. Otherwise, use NATIVE string.
if (puzTagName && *puzTagName)
{
pszTagName = NULL;
}
else if (pszTagName && *pszTagName)
{
puzTagName = NULL;
}
else
{
rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_PARM);
goto Exit;
}
// Tag number of zero not allowed.
if (!uiTagNum)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_PARM);
goto Exit;
}
// Tables must be sorted in order for this to work
if (bCheckDuplicates)
{
if (!m_bTablesSorted)
{
sortTags();
}
// Make sure that the tag name is not already used.
if (findTagByName( puzTagName, pszTagName, &uiTagNameTblInsertPos))
{
rc = RC_SET( NE_XFLM_EXISTS);
goto Exit;
}
// Make sure that the tag name + type is not already used.
if (findTagByTypeAndName( puzTagName, pszTagName,
uiType, &uiTagTypeAndNameTblInsertPos))
{
rc = RC_SET( NE_XFLM_EXISTS);
goto Exit;
}
// Make sure that the tag number is not already used.
if (findTagByNum( uiTagNum, &uiTagNumTblInsertPos))
{
rc = RC_SET( NE_XFLM_EXISTS);
goto Exit;
}
}
else
{
uiTagNameTblInsertPos =
uiTagTypeAndNameTblInsertPos =
uiTagNumTblInsertPos = m_uiNumTags;
m_bTablesSorted = FALSE;
}
// Create a new tag info structure.
if (RC_BAD( rc = allocTag( puzTagName, pszTagName, uiTagNum, uiType,
uiSubType, &pTagInfo)))
{
goto Exit;
}
// Insert the tag structure into the appropriate places in the
// sorted tables.
if (RC_BAD( rc = insertTagInTables( pTagInfo, uiTagNameTblInsertPos,
uiTagTypeAndNameTblInsertPos,
uiTagNumTblInsertPos)))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Sort the tag tables according to their respective criteria.
****************************************************************************/
void F_4xNameTable::sortTags( void)
{
if (!m_bTablesSorted && m_uiNumTags > 1)
{
sortTagTbl( m_ppSortedByTagName, 0, m_uiNumTags - 1,
compareTagNameOnly);
sortTagTbl( m_ppSortedByTagNum, 0, m_uiNumTags - 1,
compareTagNumOnly);
sortTagTbl( m_ppSortedByTagTypeAndName, 0, m_uiNumTags - 1,
compareTagTypeAndName);
}
m_bTablesSorted = TRUE;
}
/****************************************************************************
Desc: Initialize a name table from a database.
****************************************************************************/
RCODE F_4xNameTable::setupNameTable(
F_4xReader * pDb)
{
RCODE rc = NE_XFLM_OK;
F_Record * pRec = NULL;
FLMUINT uiDrn;
FLMUINT uiLoop;
void * pvField;
FLMUNICODE uzName[ 60];
FLMUNICODE * puzName = &uzName[ 0];
FLMUINT uiNameLen = sizeof( uzName);
FLMUINT uiLen;
FLMUINT uiSubType;
// Clean out all existing tags, if any.
clearTable();
// Find the next DRN in the dictionary container
if( RC_BAD( rc = pDb->getNextDrn( FLM_4x_DICT_CONTAINER, &uiDrn)))
{
goto Exit;
}
// Count the reserved tags
for (uiLoop = 0; Flm4xDictTagInfo[ uiLoop].pszTagName; uiLoop++)
{
;
}
// Preallocate space so we don't have to do it over and over.
if( RC_BAD( rc = reallocSortTables( uiLoop + uiDrn)))
{
goto Exit;
}
// Add in all of the reserved dictionary tags.
for( uiLoop = 0; Flm4xDictTagInfo[ uiLoop].pszTagName; uiLoop++)
{
if( RC_BAD( rc = addTag( NULL,
Flm4xDictTagInfo[ uiLoop].pszTagName,
Flm4xDictTagInfo[ uiLoop].uiTagNum,
FLM_4x_FIELD_TAG,
Flm4xDictTagInfo[ uiLoop].uiFieldType, FALSE)))
{
goto Exit;
}
}
// Read through all of the dictionary records
pDb->setDefaultContainer( FLM_4x_DICT_CONTAINER);
for( ;;)
{
if( RC_BAD( rc = pDb->retrieveNextRec( &pRec)))
{
if( rc != NE_XFLM_EOF_HIT)
{
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
pvField = pRec->root();
uiDrn = pRec->getID();
// Get the unicode name length (does not include NULL terminator)
if( RC_BAD( rc = pRec->getUnicode( pvField, NULL, &uiLen)))
{
goto Exit;
}
// Account for NULL character.
uiLen += sizeof( FLMUNICODE);
// See if we need a larger buffer to get the name.
if (uiLen > uiNameLen)
{
FLMUNICODE * puzTmp;
// Add enough for 60 more unicode characters.
uiLen += (60 * sizeof( FLMUNICODE));
if( RC_BAD( rc = f_alloc( uiLen, &puzTmp)))
{
goto Exit;
}
if (puzName != &uzName [0])
{
f_free( &puzName);
}
puzName = puzTmp;
uiNameLen = uiLen;
}
// Get the tag name.
uiLen = uiNameLen;
if (RC_BAD( rc = pRec->getUnicode( pvField, puzName, &uiLen)))
{
goto Exit;
}
// Get the sub-type.
if (pRec->getFieldID( pvField) == FLM_4x_FIELD_TAG)
{
void * pvFld = pRec->find( pvField, FLM_4x_TYPE_TAG, 1, FALSE);
if (!pvFld ||
RC_BAD( pDb->getTypeTag( pRec, pvFld, &uiSubType)))
{
uiSubType = FLM_4x_TEXT_TYPE;
}
}
else
{
uiSubType = 0;
}
// Add tag to table, without sorting yet.
if (RC_BAD( rc = addTag( puzName, NULL, uiDrn,
pRec->getFieldID( pvField), uiSubType, FALSE)))
{
goto Exit;
}
}
sortTags();
Exit:
if( RC_BAD( rc))
{
clearTable();
}
if( pRec)
{
pRec->Release();
}
if( puzName != &uzName [0])
{
f_free( &puzName);
}
return( rc);
}