git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@482 0109f412-320b-0410-ab79-c3e0c5ffbbe6
1002 lines
20 KiB
C++
1002 lines
20 KiB
C++
//------------------------------------------------------------------------------
|
|
// Desc: Routines that do conversions between internal number and numeric
|
|
// key format to platform number types.
|
|
//
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 2002-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$
|
|
//------------------------------------------------------------------------------
|
|
|
|
#define DEFINE_NUMBER_MAXIMUMS
|
|
#include "flaimsys.h"
|
|
|
|
/****************************************************************************
|
|
Desc: Converts a UINT to its storage value
|
|
*****************************************************************************/
|
|
RCODE FlmUINT2Storage(
|
|
FLMUINT uiNum,
|
|
FLMUINT * puiBufLen, // In (buffer size) / Out (bytes used)
|
|
FLMBYTE * pucBuf)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
|
|
if( RC_BAD( rc = flmNumber64ToStorage( uiNum, puiBufLen,
|
|
pucBuf, FALSE, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Converts an INT to its storage value
|
|
*****************************************************************************/
|
|
RCODE FlmINT2Storage(
|
|
FLMINT iNum,
|
|
FLMUINT * puiBufLen, // In (buffer size) / Out (bytes used)
|
|
FLMBYTE * pucBuf)
|
|
{
|
|
FLMBOOL bNeg = FALSE;
|
|
RCODE rc = NE_SFLM_OK;
|
|
|
|
if( iNum < 0)
|
|
{
|
|
iNum = -iNum;
|
|
bNeg = TRUE;
|
|
}
|
|
|
|
if( RC_BAD( rc = flmNumber64ToStorage( (FLMUINT64)iNum,
|
|
puiBufLen, pucBuf, bNeg, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Converts a number to its storage or collation format
|
|
Notes: Changes to this code must also be made to flmUINT32ToStorage
|
|
*****************************************************************************/
|
|
RCODE flmNumber64ToStorage(
|
|
FLMUINT64 ui64Num,
|
|
FLMUINT * puiBufLen,
|
|
FLMBYTE * pucBuf,
|
|
FLMBOOL bNegative,
|
|
FLMBOOL bCollation)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMUINT uiByteCount = 0;
|
|
FLMUINT32 ui32Low = (FLMUINT32)ui64Num;
|
|
FLMUINT32 ui32High = (FLMUINT32)(ui64Num >> 32);
|
|
|
|
if( *puiBufLen < FLM_MAX_NUM_BUF_SIZE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
// Negative flag should not be set if the number is 0
|
|
|
|
if( !ui64Num && bNegative)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
// Build the storage format, either for an index key (if bCollation
|
|
// is TRUE) or for a data element.
|
|
|
|
if( !bCollation)
|
|
{
|
|
// Build the data storage representation of the number
|
|
// Numbers are stored in a little-endian format
|
|
|
|
do
|
|
{
|
|
*pucBuf++ = (FLMBYTE)ui32Low;
|
|
ui32Low >>= 8;
|
|
uiByteCount++;
|
|
} while (ui32Low);
|
|
|
|
if( ui32High)
|
|
{
|
|
for( ; uiByteCount < 4; uiByteCount++)
|
|
{
|
|
*pucBuf++ = 0;
|
|
}
|
|
|
|
for( ; ui32High; uiByteCount++)
|
|
{
|
|
*pucBuf++ = (FLMBYTE)ui32High;
|
|
ui32High >>= 8;
|
|
}
|
|
}
|
|
|
|
// If a number is negative, the high bit of the right-most
|
|
// byte needs to be set. If the value of the number is such
|
|
// that its positive representation already has the high-bit
|
|
// set, we need to store an additional sign byte.
|
|
|
|
if( !bNegative)
|
|
{
|
|
if( *(pucBuf - 1) & 0x80)
|
|
{
|
|
*pucBuf++ = 0;
|
|
uiByteCount++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( (*(pucBuf - 1) & 0x80) == 0)
|
|
{
|
|
*(pucBuf - 1) |= 0x80;
|
|
}
|
|
else
|
|
{
|
|
*pucBuf++ = 0x80;
|
|
uiByteCount++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMBYTE * pucStart = pucBuf++;
|
|
|
|
if( ui32High)
|
|
{
|
|
if( ui32High & 0xFF000000)
|
|
{
|
|
*pucBuf++ = (FLMBYTE)(ui32High >> 24);
|
|
*pucBuf++ = (FLMBYTE)(ui32High >> 16);
|
|
*pucBuf++ = (FLMBYTE)(ui32High >> 8);
|
|
*pucBuf++ = (FLMBYTE)ui32High;
|
|
uiByteCount += 4;
|
|
}
|
|
else if( ui32High & 0x00FF0000)
|
|
{
|
|
*pucBuf++ = (FLMBYTE)(ui32High >> 16);
|
|
*pucBuf++ = (FLMBYTE)(ui32High >> 8);
|
|
*pucBuf++ = (FLMBYTE)ui32High;
|
|
uiByteCount += 3;
|
|
}
|
|
else if( ui32High & 0x0000FF00)
|
|
{
|
|
*pucBuf++ = (FLMBYTE)(ui32High >> 8);
|
|
*pucBuf++ = (FLMBYTE)ui32High;
|
|
uiByteCount += 2;
|
|
}
|
|
else if( ui32High)
|
|
{
|
|
*pucBuf++ = (FLMBYTE)ui32High;
|
|
uiByteCount++;
|
|
}
|
|
}
|
|
|
|
if( ui32Low)
|
|
{
|
|
if( ui32Low & 0xFF000000)
|
|
{
|
|
*pucBuf++ = (FLMBYTE)(ui32Low >> 24);
|
|
*pucBuf++ = (FLMBYTE)(ui32Low >> 16);
|
|
*pucBuf++ = (FLMBYTE)(ui32Low >> 8);
|
|
*pucBuf++ = (FLMBYTE)ui32Low;
|
|
uiByteCount += 4;
|
|
}
|
|
else if( ui32Low & 0x00FF0000)
|
|
{
|
|
*pucBuf++ = (FLMBYTE)(ui32Low >> 16);
|
|
*pucBuf++ = (FLMBYTE)(ui32Low >> 8);
|
|
*pucBuf++ = (FLMBYTE)ui32Low;
|
|
uiByteCount += 3;
|
|
}
|
|
else if( ui32Low & 0x0000FF00)
|
|
{
|
|
*pucBuf++ = (FLMBYTE)(ui32Low >> 8);
|
|
*pucBuf++ = (FLMBYTE)ui32Low;
|
|
uiByteCount += 2;
|
|
}
|
|
else if( ui32Low)
|
|
{
|
|
*pucBuf++ = (FLMBYTE)ui32Low;
|
|
uiByteCount++;
|
|
}
|
|
}
|
|
else if( !ui32High)
|
|
{
|
|
*pucBuf++ = 0;
|
|
uiByteCount++;
|
|
}
|
|
|
|
if( !bNegative)
|
|
{
|
|
// Positive numbers must collate after negative numbers,
|
|
// so all positive numbers will start with a byte
|
|
// in the range of 0xC8 - 0xCF.
|
|
|
|
*pucStart = (FLMBYTE)(0xC8 + (uiByteCount - 1));
|
|
uiByteCount++;
|
|
}
|
|
else
|
|
{
|
|
FLMBYTE * pucTmp = pucStart + 1;
|
|
|
|
while( pucTmp < pucBuf)
|
|
{
|
|
*pucTmp = ~(*pucTmp);
|
|
pucTmp++;
|
|
}
|
|
|
|
// Negative numbers must collate before positive numbers,
|
|
// so all negative numbers will start with a byte
|
|
// in the range of 0xC0 - 0xC7.
|
|
|
|
*pucStart = (FLMBYTE)(0xC8 - uiByteCount);
|
|
uiByteCount++;
|
|
}
|
|
}
|
|
|
|
// Set the number of bytes in the buffer before returning.
|
|
|
|
*puiBufLen = uiByteCount;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Converts a storage value back into a number
|
|
Notes: Changes to this code must also be made to flmStorage2Number64
|
|
*****************************************************************************/
|
|
RCODE flmStorage2Number(
|
|
eDataType eDataTyp,
|
|
FLMUINT uiBufLen,
|
|
const FLMBYTE * pucBuf,
|
|
FLMUINT * puiNum,
|
|
FLMINT * piNum)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMUINT uiLoop;
|
|
FLMUINT uiNum = 0;
|
|
FLMBOOL bNeg = FALSE;
|
|
|
|
if( !uiBufLen)
|
|
{
|
|
if( puiNum)
|
|
{
|
|
*puiNum = 0;
|
|
}
|
|
else
|
|
{
|
|
*piNum = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if( !pucBuf)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NULL_SRC);
|
|
goto Exit;
|
|
}
|
|
|
|
switch( eDataTyp)
|
|
{
|
|
case SFLM_NUMBER_TYPE :
|
|
{
|
|
// Make sure the number buffer does not exceed the
|
|
// max length. If there is an extra byte for the
|
|
// sign (byte 9) make sure it has a value of either
|
|
// 0x80 or 0 (by masking of the high bit).
|
|
|
|
if( uiBufLen > FLM_MAX_NUM_BUF_SIZE ||
|
|
(uiBufLen == FLM_MAX_NUM_BUF_SIZE &&
|
|
(pucBuf[ uiBufLen - 1] & 0x7F) != 0))
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
// Look at the high bit of the most-significant byte
|
|
// to determine if the number is signed
|
|
|
|
if( pucBuf[ uiBufLen - 1] & 0x80)
|
|
{
|
|
if( puiNum)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_UNDERFLOW);
|
|
goto Exit;
|
|
}
|
|
bNeg = TRUE;
|
|
}
|
|
|
|
uiNum = pucBuf[ uiBufLen - 1] & 0x7F;
|
|
uiBufLen--;
|
|
|
|
for( uiLoop = 1; uiLoop <= uiBufLen; uiLoop++)
|
|
{
|
|
if( gv_b32BitPlatform && (uiNum & 0xFF000000))
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
uiNum = (uiNum << 8) + pucBuf[ uiBufLen - uiLoop];
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SFLM_STRING_TYPE:
|
|
{
|
|
FLMBYTE ucNumBuf[ 64];
|
|
FLMUINT uiNumBufLen = sizeof( ucNumBuf);
|
|
FLMBYTE * pucTmp;
|
|
|
|
if( RC_BAD( rc = flmStorage2UTF8( SFLM_STRING_TYPE, uiBufLen, pucBuf,
|
|
&uiNumBufLen, ucNumBuf)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pucTmp = &ucNumBuf[ 0];
|
|
if( *pucTmp == ASCII_DASH)
|
|
{
|
|
if( puiNum)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_UNDERFLOW);
|
|
goto Exit;
|
|
}
|
|
bNeg = TRUE;
|
|
pucTmp++;
|
|
}
|
|
|
|
while( *pucTmp)
|
|
{
|
|
if( *pucTmp < ASCII_ZERO || *pucTmp > ASCII_NINE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( uiNum > (~(FLMUINT)0) / 10)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
uiNum *= (FLMUINT)10;
|
|
|
|
if( uiNum > (~(FLMUINT)0) - (FLMUINT)(*pucTmp - ASCII_ZERO))
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
uiNum += (FLMUINT)(*pucTmp - ASCII_ZERO);
|
|
pucTmp++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default :
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( puiNum)
|
|
{
|
|
if( bNeg)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_UNDERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
*puiNum = uiNum;
|
|
}
|
|
else
|
|
{
|
|
flmAssert( piNum);
|
|
|
|
if( bNeg)
|
|
{
|
|
if( uiNum > gv_uiMaxSignedIntVal + 1)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_UNDERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
*piNum = -(FLMINT)uiNum;
|
|
}
|
|
else
|
|
{
|
|
if( uiNum > gv_uiMaxSignedIntVal)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
*piNum = (FLMINT)uiNum;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Converts a storage value back into a number
|
|
Notes: Changes to this code must also be made to flmStorage2Number
|
|
*****************************************************************************/
|
|
RCODE flmStorage2Number64(
|
|
FLMUINT eDataTyp,
|
|
FLMUINT uiBufLen,
|
|
const FLMBYTE * pucBuf,
|
|
FLMUINT64 * pui64Num,
|
|
FLMINT64 * pi64Num)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMUINT uiLoop;
|
|
FLMUINT64 ui64Num = 0;
|
|
FLMBOOL bNeg = FALSE;
|
|
|
|
if( !uiBufLen)
|
|
{
|
|
if( pui64Num)
|
|
{
|
|
*pui64Num = 0;
|
|
}
|
|
else
|
|
{
|
|
*pi64Num = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if( !pucBuf)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NULL_SRC);
|
|
goto Exit;
|
|
}
|
|
|
|
switch( eDataTyp)
|
|
{
|
|
case SFLM_NUMBER_TYPE :
|
|
{
|
|
// Make sure the number buffer does not exceed the
|
|
// max length. If there is an extra byte for the
|
|
// sign (byte 9) make sure it has a value of either
|
|
// 0x80 or 0 (by masking of the high bit).
|
|
|
|
if( uiBufLen > FLM_MAX_NUM_BUF_SIZE ||
|
|
(uiBufLen == FLM_MAX_NUM_BUF_SIZE &&
|
|
(pucBuf[ uiBufLen - 1] & 0x7F) != 0))
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
// Look at the high bit of the most-significant byte
|
|
// to determine if the number is signed
|
|
|
|
if( pucBuf[ uiBufLen - 1] & 0x80)
|
|
{
|
|
if( pui64Num)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_UNDERFLOW);
|
|
goto Exit;
|
|
}
|
|
bNeg = TRUE;
|
|
}
|
|
|
|
ui64Num = pucBuf[ uiBufLen - 1] & 0x7F;
|
|
uiBufLen--;
|
|
|
|
for( uiLoop = 1; uiLoop <= uiBufLen; uiLoop++)
|
|
{
|
|
ui64Num = (ui64Num << 8) + pucBuf[ uiBufLen - uiLoop];
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SFLM_STRING_TYPE :
|
|
{
|
|
FLMBYTE ucNumBuf[ 64];
|
|
FLMUINT uiNumBufLen = sizeof( ucNumBuf);
|
|
FLMBYTE * pucTmp;
|
|
|
|
if( RC_BAD( rc = flmStorage2UTF8( SFLM_NUMBER_TYPE, uiBufLen, pucBuf,
|
|
&uiNumBufLen, ucNumBuf)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pucTmp = &ucNumBuf[ 0];
|
|
|
|
if( *pucTmp == ASCII_DASH)
|
|
{
|
|
if( pui64Num)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_UNDERFLOW);
|
|
goto Exit;
|
|
}
|
|
bNeg = TRUE;
|
|
pucTmp++;
|
|
}
|
|
|
|
while( *pucTmp)
|
|
{
|
|
if( *pucTmp < ASCII_ZERO || *pucTmp > ASCII_NINE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( ui64Num > (~(FLMUINT64)0) / 10)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
ui64Num *= (FLMUINT64)10;
|
|
|
|
if( ui64Num > (~(FLMUINT64)0) - (FLMUINT64)(*pucTmp - ASCII_ZERO))
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
ui64Num += (FLMUINT64)(*pucTmp - ASCII_ZERO);
|
|
pucTmp++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default :
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( pui64Num)
|
|
{
|
|
*pui64Num = ui64Num;
|
|
}
|
|
else
|
|
{
|
|
flmAssert( pi64Num);
|
|
|
|
if( bNeg)
|
|
{
|
|
if( ui64Num > gv_ui64MaxSignedIntVal + 1)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_UNDERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
*pi64Num = -(FLMINT64)ui64Num;
|
|
}
|
|
else
|
|
{
|
|
if( ui64Num > gv_ui64MaxSignedIntVal)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
*pi64Num = (FLMINT64)ui64Num;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Converts a numeric storage value into a collation value
|
|
*****************************************************************************/
|
|
RCODE flmStorageNum2CollationNum(
|
|
const FLMBYTE * pucStorageBuf,
|
|
FLMUINT uiStorageLen,
|
|
FLMBYTE * pucCollBuf,
|
|
FLMUINT * puiCollLen)
|
|
{
|
|
FLMUINT uiLoop;
|
|
FLMUINT uiOffset;
|
|
FLMUINT uiMaxLen = *puiCollLen;
|
|
FLMBYTE ucVal;
|
|
FLMBOOL bNegative = FALSE;
|
|
RCODE rc = NE_SFLM_OK;
|
|
|
|
if( !pucStorageBuf || !uiStorageLen)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_INVALID_PARM);
|
|
goto Exit;
|
|
}
|
|
|
|
// Look at the high bit of the most-significant byte
|
|
// to determine if the number is signed
|
|
|
|
if( pucStorageBuf[ uiStorageLen - 1] & 0x80)
|
|
{
|
|
bNegative = TRUE;
|
|
}
|
|
|
|
uiOffset = 1;
|
|
if( (ucVal = pucStorageBuf[ uiStorageLen - 1] & 0x7F) != 0 ||
|
|
uiStorageLen == 1) // Handle the special case of zero
|
|
{
|
|
if( bNegative)
|
|
{
|
|
ucVal = ~ucVal;
|
|
}
|
|
|
|
if( uiOffset >= uiMaxLen)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
pucCollBuf[ uiOffset++] = ucVal;
|
|
}
|
|
uiStorageLen--;
|
|
|
|
// Check for overflow
|
|
|
|
if( uiOffset + uiStorageLen >= uiMaxLen)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
// Map the little-endian storage format to the big-endian
|
|
// collation format
|
|
|
|
if( !bNegative)
|
|
{
|
|
for( uiLoop = 1; uiLoop <= uiStorageLen; uiLoop++)
|
|
{
|
|
pucCollBuf[ uiOffset++] = pucStorageBuf[ uiStorageLen - uiLoop];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( uiLoop = 1; uiLoop <= uiStorageLen; uiLoop++)
|
|
{
|
|
pucCollBuf[ uiOffset++] = ~pucStorageBuf[ uiStorageLen - uiLoop];
|
|
}
|
|
}
|
|
|
|
flmAssert( uiOffset >= 2);
|
|
|
|
// Store the numeric collation marker and byte count
|
|
|
|
if( !bNegative)
|
|
{
|
|
// Positive numbers must collate after negative numbers,
|
|
// so all positive numbers will start with a byte
|
|
// in the range of 0xC8 - 0xCF.
|
|
|
|
pucCollBuf[ 0] = (FLMBYTE)(0xC8 + (uiOffset - 2));
|
|
}
|
|
else
|
|
{
|
|
// Negative numbers must collate before positive numbers,
|
|
// so all negative numbers will start with a byte
|
|
// in the range of 0xC0 - 0xC7.
|
|
|
|
pucCollBuf[ 0] = (FLMBYTE)(0xC8 - (uiOffset - 1));
|
|
}
|
|
|
|
// Set the key length
|
|
|
|
*puiCollLen = uiOffset;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Converts a numeric collation value into a storage value
|
|
*****************************************************************************/
|
|
RCODE flmCollationNum2StorageNum(
|
|
const FLMBYTE * pucCollBuf,
|
|
FLMUINT uiCollLen,
|
|
FLMBYTE * pucStorageBuf,
|
|
FLMUINT * puiStorageLen)
|
|
{
|
|
FLMUINT uiLoop;
|
|
FLMUINT uiOffset;
|
|
FLMUINT uiMaxOffset = *puiStorageLen;
|
|
FLMUINT uiNumKeyBytes;
|
|
FLMBOOL bNegative = FALSE;
|
|
RCODE rc = NE_SFLM_OK;
|
|
|
|
if( !pucCollBuf || !uiCollLen)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_INVALID_PARM);
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure this looks like a valid numeric key piece
|
|
|
|
if( (pucCollBuf[ 0] & 0xC0) != 0xC0)
|
|
{
|
|
rc = RC_SET( NE_SFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
// Get the byte count
|
|
|
|
if( (uiNumKeyBytes = (FLMUINT)(pucCollBuf[ 0] & 0x0F)) >= 8)
|
|
{
|
|
uiNumKeyBytes -= 7;
|
|
}
|
|
else
|
|
{
|
|
uiNumKeyBytes = 8 - uiNumKeyBytes;
|
|
bNegative = TRUE;
|
|
}
|
|
pucCollBuf++;
|
|
uiCollLen--;
|
|
|
|
// Make sure the buffer has at least the number of bytes
|
|
// we need
|
|
|
|
if( uiCollLen != uiNumKeyBytes)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiNumKeyBytes >= uiMaxOffset)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
// Translate the collation value into a numeric value
|
|
|
|
if( !bNegative)
|
|
{
|
|
for( uiLoop = 0; uiLoop < uiNumKeyBytes; uiLoop++)
|
|
{
|
|
pucStorageBuf[ uiNumKeyBytes - uiLoop - 1] = pucCollBuf[ uiLoop];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( uiLoop = 0; uiLoop < uiNumKeyBytes; uiLoop++)
|
|
{
|
|
pucStorageBuf[ uiNumKeyBytes - uiLoop - 1] = ~pucCollBuf[ uiLoop];
|
|
}
|
|
}
|
|
|
|
uiOffset = uiNumKeyBytes;
|
|
|
|
// If a number is negative, the high bit of the right-most
|
|
// byte needs to be set. If the value of the number is such
|
|
// that its positive representation already has the high-bit
|
|
// set, we need to store an additional sign byte.
|
|
|
|
if( !bNegative)
|
|
{
|
|
if( pucStorageBuf[ uiOffset - 1] & 0x80)
|
|
{
|
|
if( uiOffset >= uiMaxOffset)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
pucStorageBuf[ uiOffset++] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( (pucStorageBuf[ uiOffset - 1] & 0x80) == 0)
|
|
{
|
|
pucStorageBuf[ uiOffset - 1] |= 0x80;
|
|
}
|
|
else
|
|
{
|
|
if( uiOffset >= uiMaxOffset)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
pucStorageBuf[ uiOffset++] = 0x80;
|
|
}
|
|
}
|
|
|
|
// Set the storage length
|
|
|
|
*puiStorageLen = uiOffset;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Converts a collation value (numeric only) to a number
|
|
*****************************************************************************/
|
|
RCODE flmCollation2Number(
|
|
FLMUINT uiBufLen,
|
|
const FLMBYTE * pucBuf,
|
|
FLMUINT64 * pui64Num,
|
|
FLMBOOL * pbNeg,
|
|
FLMUINT * puiBytesProcessed)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMUINT uiLoop;
|
|
FLMUINT uiNumBytes;
|
|
FLMUINT64 ui64Num;
|
|
FLMBOOL bNeg = FALSE;
|
|
|
|
*pui64Num = 0;
|
|
|
|
if( !uiBufLen)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !pucBuf)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_NULL_SRC);
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure this looks like a valid numeric key piece
|
|
|
|
if( (pucBuf[ 0] & 0xC0) != 0xC0)
|
|
{
|
|
rc = RC_SET( NE_SFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
// Get the byte count
|
|
|
|
if( (uiNumBytes = (FLMUINT)(pucBuf[ 0] & 0x0F)) >= 8)
|
|
{
|
|
uiNumBytes -= 7;
|
|
}
|
|
else
|
|
{
|
|
uiNumBytes = 8 - uiNumBytes;
|
|
bNeg = TRUE;
|
|
}
|
|
pucBuf++;
|
|
uiBufLen--;
|
|
|
|
// Make sure the buffer has at least the number of bytes
|
|
// we need
|
|
|
|
if( uiBufLen < uiNumBytes)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
// Reconstruct the number
|
|
|
|
ui64Num = 0;
|
|
if( !bNeg)
|
|
{
|
|
for( uiLoop = 0; uiLoop < uiNumBytes; uiLoop++)
|
|
{
|
|
ui64Num += (((FLMUINT64)pucBuf[ uiLoop]) <<
|
|
(8 * ((uiNumBytes - uiLoop) - 1)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( uiLoop = 0; uiLoop < uiNumBytes; uiLoop++)
|
|
{
|
|
ui64Num += (((FLMUINT64)((FLMBYTE)~pucBuf[ uiLoop])) <<
|
|
(8 * ((uiNumBytes - uiLoop) - 1)));
|
|
}
|
|
}
|
|
|
|
*pui64Num = ui64Num;
|
|
|
|
if( puiBytesProcessed)
|
|
{
|
|
*puiBytesProcessed = uiNumBytes + 1;
|
|
}
|
|
|
|
if( pbNeg)
|
|
{
|
|
*pbNeg = bNeg;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE flmStorageNumberToNumber(
|
|
const FLMBYTE * pucNumBuf,
|
|
FLMUINT uiNumBufLen,
|
|
FLMUINT64 * pui64Number,
|
|
FLMBOOL * pbNeg)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMUINT uiLoop;
|
|
FLMUINT64 ui64Num = 0;
|
|
FLMBOOL bNeg = FALSE;
|
|
|
|
if( !uiNumBufLen)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the number buffer does not exceed the
|
|
// max length. If there is an extra byte for the
|
|
// sign (byte 9) make sure it has a value of either
|
|
// 0x80 or 0 (by masking of the high bit).
|
|
|
|
if( uiNumBufLen > FLM_MAX_NUM_BUF_SIZE ||
|
|
(uiNumBufLen == FLM_MAX_NUM_BUF_SIZE &&
|
|
(pucNumBuf[ uiNumBufLen - 1] & 0x7F) != 0))
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
// Look at the high bit of the most-significant byte
|
|
// to determine if the number is signed
|
|
|
|
if( pucNumBuf[ uiNumBufLen - 1] & 0x80)
|
|
{
|
|
bNeg = TRUE;
|
|
}
|
|
|
|
ui64Num = pucNumBuf[ uiNumBufLen - 1] & 0x7F;
|
|
uiNumBufLen--;
|
|
|
|
for( uiLoop = 1; uiLoop <= uiNumBufLen; uiLoop++)
|
|
{
|
|
ui64Num = (ui64Num << 8) + pucNumBuf[ uiNumBufLen - uiLoop];
|
|
}
|
|
|
|
Exit:
|
|
|
|
*pui64Number = ui64Num;
|
|
*pbNeg = bNeg;
|
|
|
|
return( rc);
|
|
}
|