Files
mars-flaim/flaim/src/fsnext.cpp

478 lines
10 KiB
C++

//-------------------------------------------------------------------------
// Desc: Traverse to next element in a b-tree.
// Tabs: 3
//
// Copyright (c) 1991-2001,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: fsnext.cpp 12321 2006-01-19 15:55:00 -0700 (Thu, 19 Jan 2006) dsanders $
//-------------------------------------------------------------------------
#include "flaimsys.h"
// The SENLenArray[] is used to find the length of an unsigned SEN value.
FLMBYTE SENLenArray[] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 5, 0 };
/***************************************************************************
Desc: Go to the next data record given a stack.
***************************************************************************/
RCODE FSNextRecord(
FDB * pDb,
LFILE * pLFile,
BTSK * pStack)
{
RCODE rc = FERR_OK;
FLMBYTE * pCurElm;
pStack->uiFlags = NO_STACK;
pStack->uiKeyBufSize = DIN_KEY_SIZ;
pCurElm = CURRENT_ELM( pStack);
// Scan over the current record till 'does continue' flag NOT set
while (BBE_NOT_LAST( pCurElm))
{
// First go to the next element - rc may return FERR_BT_END_OF_DATA
if (RC_BAD( rc = FSBtNextElm( pDb, pLFile, pStack)))
{
if (rc == FERR_BT_END_OF_DATA)
{
rc = RC_SET( FERR_BTREE_ERROR);
}
goto Exit;
}
pCurElm = CURRENT_ELM( pStack);
}
// Now go to the next element.
if (RC_BAD( rc = FSBtNextElm( pDb, pLFile, pStack)))
{
if (rc == FERR_BT_END_OF_DATA)
{
rc = RC_SET( FERR_EOF_HIT);
}
goto Exit;
}
Exit:
return (rc);
}
/***************************************************************************
Desc: Go to the next reference given a valid cursor.
***************************************************************************/
RCODE FSRefNext(
FDB * pDb,
LFILE * pLFile,
BTSK * pStack,
DIN_STATE * pState,
FLMUINT * puiDin)
{
RCODE rc = FERR_OK;
FLMBYTE * pCurRef;
FLMBYTE * pCurElm;
FLMUINT uiRefSize;
FLMUINT uiHasDomain;
FLMUINT uiDin = *puiDin;
DIN_STATE savedState;
// Point to the start of the current reference
pCurRef = pCurElm = CURRENT_ELM( pStack);
uiHasDomain = FSGetDomain( &pCurRef, pStack->uiElmOvhd);
uiRefSize = (FLMUINT) (BBE_GET_RL( pCurElm) -
(pCurRef - BBE_REC_PTR( pCurElm)));
if (pState->uiOffset < uiRefSize)
{
DINNextVal( pCurRef, pState);
}
if (pState->uiOffset >= uiRefSize)
{
// Read in the next element if a domain was found else
// FERR_BT_END_OF_DATA
if (!uiHasDomain)
{
// May use the DOES_CONT element flag
return (FERR_BT_END_OF_DATA);
}
if (RC_BAD( rc = FSBtNextElm( pDb, pLFile, pStack)))
{
return (rc);
}
uiDin = FSRefFirst( pStack, pState, &uiHasDomain);
}
else
{
// Don't move the pState, stay put and get the next DIN value
savedState.uiOffset = pState->uiOffset;
savedState.uiOnes = pState->uiOnes;
uiDin -= DINNextVal( pCurRef, &savedState);
}
*puiDin = uiDin;
return (FERR_OK);
}
/***************************************************************************
Desc: Search for and position to the current (or next) reference
***************************************************************************/
RCODE FSRefSearch(
BTSK * pStack,
DIN_STATE * pState,
FLMUINT * puiDin)
{
FLMBYTE * pCurRef;
FLMBYTE * pCurElm;
FLMUINT uiRefSize;
FLMUINT uiLastOffset;
FLMUINT uiDelta;
FLMUINT uiTargetDin = *puiDin;
FLMUINT uiDin;
FLMUINT uiOneRuns;
DIN_STATE tempState;
FLMBYTE byValue;
// Point to the start of the current reference
pCurRef = pCurElm = CURRENT_ELM( pStack);
(void) FSGetDomain( &pCurRef, pStack->uiElmOvhd);
uiRefSize = (FLMUINT) (BBE_GET_RL( pCurElm) -
(pCurRef - BBE_REC_PTR( pCurElm)));
RESET_DINSTATE_p( pState);
RESET_DINSTATE( tempState);
uiLastOffset = tempState.uiOffset;
uiDin = DINNextVal( pCurRef, &tempState);
if (uiDin > uiTargetDin)
{
while (tempState.uiOffset < uiRefSize)
{
// Get the current byte to see what kind of item it is
byValue = (FLMBYTE) pCurRef[uiLastOffset = tempState.uiOffset];
if (DIN_IS_REAL_ONE_RUN( byValue))
{
uiOneRuns = DINOneRunVal( pCurRef, &tempState);
// Check if one run is includes the target din
if ((uiDin - uiOneRuns) <= uiTargetDin)
{
uiOneRuns = (uiDin - uiTargetDin) - 1;
pState->uiOffset = uiLastOffset;
pState->uiOnes = uiOneRuns;
uiDin = uiTargetDin;
break;
}
uiDin -= uiOneRuns;
}
else
{
uiDelta = DINNextVal( pCurRef, &tempState);
// Check if next din value is equal or less than target din
uiDin -= uiDelta;
if (uiDin <= uiTargetDin)
{
pState->uiOffset = uiLastOffset;
break;
}
}
}
pState->uiOffset = uiLastOffset;
}
*puiDin = uiDin;
return ((uiDin == uiTargetDin) ? FERR_OK : RC_SET( FERR_FAILURE));
}
/***************************************************************************
Desc: Get the next DIN value from the DIN set.
***************************************************************************/
FLMUINT DINNextVal(
FLMBYTE * puiDin,
DIN_STATE * pState)
{
FLMBYTE * pOneRun;
FLMBYTE * pCurDin;
FLMUINT uiTemp = 0;
FLMUINT uiOneRun;
FLMUINT uiStateOneRuns;
pCurDin = puiDin + pState->uiOffset;
switch (SENValLen( pCurDin))
{
case 0:
{
uiOneRun = 0;
pOneRun = pCurDin + 1;
if (*pCurDin < DIN_ONE_RUN_HV)
{
uiOneRun = (*pCurDin - DIN_ONE_RUN_LV) + 2;
}
else if (*pCurDin == DIN_ONE_RUN_HV)
{
uiOneRun = SENNextVal( &pOneRun);
}
else
{
// Invalid code found
pCurDin++;
uiTemp = 0;
break;
}
// Handle the position of the one run
uiStateOneRuns = pState->uiOnes;
// return 1 unless on last one run value
uiTemp = 1;
uiStateOneRuns++;
if (uiStateOneRuns >= uiOneRun)
{
pCurDin = pOneRun; // Set to after the one runs
uiStateOneRuns = 0; // This sets state of ones to zero
}
pState->uiOnes = uiStateOneRuns;
break;
}
case 1:
{
uiTemp = *pCurDin++;
break;
}
case 2:
{
uiTemp = ((FLMUINT) (SEN_2B_MASK &*pCurDin++)) << 8;
goto DINNV_1_byte;
}
case 3:
{
uiTemp = ((FLMUINT) (SEN_3B_MASK & (*pCurDin++))) << 16;
goto DINNV_2_bytes;
}
case 4:
{
uiTemp = ((FLMUINT) (SEN_4B_MASK & (*pCurDin++))) << 24;
goto DINNV_3_bytes;
}
case 5:
{
pCurDin++;
uiTemp = ((FLMUINT) * pCurDin++) << 24;
DINNV_3_bytes:
uiTemp += ((FLMUINT) * pCurDin++) << 16;
DINNV_2_bytes:
uiTemp += ((FLMUINT) * pCurDin++) << 8;
DINNV_1_byte:
uiTemp += *pCurDin++;
break;
}
}
// Set the offset to point to the next reference
pState->uiOffset = (FLMUINT) (pCurDin - puiDin);
return (uiTemp);
}
/***************************************************************************
Desc: Get the next one run value and update the state information
***************************************************************************/
FLMUINT DINOneRunVal(
FLMBYTE * puiDin,
DIN_STATE * pState)
{
FLMBYTE * pOneRun;
FLMBYTE * pCurDin;
FLMUINT uiOneRun;
pCurDin = puiDin + pState->uiOffset;
if (*pCurDin == 1)
{
pState->uiOffset++;
uiOneRun = 1;
}
else
{
uiOneRun = 0;
pOneRun = pCurDin + 1;
if (*pCurDin < DIN_ONE_RUN_HV)
{
uiOneRun = (*pCurDin - DIN_ONE_RUN_LV) + 2;
}
else if (*pCurDin == DIN_ONE_RUN_HV)
{
uiOneRun = SENNextVal( &pOneRun);
}
else
{
// Invald code found
uiOneRun = 0;
}
pState->uiOffset = (FLMUINT) (pOneRun - puiDin);
}
return (uiOneRun);
}
/***************************************************************************
Desc: Return the next SEN value.
***************************************************************************/
FLMUINT SENNextVal(
FLMBYTE ** pSenRV)
{
FLMUINT uiTemp;
FLMBYTE * pSen = *pSenRV;
switch (SENValLen( pSen))
{
case 1:
{
uiTemp = *pSen;
break;
}
case 2:
{
uiTemp = ((FLMUINT) (SEN_2B_MASK &*pSen++)) << 8;
uiTemp += *pSen;
break;
}
case 3:
{
uiTemp = ((FLMUINT) (SEN_3B_MASK & (*pSen++))) << 16;
goto SENNV_2_bytes;
}
case 4:
{
uiTemp = ((FLMUINT) (SEN_4B_MASK & (*pSen++))) << 24;
goto SENNV_3_bytes;
}
case 5:
{
pSen++;
uiTemp = ((FLMUINT) * pSen++) << 24;
SENNV_3_bytes:
uiTemp += ((FLMUINT) * pSen++) << 16;
SENNV_2_bytes:
uiTemp += ((FLMUINT) * pSen++) << 8;
uiTemp += *pSen;
break;
}
default:
{
uiTemp = 0;
break;
}
}
*pSenRV = pSen + 1;
return (uiTemp);
}
/***************************************************************************
Desc: Get the domain from a block type and current element pointer
***************************************************************************/
FLMUINT FSGetDomain(
FLMBYTE ** curElmRV,
FLMUINT uiElmOvhd)
{
FLMUINT uiDinDomain = 0;
FLMBYTE * curElm = *curElmRV;
if (uiElmOvhd == BBE_KEY)
{
// Normal leaf block, parse element to see if DOMAIN flag is present
curElm += BBE_REC_OFS( curElm);
// Skip past the update version information
if (*curElm == SEN_DOMAIN)
{
curElm++;
uiDinDomain = SENNextVal( &curElm);
}
}
else
{
if (BNE_IS_DOMAIN( curElm))
{
curElm += BBE_GET_KL( curElm) + uiElmOvhd;
uiDinDomain = ((FLMUINT) * curElm++) << 16;
uiDinDomain |= ((FLMUINT16) * curElm++) << 8;
uiDinDomain |= *curElm++;
}
}
*curElmRV = curElm;
return (uiDinDomain);
}