git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@789 0109f412-320b-0410-ab79-c3e0c5ffbbe6
887 lines
20 KiB
C++
887 lines
20 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: Read a record from the database.
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1991-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: fsrecget.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
#define NUM_FIELDS_IN_ARRAY 16
|
|
|
|
typedef struct Field_State
|
|
{
|
|
FLMBYTE * pElement; // Points to the element within block
|
|
FLMUINT uiFieldType; // Storage field type
|
|
FLMUINT uiFieldLen; // Length of storage if known
|
|
FLMUINT uiPosInElm; // Position within the element
|
|
FLMUINT uiTagNum; // Field tag/data dictionary number
|
|
FLMUINT uiLevel; // Current level number
|
|
FLMUINT uiEncId; // EncDef ID if encrypted
|
|
FLMUINT uiEncFieldLen; // Encrypted field length
|
|
} FSTATE;
|
|
|
|
typedef struct DATAPIECE
|
|
{
|
|
FLMBYTE * pData; // Points to data within the block.
|
|
FLMUINT uiLength; // Length of this data piece
|
|
DATAPIECE * pNext; // Next data piece or NULL
|
|
} DATAPIECE;
|
|
|
|
typedef struct Temporary_Field
|
|
{
|
|
FLMUINT uiLevel;
|
|
FLMUINT uiFieldID;
|
|
FLMUINT uiFieldType;
|
|
FLMUINT uiFieldLen;
|
|
FLMUINT uiEncId;
|
|
FLMUINT uiEncFieldLen;
|
|
DATAPIECE DataPiece;
|
|
} TEMPFIELD;
|
|
|
|
typedef struct FLDGROUP
|
|
{
|
|
TEMPFIELD pFields[ NUM_FIELDS_IN_ARRAY];
|
|
FLDGROUP * pNext;
|
|
} FLDGROUP;
|
|
|
|
typedef struct LOCKED_BLOCK
|
|
{
|
|
SCACHE * pSCache;
|
|
LOCKED_BLOCK * pNext;
|
|
} LOCKED_BLOCK;
|
|
|
|
FSTATIC RCODE FSGetFldOverhead(
|
|
FDB * pDb,
|
|
FSTATE * fState);
|
|
|
|
/****************************************************************************
|
|
Desc: Retrieves a record given a DRN
|
|
****************************************************************************/
|
|
RCODE FSReadRecord(
|
|
FDB * pDb,
|
|
LFILE * pLFile,
|
|
FLMUINT uiDrn,
|
|
FlmRecord ** ppRecord,
|
|
FLMUINT * puiRecTransId,
|
|
FLMBOOL * pbMostCurrent)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
BTSK stackBuf[BH_MAX_LEVELS];
|
|
BTSK * pStack = NULL;
|
|
FLMBYTE pKeyBuf[DIN_KEY_SIZ];
|
|
FLMBYTE pDrnBuf[DIN_KEY_SIZ];
|
|
|
|
FSInitStackCache( &stackBuf[0], BH_MAX_LEVELS);
|
|
|
|
pStack = stackBuf;
|
|
pStack->pKeyBuf = pKeyBuf;
|
|
|
|
// Search the B-TREE for the record
|
|
|
|
f_UINT32ToBigEndian( (FLMUINT32)uiDrn, pDrnBuf);
|
|
if (RC_OK( rc = FSBtSearch( pDb, pLFile, &pStack, pDrnBuf, 4, 0)))
|
|
{
|
|
rc = RC_SET( FERR_NOT_FOUND);
|
|
|
|
if ((pStack->uiCmpStatus == BT_EQ_KEY) && (uiDrn != DRN_LAST_MARKER))
|
|
{
|
|
rc = FSReadElement( pDb, &pDb->TempPool, pLFile, uiDrn, pStack, TRUE,
|
|
ppRecord, puiRecTransId, pbMostCurrent);
|
|
}
|
|
}
|
|
|
|
FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE);
|
|
return (rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Low-level routine to retrieve and build an internal tree record.
|
|
****************************************************************************/
|
|
RCODE FSReadElement(
|
|
FDB * pDb,
|
|
F_Pool * pPool,
|
|
LFILE * pLFile,
|
|
FLMUINT uiDrn,
|
|
BTSK * pStack,
|
|
FLMBOOL bOkToPreallocSpace,
|
|
FlmRecord ** ppRecord,
|
|
FLMUINT * puiRecTransId,
|
|
FLMBOOL * pbMostCurrent)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pRecord = NULL;
|
|
FLMBYTE * pCurElm;
|
|
void * pvPoolMark = pPool->poolMark();
|
|
FLMUINT uiElmRecLen;
|
|
FLMUINT uiFieldLen;
|
|
FLMUINT uiLowestTransId;
|
|
FLMUINT uiFieldCount;
|
|
FLMUINT uiTrueDataSpace;
|
|
FLMUINT uiFieldPos;
|
|
FLMBOOL bMostCurrent;
|
|
TEMPFIELD * pField;
|
|
FLDGROUP * pFldGroup = NULL;
|
|
FLDGROUP* pFirstFldGroup = NULL;
|
|
DATAPIECE * pDataPiece;
|
|
LOCKED_BLOCK * pLockedBlock = NULL;
|
|
FSTATE fState;
|
|
FLMUINT uiEncFieldLen;
|
|
|
|
// Initialize variables
|
|
|
|
fState.uiLevel = 0;
|
|
uiFieldCount = 0;
|
|
uiTrueDataSpace = 0;
|
|
uiFieldPos = NUM_FIELDS_IN_ARRAY;
|
|
|
|
// Check to make sure we are positioned at the first element.
|
|
|
|
pCurElm = CURRENT_ELM( pStack);
|
|
if (!BBE_IS_FIRST( pCurElm))
|
|
{
|
|
rc = RC_SET( FERR_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
uiLowestTransId = FB2UD( &pStack->pBlk[BH_TRANS_ID]);
|
|
bMostCurrent = (pStack->pSCache->uiHighTransID == 0xFFFFFFFF)
|
|
? TRUE
|
|
: FALSE;
|
|
|
|
// Loop on each element in the record
|
|
|
|
for (;;)
|
|
{
|
|
|
|
// Setup all variables to process the current element
|
|
|
|
uiElmRecLen = BBE_GET_RL( pCurElm);
|
|
if (uiElmRecLen == 0)
|
|
{
|
|
rc = RC_SET( FERR_EOF_HIT);
|
|
break;
|
|
}
|
|
|
|
pCurElm += BBE_REC_OFS( pCurElm);
|
|
fState.uiPosInElm = 0;
|
|
|
|
// Loop on each field within this element.
|
|
|
|
while (fState.uiPosInElm < uiElmRecLen)
|
|
{
|
|
fState.pElement = pCurElm;
|
|
if (RC_BAD( rc = FSGetFldOverhead( pDb, &fState)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiFieldLen = fState.uiFieldLen;
|
|
uiEncFieldLen = fState.uiEncFieldLen;
|
|
|
|
// Old record info data - skip past for now
|
|
|
|
if (fState.uiTagNum == 0)
|
|
{
|
|
fState.uiPosInElm += (uiEncFieldLen ? uiEncFieldLen : uiFieldLen);
|
|
continue;
|
|
}
|
|
|
|
if (!pRecord)
|
|
{
|
|
|
|
// Create a new data record or use the existing data record.
|
|
|
|
if (*ppRecord)
|
|
{
|
|
if ((*ppRecord)->isReadOnly())
|
|
{
|
|
(*ppRecord)->Release();
|
|
*ppRecord = NULL;
|
|
|
|
if ((pRecord = f_new FlmRecord) == NULL)
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// Reuse the existing FlmRecord object.
|
|
|
|
pRecord = *ppRecord;
|
|
*ppRecord = NULL;
|
|
pRecord->clear();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((pRecord = f_new FlmRecord) == NULL)
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pRecord->setContainerID( pLFile->uiLfNum);
|
|
pRecord->setID( uiDrn);
|
|
if (pLFile->bMakeFieldIdTable)
|
|
{
|
|
pRecord->enableFieldIdTable();
|
|
}
|
|
}
|
|
|
|
// 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 = pPool->poolAlloc(
|
|
sizeof( FLDGROUP), (void **)&pTempFldGroup)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pTempFldGroup->pNext = NULL;
|
|
if (pFldGroup)
|
|
{
|
|
pFldGroup->pNext = pTempFldGroup;
|
|
}
|
|
else
|
|
{
|
|
pFirstFldGroup = pTempFldGroup;
|
|
}
|
|
|
|
pFldGroup = pTempFldGroup;
|
|
}
|
|
|
|
uiFieldCount++;
|
|
pField = &pFldGroup->pFields[uiFieldPos++];
|
|
pField->uiLevel = fState.uiLevel;
|
|
pField->uiFieldID = fState.uiTagNum;
|
|
pField->uiFieldType = fState.uiFieldType;
|
|
pField->uiFieldLen = fState.uiFieldLen;
|
|
pField->uiEncId = fState.uiEncId;
|
|
pField->uiEncFieldLen = fState.uiEncFieldLen;
|
|
pDataPiece = &pField->DataPiece;
|
|
|
|
if (uiFieldLen || uiEncFieldLen)
|
|
{
|
|
FLMUINT uiDataPos = 0;
|
|
|
|
if (fState.uiEncFieldLen)
|
|
{
|
|
uiTrueDataSpace += FLM_ENC_FLD_OVERHEAD;
|
|
|
|
// Binary data needs to account for alignment issues.
|
|
|
|
if (fState.uiFieldType == FLM_BINARY_TYPE)
|
|
{
|
|
|
|
// Adjust for the decrypted data.
|
|
|
|
uiTrueDataSpace = ((uiTrueDataSpace + FLM_ALLOC_ALIGN) &
|
|
(~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF));
|
|
}
|
|
|
|
uiTrueDataSpace += fState.uiFieldLen + fState.uiEncFieldLen;
|
|
|
|
// Store the encrypted field length rather than the
|
|
// decrypted field length This will allow the gathering of
|
|
// the encrypted or decrypted field data to use the same
|
|
// code.
|
|
|
|
uiFieldLen = uiEncFieldLen;
|
|
}
|
|
else if (fState.uiFieldLen > 4)
|
|
{
|
|
|
|
// Binary data needs to account for alignment issues.
|
|
|
|
if (fState.uiFieldType == FLM_BINARY_TYPE)
|
|
{
|
|
if (fState.uiFieldLen >= 0xFF)
|
|
{
|
|
|
|
// Align so that the data is aligned - not the length
|
|
|
|
uiTrueDataSpace += sizeof(FLMUINT32);
|
|
uiTrueDataSpace = ((uiTrueDataSpace + FLM_ALLOC_ALIGN) &
|
|
(~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF));
|
|
uiTrueDataSpace -= sizeof(FLMUINT32);
|
|
}
|
|
else
|
|
{
|
|
uiTrueDataSpace = ((uiTrueDataSpace + FLM_ALLOC_ALIGN) &
|
|
(~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF));
|
|
}
|
|
}
|
|
|
|
uiTrueDataSpace += fState.uiFieldLen;
|
|
|
|
// Field values with lengths greater than 255 bytes are
|
|
// stored length-preceded. A single byte flags field
|
|
// precedes the length.
|
|
|
|
if (fState.uiFieldLen >= 0xFF)
|
|
{
|
|
uiTrueDataSpace += sizeof(FLMUINT32) + 1;
|
|
}
|
|
}
|
|
|
|
// Value may start in the next element.
|
|
|
|
while (uiDataPos < uiFieldLen)
|
|
{
|
|
|
|
// Need to read next element for the value portion?
|
|
|
|
if (fState.uiPosInElm >= uiElmRecLen)
|
|
{
|
|
if (BBE_IS_LAST( CURRENT_ELM( pStack)))
|
|
{
|
|
rc = RC_SET( FERR_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
// If we are going to the next block, lock down this
|
|
// block because data pointers are pointing to it.
|
|
|
|
if (RC_BAD( FSBlkNextElm( pStack)))
|
|
{
|
|
LOCKED_BLOCK * pLastLockedBlock = pLockedBlock;
|
|
|
|
if( RC_BAD( rc = pPool->poolAlloc( sizeof( LOCKED_BLOCK),
|
|
(void **)&pLockedBlock)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ScaHoldCache( pStack->pSCache);
|
|
pLockedBlock->pSCache = pStack->pSCache;
|
|
pLockedBlock->pNext = pLastLockedBlock;
|
|
|
|
if (RC_BAD( rc = FSBtNextElm( pDb, pLFile, pStack)))
|
|
{
|
|
rc = (rc == FERR_BT_END_OF_DATA)
|
|
? RC_SET( FERR_DATA_ERROR)
|
|
: rc;
|
|
goto Exit;
|
|
}
|
|
|
|
if (uiLowestTransId > FB2UD( &pStack->pBlk[BH_TRANS_ID]))
|
|
{
|
|
uiLowestTransId = FB2UD( &pStack->pBlk[BH_TRANS_ID]);
|
|
}
|
|
|
|
if (!bMostCurrent)
|
|
{
|
|
bMostCurrent =
|
|
(pStack->pSCache->uiHighTransID == 0xFFFFFFFF)
|
|
? TRUE
|
|
: FALSE;
|
|
}
|
|
}
|
|
|
|
pCurElm = CURRENT_ELM( pStack);
|
|
uiElmRecLen = BBE_GET_RL( pCurElm);
|
|
pCurElm += BBE_REC_OFS( pCurElm);
|
|
fState.uiPosInElm = 0;
|
|
}
|
|
|
|
// Compare number of bytes left if value <= # bytes left
|
|
// in element
|
|
|
|
if (uiFieldLen - uiDataPos <= uiElmRecLen - fState.uiPosInElm)
|
|
{
|
|
FLMUINT uiDelta = uiFieldLen - uiDataPos;
|
|
|
|
pDataPiece->pData = &pCurElm[fState.uiPosInElm];
|
|
pDataPiece->uiLength = uiDelta;
|
|
fState.uiPosInElm += uiDelta;
|
|
pDataPiece->pNext = NULL;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
|
|
// Take what is there and get next element to grab some
|
|
// more.
|
|
|
|
FLMUINT uiBytesToMove = uiElmRecLen - fState.uiPosInElm;
|
|
DATAPIECE * pNextDataPiece;
|
|
|
|
pDataPiece->pData = &pCurElm[fState.uiPosInElm];
|
|
pDataPiece->uiLength = uiBytesToMove;
|
|
fState.uiPosInElm += uiBytesToMove;
|
|
uiDataPos += uiBytesToMove;
|
|
|
|
if( RC_BAD( rc = pPool->poolAlloc( sizeof( DATAPIECE),
|
|
(void **)&pNextDataPiece)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pDataPiece->pNext = pNextDataPiece;
|
|
pDataPiece = pNextDataPiece;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Done?
|
|
|
|
if (BBE_IS_LAST( CURRENT_ELM( pStack)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Position to next element
|
|
|
|
if (RC_BAD( FSBlkNextElm( pStack)))
|
|
{
|
|
LOCKED_BLOCK * pLastLockedBlock = pLockedBlock;
|
|
|
|
if( RC_BAD( rc = pPool->poolAlloc( sizeof( LOCKED_BLOCK),
|
|
(void **)&pLockedBlock)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ScaHoldCache( pStack->pSCache);
|
|
pLockedBlock->pSCache = pStack->pSCache;
|
|
pLockedBlock->pNext = pLastLockedBlock;
|
|
|
|
if (RC_BAD( rc = FSBtNextElm( pDb, pLFile, pStack)))
|
|
{
|
|
if (rc == FERR_BT_END_OF_DATA)
|
|
{
|
|
rc = RC_SET( FERR_DATA_ERROR);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if (uiLowestTransId > FB2UD( &pStack->pBlk[BH_TRANS_ID]))
|
|
{
|
|
uiLowestTransId = FB2UD( &pStack->pBlk[BH_TRANS_ID]);
|
|
}
|
|
|
|
if (!bMostCurrent)
|
|
{
|
|
bMostCurrent = (pStack->pSCache->uiHighTransID == 0xFFFFFFFF)
|
|
? TRUE
|
|
: FALSE;
|
|
}
|
|
}
|
|
|
|
// Corruption Check.
|
|
|
|
pCurElm = CURRENT_ELM( pStack);
|
|
if (BBE_IS_FIRST( pCurElm))
|
|
{
|
|
rc = RC_SET( FERR_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (pRecord)
|
|
{
|
|
void * pvField;
|
|
|
|
if (bOkToPreallocSpace)
|
|
{
|
|
if (RC_BAD( rc = pRecord->preallocSpace(
|
|
uiFieldCount, 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;
|
|
FLMBYTE * pEncDataPtr;
|
|
|
|
pDataPiece = &pField->DataPiece;
|
|
if (RC_BAD( rc = pRecord->allocStorageSpace( pvField,
|
|
pField->uiFieldType, pField->uiFieldLen,
|
|
pField->uiEncFieldLen, pField->uiEncId,
|
|
(pField->uiEncId ? FLD_HAVE_ENCRYPTED_DATA : 0),
|
|
&pDataPtr, &pEncDataPtr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
do
|
|
{
|
|
if (pField->uiEncId)
|
|
{
|
|
f_memcpy( pEncDataPtr, pDataPiece->pData, pDataPiece->uiLength);
|
|
pEncDataPtr += pDataPiece->uiLength;
|
|
}
|
|
else
|
|
{
|
|
f_memcpy( pDataPtr, pDataPiece->pData, pDataPiece->uiLength);
|
|
pDataPtr += pDataPiece->uiLength;
|
|
}
|
|
|
|
pDataPiece = pDataPiece->pNext;
|
|
} while (pDataPiece);
|
|
|
|
// If the field is encrypted, we must decrypt it here.
|
|
|
|
if (pField->uiEncId && !pDb->pFile->bInLimitedMode)
|
|
{
|
|
if (RC_BAD( rc = flmDecryptField( pDb->pDict, pRecord, pvField,
|
|
pField->uiEncId, &pDb->TempPool)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (puiRecTransId)
|
|
{
|
|
*puiRecTransId = uiLowestTransId;
|
|
}
|
|
|
|
if (pbMostCurrent)
|
|
{
|
|
*pbMostCurrent = bMostCurrent;
|
|
}
|
|
|
|
if (*ppRecord)
|
|
{
|
|
flmAssert( 0);
|
|
(*ppRecord)->Release();
|
|
}
|
|
|
|
pRecord->sortFieldIdTable();
|
|
|
|
*ppRecord = pRecord;
|
|
pRecord = NULL;
|
|
|
|
Exit:
|
|
|
|
// Release all locked down blocks except the current block.
|
|
|
|
while (pLockedBlock)
|
|
{
|
|
ScaReleaseCache( pLockedBlock->pSCache, FALSE);
|
|
pLockedBlock = pLockedBlock->pNext;
|
|
}
|
|
|
|
pPool->poolReset( pvPoolMark);
|
|
|
|
if (pRecord)
|
|
{
|
|
pRecord->Release();
|
|
}
|
|
|
|
// You are now positioned to the last element in the record
|
|
|
|
return (rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Read field overhead (level, field drn, and length information. This
|
|
isolates the complexity of the storage formats.
|
|
****************************************************************************/
|
|
FSTATIC RCODE FSGetFldOverhead(
|
|
FDB * pDb,
|
|
FSTATE * fState)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMBYTE * pFieldOvhd = &fState->pElement[fState->uiPosInElm];
|
|
FLMBYTE * pElement = fState->pElement;
|
|
FLMBYTE * pTmp;
|
|
FLMBOOL bDoesntHaveFieldDef = TRUE;
|
|
FLMUINT uiFieldLen;
|
|
FLMUINT uiFieldType = 0;
|
|
FLMUINT uiTagNum;
|
|
FLMBYTE ucBaseFlags;
|
|
FLMUINT uiEncId = 0;
|
|
FLMUINT uiEncFieldLen = 0;
|
|
|
|
if (FOP_IS_STANDARD( pFieldOvhd))
|
|
{
|
|
if (FSTA_LEVEL( pFieldOvhd))
|
|
{
|
|
fState->uiLevel++;
|
|
}
|
|
|
|
uiFieldLen = FSTA_FLD_LEN( pFieldOvhd);
|
|
uiTagNum = FSTA_FLD_NUM( pFieldOvhd);
|
|
pFieldOvhd += FSTA_OVHD;
|
|
}
|
|
else if (FOP_IS_OPEN( pFieldOvhd))
|
|
{
|
|
if (FOPE_LEVEL( pFieldOvhd))
|
|
{
|
|
fState->uiLevel++;
|
|
}
|
|
|
|
ucBaseFlags = (FLMBYTE) (FOP_GET_FLD_FLAGS( pFieldOvhd++));
|
|
uiTagNum = (FLMUINT) * pFieldOvhd++;
|
|
|
|
if (FOP_2BYTE_FLDNUM( ucBaseFlags))
|
|
{
|
|
uiTagNum += ((FLMUINT) * pFieldOvhd++) << 8;
|
|
}
|
|
|
|
uiFieldLen = (FLMUINT) * pFieldOvhd++;
|
|
if (FOP_2BYTE_FLDLEN( ucBaseFlags))
|
|
{
|
|
uiFieldLen += ((FLMUINT) * pFieldOvhd++) << 8;
|
|
}
|
|
}
|
|
else if (FOP_IS_NO_VALUE( pFieldOvhd))
|
|
{
|
|
if (FNOV_LEVEL( pFieldOvhd))
|
|
{
|
|
fState->uiLevel++;
|
|
}
|
|
|
|
ucBaseFlags = (FLMBYTE) (FOP_GET_FLD_FLAGS( pFieldOvhd++));
|
|
uiTagNum = (FLMUINT) * pFieldOvhd++;
|
|
if (FOP_2BYTE_FLDNUM( ucBaseFlags))
|
|
{
|
|
uiTagNum += ((FLMUINT) * pFieldOvhd++) << 8;
|
|
}
|
|
|
|
uiFieldLen = uiFieldType = 0;
|
|
}
|
|
else if (FOP_IS_SET_LEVEL( pFieldOvhd))
|
|
{
|
|
|
|
// SET THE LEVEL Must be continuous with the next field
|
|
|
|
fState->uiLevel -= FSLEV_GET( pFieldOvhd++);
|
|
fState->uiPosInElm = (FLMUINT) (pFieldOvhd - pElement);
|
|
|
|
rc = FSGetFldOverhead( pDb, fState);
|
|
goto Exit;
|
|
}
|
|
else if (FOP_IS_TAGGED( pFieldOvhd))
|
|
{
|
|
bDoesntHaveFieldDef = FALSE;
|
|
|
|
if (FTAG_LEVEL( pFieldOvhd))
|
|
{
|
|
fState->uiLevel++;
|
|
}
|
|
|
|
ucBaseFlags = (FLMBYTE) (FOP_GET_FLD_FLAGS( pFieldOvhd));
|
|
pFieldOvhd++;
|
|
uiFieldType = (FLMUINT) (FTAG_GET_FLD_TYPE( *pFieldOvhd));
|
|
pFieldOvhd++;
|
|
uiTagNum = (FLMUINT) * pFieldOvhd++;
|
|
|
|
if (FOP_2BYTE_FLDNUM( ucBaseFlags))
|
|
{
|
|
uiTagNum += ((FLMUINT) * pFieldOvhd++) << 8;
|
|
}
|
|
|
|
// When storing the unregistered fields we cleared the high bit to
|
|
// save on storage for VER11. The problem is that if a tag that is
|
|
// not in the unregistered range (FLAIM TAGS) cannot be represented.
|
|
// SO, we will XOR the high bit so 0x0111 is stored as 0x8111 and
|
|
// 0x8222 is stored as 0x0222.
|
|
|
|
uiTagNum ^= 0x8000;
|
|
uiFieldLen = (FLMUINT) * pFieldOvhd++;
|
|
if (FOP_2BYTE_FLDLEN( ucBaseFlags))
|
|
{
|
|
uiFieldLen += ((FLMUINT) * pFieldOvhd++) << 8;
|
|
}
|
|
}
|
|
else if (FOP_IS_RECORD_INFO( pFieldOvhd))
|
|
{
|
|
bDoesntHaveFieldDef = FALSE;
|
|
ucBaseFlags = *pFieldOvhd++;
|
|
uiFieldLen = *pFieldOvhd++;
|
|
|
|
if (FOP_2BYTE_FLDLEN( ucBaseFlags))
|
|
{
|
|
uiFieldLen += ((FLMUINT) * pFieldOvhd++) << 8;
|
|
}
|
|
|
|
uiTagNum = 0;
|
|
}
|
|
else if (FOP_IS_ENCRYPTED( pFieldOvhd))
|
|
{
|
|
FLMBOOL bTagSz;
|
|
FLMBOOL bLenSz;
|
|
FLMBOOL bENumSz;
|
|
FLMBOOL bELenSz;
|
|
|
|
if (pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_60)
|
|
{
|
|
rc = RC_SET( FERR_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
bDoesntHaveFieldDef = FALSE;
|
|
|
|
if (FENC_LEVEL( pFieldOvhd))
|
|
{
|
|
fState->uiLevel++;
|
|
}
|
|
|
|
uiFieldType = (FLMUINT) (FENC_FLD_TYPE( pFieldOvhd));
|
|
bTagSz = FENC_TAG_SZ( pFieldOvhd);
|
|
bLenSz = FENC_LEN_SZ( pFieldOvhd);
|
|
bENumSz = FENC_ETAG_SZ( pFieldOvhd);
|
|
bELenSz = FENC_ELEN_SZ( pFieldOvhd);
|
|
|
|
pFieldOvhd += 2;
|
|
|
|
uiTagNum = (FLMUINT) * pFieldOvhd++;
|
|
if (bTagSz)
|
|
{
|
|
uiTagNum += ((FLMUINT) * pFieldOvhd++) << 8;
|
|
}
|
|
|
|
uiFieldLen = (FLMUINT) * pFieldOvhd++;
|
|
if (bLenSz)
|
|
{
|
|
uiFieldLen += ((FLMUINT) * pFieldOvhd++) << 8;
|
|
}
|
|
|
|
uiEncId = (FLMUINT) * pFieldOvhd++;
|
|
if (bENumSz)
|
|
{
|
|
uiEncId += ((FLMUINT) * pFieldOvhd++) << 8;
|
|
}
|
|
|
|
uiEncFieldLen = (FLMUINT) * pFieldOvhd++;
|
|
if (bELenSz)
|
|
{
|
|
uiEncFieldLen += ((FLMUINT) * pFieldOvhd++) << 8;
|
|
}
|
|
}
|
|
else if (FOP_IS_LARGE( pFieldOvhd))
|
|
{
|
|
if (pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_61)
|
|
{
|
|
rc = RC_SET( FERR_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
bDoesntHaveFieldDef = FALSE;
|
|
pTmp = pFieldOvhd;
|
|
|
|
if (FLARGE_LEVEL( pFieldOvhd))
|
|
{
|
|
fState->uiLevel++;
|
|
}
|
|
|
|
pTmp++;
|
|
|
|
uiFieldType = FLARGE_FLD_TYPE( pFieldOvhd);
|
|
pTmp++;
|
|
|
|
uiTagNum = FLARGE_TAG_NUM( pFieldOvhd);
|
|
pTmp += 2;
|
|
|
|
if ((uiFieldLen = FLARGE_DATA_LEN( pFieldOvhd)) <= 0x0000FFFF)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( FERR_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
pTmp += 4;
|
|
|
|
if (FLARGE_ENCRYPTED( pFieldOvhd))
|
|
{
|
|
uiEncId = FLARGE_ETAG_NUM( pFieldOvhd);
|
|
pTmp += 2;
|
|
|
|
uiEncFieldLen = FLARGE_EDATA_LEN( pFieldOvhd);
|
|
pTmp += 4;
|
|
}
|
|
|
|
pFieldOvhd = pTmp;
|
|
}
|
|
else
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( FERR_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
if (bDoesntHaveFieldDef)
|
|
{
|
|
|
|
// Get the field's storage type.
|
|
|
|
if (RC_BAD( fdictGetField( pDb->pDict, uiTagNum,
|
|
&uiFieldType, NULL, NULL)))
|
|
{
|
|
rc = RC_SET( FERR_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Set the fState return values
|
|
|
|
fState->uiFieldType = uiFieldType;
|
|
fState->uiFieldLen = uiFieldLen;
|
|
fState->uiPosInElm = (FLMUINT) (pFieldOvhd - pElement);
|
|
fState->uiTagNum = uiTagNum;
|
|
fState->uiEncId = uiEncId;
|
|
fState->uiEncFieldLen = uiEncFieldLen;
|
|
|
|
Exit:
|
|
|
|
return (rc);
|
|
}
|