git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@482 0109f412-320b-0410-ab79-c3e0c5ffbbe6
1076 lines
22 KiB
C++
1076 lines
22 KiB
C++
//------------------------------------------------------------------------------
|
|
// Desc: This file contains the Unicode conversion routines
|
|
//
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1999-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 DEF_FLM_UNI_GLOBALS
|
|
#include "flaimsys.h"
|
|
|
|
/****************************************************************************
|
|
Desc: Encode a string into FLAIM's internal text format
|
|
(SEN-prefixed, null-terminated UTF8). The string is prefixed with
|
|
a SEN that indicates the number of characters, not including the
|
|
terminating NULL.
|
|
|
|
This routine can be called with a NULL input buffer. If it is
|
|
called in this way, the length of the encoded string will be
|
|
returned in *puiBufLength, but no encoding will actually be
|
|
performed.
|
|
****************************************************************************/
|
|
RCODE flmUnicode2Storage(
|
|
const FLMUNICODE * puzStr, // UNICODE string to encode
|
|
FLMUINT uiStrLen, // 0 = Unknown
|
|
FLMBYTE * pucBuf, // Destination buffer
|
|
FLMUINT * puiBufLength, // [IN ] Size of pucBuf,
|
|
// [OUT] Amount of pucBuf used
|
|
FLMUINT * puiCharCount)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBYTE * pucEncPtr;
|
|
const FLMUNICODE * puzPtr = NULL;
|
|
FLMUINT uiMaxLen;
|
|
FLMUINT uiCharsEncoded = 0;
|
|
FLMUINT uiEncodedLen = 0;
|
|
FLMUINT uiTmp;
|
|
FLMUNICODE uChar;
|
|
FLMBYTE ucTmpSen[ 5];
|
|
FLMBYTE * pucTmpSen = &ucTmpSen[ 0];
|
|
|
|
if( !pucBuf)
|
|
{
|
|
uiMaxLen = (~(FLMUINT)0);
|
|
}
|
|
else
|
|
{
|
|
uiMaxLen = *puiBufLength;
|
|
}
|
|
|
|
// If uiStrLen is 0, determine the number of characters.
|
|
|
|
if( !uiStrLen)
|
|
{
|
|
uiStrLen = f_unilen( puzStr);
|
|
}
|
|
else if( puzStr[ uiStrLen] != 0)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_INVALID_PARM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( puiCharCount)
|
|
{
|
|
*puiCharCount = uiStrLen;
|
|
}
|
|
|
|
if( !uiStrLen)
|
|
{
|
|
// Nothing to encode
|
|
|
|
*puiBufLength = 0;
|
|
goto Exit;
|
|
}
|
|
|
|
pucEncPtr = pucBuf;
|
|
|
|
// Encode the number of characters as a SEN. If pucEncPtr is
|
|
// NULL, the caller is only interested in the length of the encoded
|
|
// string, so a temporary buffer is used to call f_encodeSEN.
|
|
|
|
uiTmp = f_encodeSEN( uiStrLen, &pucTmpSen);
|
|
|
|
if( pucEncPtr)
|
|
{
|
|
if( (uiEncodedLen + uiTmp) >= uiMaxLen)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiTmp == 1)
|
|
{
|
|
*pucEncPtr++ = ucTmpSen[ 0];
|
|
}
|
|
else
|
|
{
|
|
f_memcpy( pucEncPtr, &ucTmpSen[ 0], uiTmp);
|
|
pucEncPtr += uiTmp;
|
|
}
|
|
}
|
|
uiEncodedLen += uiTmp;
|
|
|
|
// Encode the string using UTF-8
|
|
|
|
puzPtr = puzStr;
|
|
if( uiStrLen)
|
|
{
|
|
while( (uChar = *puzPtr) != 0)
|
|
{
|
|
if( (uiTmp = uiMaxLen - uiEncodedLen) == 0)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
if( uChar <= 127)
|
|
{
|
|
if( pucEncPtr)
|
|
{
|
|
*pucEncPtr++ = (FLMBYTE)uChar;
|
|
}
|
|
|
|
uiEncodedLen++;
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = f_uni2UTF8( uChar, pucEncPtr, &uiTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pucEncPtr)
|
|
{
|
|
pucEncPtr += uiTmp;
|
|
}
|
|
|
|
uiEncodedLen += uiTmp;
|
|
}
|
|
|
|
puzPtr++;
|
|
uiCharsEncoded++;
|
|
}
|
|
|
|
// Make sure the string length (which may have been provided by
|
|
// the caller) was correct.
|
|
|
|
if( uiCharsEncoded != uiStrLen)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_INVALID_PARM);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Terminate the string with a 0 byte
|
|
|
|
if( (uiMaxLen - uiEncodedLen) < 1)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
if( pucEncPtr)
|
|
{
|
|
*pucEncPtr++ = 0;
|
|
}
|
|
uiEncodedLen++;
|
|
|
|
// Return the length of the encoded string
|
|
|
|
*puiBufLength = uiEncodedLen;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Encode a string into FLAIM's internal text format
|
|
(SEN-prefixed, null-terminated UTF8). The string is prefixed with
|
|
a SEN that indicates the number of characters, not including the
|
|
terminating NULL.
|
|
|
|
This routine can be called with a NULL input buffer. If it is
|
|
called in this way, the length of the encoded string will be
|
|
returned in *puiBufLength, but no encoding will actually be
|
|
performed.
|
|
****************************************************************************/
|
|
RCODE flmNative2Storage(
|
|
char * pszStr, // Native string to encode
|
|
FLMUINT uiStrLen, // 0 = Unknown
|
|
FLMBYTE * pucBuf, // Destination buffer
|
|
FLMUINT * puiBufLength, // [IN ] Size of pucBuf,
|
|
// [OUT] Amount of pucBuf used
|
|
FLMUINT * puiCharCount)
|
|
{
|
|
FLMBYTE * pucEncPtr;
|
|
char * pszPtr = NULL;
|
|
FLMUINT uiMaxLen;
|
|
FLMUINT uiCharsEncoded = 0;
|
|
FLMUINT uiEncodedLen = 0;
|
|
FLMUINT uiTmp;
|
|
FLMBYTE ucTmpSen[ 5];
|
|
FLMBYTE * pucTmpSen = &ucTmpSen[ 0];
|
|
FLMBOOL bDirectCopy = FALSE;
|
|
RCODE rc = NE_SFLM_OK;
|
|
|
|
if( !pucBuf)
|
|
{
|
|
uiMaxLen = (~(FLMUINT)0);
|
|
}
|
|
else
|
|
{
|
|
uiMaxLen = *puiBufLength;
|
|
}
|
|
|
|
// If uiStrLen is 0, determine the number of characters.
|
|
|
|
if( !uiStrLen)
|
|
{
|
|
#ifdef FLM_ASCII_PLATFORM
|
|
bDirectCopy = TRUE;
|
|
for( pszPtr = pszStr; *pszPtr; pszPtr++, uiStrLen++)
|
|
{
|
|
if( (FLMBYTE)*pszPtr > 0x7F)
|
|
{
|
|
bDirectCopy = FALSE;
|
|
}
|
|
}
|
|
#else
|
|
uiStrLen = f_strlen( pszStr);
|
|
#endif
|
|
}
|
|
else if( pszStr[ uiStrLen] != 0)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_INVALID_PARM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( puiCharCount)
|
|
{
|
|
*puiCharCount = uiStrLen;
|
|
}
|
|
|
|
if( !uiStrLen)
|
|
{
|
|
// Nothing to encode
|
|
|
|
*puiBufLength = 0;
|
|
goto Exit;
|
|
}
|
|
|
|
pucEncPtr = pucBuf;
|
|
|
|
// Encode the number of characters as a SEN. If pucEncPtr is
|
|
// NULL, the caller is only interested in the length of the encoded
|
|
// string, so a temporary buffer is used to call f_encodeSEN.
|
|
|
|
uiTmp = f_encodeSEN( uiStrLen, &pucTmpSen);
|
|
if( pucEncPtr)
|
|
{
|
|
if( (uiEncodedLen + uiTmp) >= uiMaxLen)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
f_memcpy( pucEncPtr, &ucTmpSen[ 0], uiTmp);
|
|
pucEncPtr += uiTmp;
|
|
}
|
|
uiEncodedLen += uiTmp;
|
|
|
|
// Encode the string using UTF-8
|
|
|
|
if( uiStrLen)
|
|
{
|
|
if( bDirectCopy)
|
|
{
|
|
// Since all of the characters are ASCII and have
|
|
// values <= 0x7F, the string can be copied directly
|
|
// into the destination buffer buffer.
|
|
|
|
if( uiEncodedLen + uiStrLen >= uiMaxLen)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
if( pucEncPtr)
|
|
{
|
|
f_memcpy( pucEncPtr, pszStr, uiStrLen);
|
|
pucEncPtr += uiStrLen;
|
|
}
|
|
uiEncodedLen += uiStrLen;
|
|
}
|
|
else
|
|
{
|
|
pszPtr = pszStr;
|
|
while( *pszPtr)
|
|
{
|
|
if( (uiTmp = uiMaxLen - uiEncodedLen) == 0)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
// Convert the native character to ASCII before
|
|
// mapping it to Unicode.
|
|
|
|
if( RC_BAD( rc = f_uni2UTF8( (FLMUNICODE)f_toascii( *pszPtr),
|
|
pucEncPtr, &uiTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiEncodedLen += uiTmp;
|
|
|
|
if( pucEncPtr)
|
|
{
|
|
pucEncPtr += uiTmp;
|
|
}
|
|
|
|
pszPtr++;
|
|
uiCharsEncoded++;
|
|
}
|
|
|
|
// Make sure the string length (which may have been provided by
|
|
// the caller) was correct.
|
|
|
|
if( uiCharsEncoded != uiStrLen)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_INVALID_PARM);
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Terminate the string with a 0 byte
|
|
|
|
if( (uiMaxLen - uiEncodedLen) == 0)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
if( pucEncPtr)
|
|
{
|
|
*pucEncPtr++ = 0;
|
|
}
|
|
uiEncodedLen++;
|
|
|
|
// Return the length of the encoded string
|
|
|
|
*puiBufLength = uiEncodedLen;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Encode a string into FLAIM's internal text format
|
|
(SEN-prefixed, null-terminated UTF8). The string is prefixed with
|
|
a SEN that indicates the number of characters, not including the
|
|
terminating NULL.
|
|
|
|
This routine can be called with a NULL input buffer. If it is
|
|
called in this way, the length of the encoded string will be
|
|
returned in *puiBufLength, but no encoding will actually be
|
|
performed.
|
|
****************************************************************************/
|
|
RCODE flmUTF8ToStorage(
|
|
const FLMBYTE * pucUTF8, // UTF8 string to encode
|
|
FLMUINT uiBytesInBuffer, // Maximum bytes to process from source
|
|
FLMBYTE * pucBuf, // Destination buffer
|
|
FLMUINT * puiBufLength) // [IN ] Size of pucBuf,
|
|
// [OUT] Amount of pucBuf used
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBYTE * pucEncPtr;
|
|
const FLMBYTE * pucPtr = NULL;
|
|
FLMUINT uiMaxLen;
|
|
FLMUINT uiEncodedLen = 0;
|
|
FLMUINT uiCharCount;
|
|
FLMUINT uiByteCount;
|
|
FLMUINT uiTmp;
|
|
FLMUNICODE uChar;
|
|
FLMBYTE ucTmpSen[ 5];
|
|
FLMBYTE * pucTmpSen = &ucTmpSen[ 0];
|
|
const FLMBYTE * pucEnd = NULL;
|
|
|
|
if( !pucBuf)
|
|
{
|
|
uiMaxLen = (~(FLMUINT)0);
|
|
}
|
|
else
|
|
{
|
|
uiMaxLen = *puiBufLength;
|
|
}
|
|
|
|
if( uiBytesInBuffer)
|
|
{
|
|
pucEnd = &pucUTF8[ uiBytesInBuffer];
|
|
}
|
|
|
|
// Determine the number of bytes and characters in the
|
|
// string
|
|
|
|
uiCharCount = 0;
|
|
pucPtr = pucUTF8;
|
|
for( ;;)
|
|
{
|
|
if( RC_BAD( rc = f_getCharFromUTF8Buf( &pucPtr, pucEnd, &uChar)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !uChar)
|
|
{
|
|
break;
|
|
}
|
|
|
|
uiCharCount++;
|
|
}
|
|
|
|
if( !uiCharCount)
|
|
{
|
|
*puiBufLength = 0;
|
|
goto Exit;
|
|
}
|
|
|
|
pucEncPtr = pucBuf;
|
|
|
|
// Encode the number of characters as a SEN. If pucEncPtr is
|
|
// NULL, the caller is only interested in the length of the encoded
|
|
// string, so a temporary buffer is used to call f_encodeSEN.
|
|
|
|
uiTmp = f_encodeSEN( uiCharCount, &pucTmpSen);
|
|
if( pucEncPtr)
|
|
{
|
|
if( (uiEncodedLen + uiTmp) >= uiMaxLen)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
f_memcpy( pucEncPtr, &ucTmpSen[ 0], uiTmp);
|
|
pucEncPtr += uiTmp;
|
|
}
|
|
uiEncodedLen += uiTmp;
|
|
|
|
// Copy the UTF8 characters into the destination buffer
|
|
|
|
uiByteCount = (FLMUINT)(pucPtr - pucUTF8);
|
|
if( pucEncPtr)
|
|
{
|
|
if( (uiMaxLen - uiEncodedLen) < uiByteCount)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
f_memcpy( pucEncPtr, pucUTF8, uiByteCount);
|
|
pucEncPtr += uiByteCount;
|
|
}
|
|
uiEncodedLen += uiByteCount;
|
|
|
|
// Terminate the string with a 0 byte
|
|
|
|
if( uiEncodedLen == uiMaxLen)
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
if( pucEncPtr)
|
|
{
|
|
*pucEncPtr++ = 0;
|
|
}
|
|
uiEncodedLen++;
|
|
|
|
// Return the length of the encoded string
|
|
|
|
*puiBufLength = uiEncodedLen;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Convert text storage string to Unicode.
|
|
Notes: If puzOutBuf is NULL, only a count is returned
|
|
in puiOutBufLen to indicate the number of bytes needed to
|
|
contain the data. Two (unicode) bytes must be
|
|
added to this value to account for null termination.
|
|
****************************************************************************/
|
|
RCODE flmStorage2Unicode(
|
|
FLMUINT uiType,
|
|
FLMUINT uiBufLength,
|
|
const FLMBYTE * pucBuffer,
|
|
FLMUINT * puiOutBufLen,
|
|
// [IN] Number of bytes available in buffer
|
|
// [OUT] Returns the number of bytes that are needed to
|
|
// represent the data. The null termination byte(s) are
|
|
// not included in this value.
|
|
void * pOutBuf)
|
|
// [IN/OUT] Buffer to hold the data.
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMUNICODE uChar;
|
|
FLMUINT uiOffset = 0;
|
|
FLMUINT uiSenLen;
|
|
FLMUINT uiNumChars;
|
|
FLMUINT uiMaxOutChars;
|
|
FLMBYTE ucTempBuf[ 64];
|
|
FLMUNICODE * puzOutBuf = NULL;
|
|
FLMBYTE * pszOutBuf = NULL;
|
|
const FLMBYTE * pucEnd;
|
|
FLMUINT uiDecodeCount;
|
|
|
|
if( !pucBuffer || !uiBufLength)
|
|
{
|
|
ucTempBuf[ 0] = 0; // SEN encoding of 0
|
|
ucTempBuf[ 1] = 0; // String terminator
|
|
pucBuffer = &ucTempBuf[ 0];
|
|
uiBufLength = 2;
|
|
}
|
|
else if( uiType != SFLM_STRING_TYPE)
|
|
{
|
|
// If the value is a number, convert to text
|
|
|
|
if( uiType == SFLM_NUMBER_TYPE)
|
|
{
|
|
FLMUINT uiTmp;
|
|
|
|
uiTmp = sizeof( ucTempBuf);
|
|
if( RC_BAD( rc = flmStorageNum2StorageText( pucBuffer, uiBufLength,
|
|
ucTempBuf, &uiTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pucBuffer = &ucTempBuf[ 0];
|
|
uiBufLength = uiTmp;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( !uiBufLength)
|
|
{
|
|
if( puiOutBufLen)
|
|
{
|
|
if( *puiOutBufLen >= 2)
|
|
{
|
|
*((FLMUNICODE *)pOutBuf) = 0;
|
|
}
|
|
|
|
*puiOutBufLen = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
pucEnd = &pucBuffer[ uiBufLength];
|
|
|
|
uiSenLen = f_getSENLength( *pucBuffer);
|
|
if( pucBuffer + uiSenLen >= pucEnd)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = f_decodeSEN( &pucBuffer, pucEnd, &uiNumChars)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If only a length is needed (number of bytes), we can
|
|
// return that without parsing the string
|
|
|
|
if( !pOutBuf)
|
|
{
|
|
uiOffset = uiNumChars;
|
|
goto Exit;
|
|
}
|
|
|
|
flmAssert( puiOutBufLen);
|
|
uiMaxOutChars = (*puiOutBufLen) / sizeof( FLMUNICODE);
|
|
puzOutBuf = (FLMUNICODE *)pOutBuf;
|
|
|
|
// If we have a zero-length string, jump to exit.
|
|
|
|
if( !uiNumChars)
|
|
{
|
|
if( (pucBuffer + 1) != pucEnd || *pucBuffer != 0)
|
|
{
|
|
rc = RC_SET( NE_SFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( *pucBuffer != 0)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_DATA_ERROR);
|
|
}
|
|
else if (!uiMaxOutChars)
|
|
{
|
|
goto Overflow_Error;
|
|
}
|
|
|
|
if( puzOutBuf)
|
|
{
|
|
*puzOutBuf = 0;
|
|
}
|
|
else
|
|
{
|
|
*pszOutBuf = 0;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
// Parse through the string, outputting data to the buffer as we go.
|
|
|
|
uChar = 0;
|
|
uiDecodeCount = 0;
|
|
for( ;;)
|
|
{
|
|
// Decode the bytes.
|
|
|
|
if( RC_BAD( rc = f_getCharFromUTF8Buf( &pucBuffer, pucEnd, &uChar)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !uChar)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( uiOffset == uiMaxOutChars)
|
|
{
|
|
goto Overflow_Error;
|
|
}
|
|
|
|
if( puzOutBuf)
|
|
{
|
|
puzOutBuf[ uiOffset++] = uChar;
|
|
}
|
|
else
|
|
{
|
|
if ( uChar <= 0xFF)
|
|
{
|
|
uChar = (FLMUNICODE)f_tonative( (FLMBYTE)uChar);
|
|
pszOutBuf[ uiOffset++] = (FLMBYTE)uChar;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
uiDecodeCount++;
|
|
}
|
|
|
|
if( uChar || uiDecodeCount != uiNumChars)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
// There is room for the 0 terminating character, but we
|
|
// will not increment return length.
|
|
|
|
if( uiOffset < uiMaxOutChars)
|
|
{
|
|
if( puzOutBuf)
|
|
{
|
|
puzOutBuf[ uiOffset] = 0;
|
|
}
|
|
else
|
|
{
|
|
pszOutBuf[ uiOffset] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Overflow_Error:
|
|
flmAssert( uiOffset == uiMaxOutChars);
|
|
|
|
// If uiOffset is zero, so is uiMaxOutChars, which means
|
|
// that we can't even put out the zero terminator.
|
|
|
|
if (uiOffset)
|
|
{
|
|
uiOffset--;
|
|
if( puzOutBuf)
|
|
{
|
|
puzOutBuf[ uiOffset] = 0;
|
|
}
|
|
else
|
|
{
|
|
pszOutBuf[ uiOffset] = 0;
|
|
}
|
|
}
|
|
rc = RC_SET( NE_SFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( puiOutBufLen)
|
|
{
|
|
*puiOutBufLen = uiOffset + uiOffset;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Converts storage formats to UNICODE
|
|
****************************************************************************/
|
|
RCODE flmStorage2Unicode(
|
|
FLMUINT uiType,
|
|
FLMUINT uiStorageLength,
|
|
const FLMBYTE * pucStorageBuffer,
|
|
F_DynaBuf * pBuffer)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBYTE ucTempBuf[ 80];
|
|
const FLMBYTE * pucEnd;
|
|
FLMUINT uiSenLen;
|
|
FLMUINT uiNumChars;
|
|
FLMUNICODE * puzDestBuffer;
|
|
|
|
pBuffer->truncateData( 0);
|
|
|
|
if( uiType != SFLM_STRING_TYPE)
|
|
{
|
|
// If the value is a number, convert to text
|
|
|
|
if( uiType == SFLM_NUMBER_TYPE)
|
|
{
|
|
FLMUINT uiTmp;
|
|
|
|
uiStorageLength = sizeof( ucTempBuf);
|
|
if( RC_BAD( rc = flmStorageNum2StorageText( pucStorageBuffer,
|
|
uiStorageLength, ucTempBuf, &uiTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pucStorageBuffer = &ucTempBuf[ 0];
|
|
uiStorageLength = uiTmp;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pucEnd = &pucStorageBuffer[ uiStorageLength];
|
|
uiSenLen = f_getSENLength( *pucStorageBuffer);
|
|
|
|
if( pucStorageBuffer + uiSenLen >= pucEnd)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = f_decodeSEN( &pucStorageBuffer, pucEnd, &uiNumChars)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBuffer->allocSpace(
|
|
(uiNumChars + 1) * sizeof( FLMUNICODE), (void **)&puzDestBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Parse through the string outputting data to the buffer as we go
|
|
|
|
for( ;;)
|
|
{
|
|
if( RC_BAD( rc = f_getCharFromUTF8Buf(
|
|
&pucStorageBuffer, pucEnd, puzDestBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !(*puzDestBuffer))
|
|
{
|
|
break;
|
|
}
|
|
|
|
puzDestBuffer++;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Converts a storage buffer to UTF-8 (null-terminated) text
|
|
****************************************************************************/
|
|
RCODE flmStorage2UTF8(
|
|
FLMUINT uiType,
|
|
FLMUINT uiBufLength,
|
|
const FLMBYTE * pucBuffer,
|
|
FLMUINT * puiOutBufLen,
|
|
FLMBYTE * pucOutBuf)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
const FLMBYTE * pucEnd;
|
|
FLMBYTE ucTempBuf[ 64];
|
|
FLMUINT uiSenLen;
|
|
|
|
if( !pucBuffer)
|
|
{
|
|
ucTempBuf[ 0] = 0; // SEN encoding of 0
|
|
ucTempBuf[ 1] = 0; // String terminator
|
|
pucBuffer = &ucTempBuf[ 0];
|
|
uiBufLength = 2;
|
|
}
|
|
else if( uiType != SFLM_STRING_TYPE)
|
|
{
|
|
// If the value is a number, convert to text
|
|
|
|
if( uiType == SFLM_NUMBER_TYPE)
|
|
{
|
|
FLMUINT uiTmp;
|
|
|
|
uiTmp = sizeof( ucTempBuf);
|
|
if( RC_BAD( rc = flmStorageNum2StorageText( pucBuffer, uiBufLength,
|
|
ucTempBuf, &uiTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pucBuffer = &ucTempBuf[ 0];
|
|
uiBufLength = uiTmp;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( !uiBufLength)
|
|
{
|
|
if( *puiOutBufLen && pucOutBuf)
|
|
{
|
|
*pucOutBuf = 0;
|
|
}
|
|
*puiOutBufLen = 0;
|
|
goto Exit;
|
|
}
|
|
|
|
pucEnd = &pucBuffer[ uiBufLength];
|
|
|
|
uiSenLen = f_getSENLength( *pucBuffer);
|
|
if( pucBuffer + uiSenLen >= pucEnd)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = f_decodeSEN( &pucBuffer, pucEnd, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pucOutBuf)
|
|
{
|
|
if( *puiOutBufLen >= uiBufLength - uiSenLen)
|
|
{
|
|
f_memcpy( pucOutBuf, pucBuffer, uiBufLength - uiSenLen);
|
|
}
|
|
}
|
|
|
|
*puiOutBufLen = (uiBufLength - uiSenLen) - 1;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Converts storage formats to UTF8
|
|
****************************************************************************/
|
|
RCODE flmStorage2UTF8(
|
|
FLMUINT uiType,
|
|
FLMUINT uiStorageLength,
|
|
const FLMBYTE * pucStorageBuffer,
|
|
F_DynaBuf * pBuffer)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBYTE ucTempBuf[ 80];
|
|
FLMUINT uiSenLen;
|
|
FLMBYTE * pucDestBuffer;
|
|
|
|
pBuffer->truncateData( 0);
|
|
|
|
if( uiType != SFLM_STRING_TYPE)
|
|
{
|
|
// If the value is a number, convert to text
|
|
|
|
if( uiType == SFLM_NUMBER_TYPE)
|
|
{
|
|
FLMUINT uiTmp;
|
|
|
|
uiStorageLength = sizeof( ucTempBuf);
|
|
if( RC_BAD( rc = flmStorageNum2StorageText( pucStorageBuffer,
|
|
uiStorageLength, ucTempBuf, &uiTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pucStorageBuffer = &ucTempBuf[ 0];
|
|
uiStorageLength = uiTmp;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( NE_SFLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
uiSenLen = f_getSENLength( *pucStorageBuffer);
|
|
if (uiSenLen >= uiStorageLength)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBuffer->allocSpace( uiStorageLength - uiSenLen,
|
|
(void **)&pucDestBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
f_memcpy( pucDestBuffer, pucStorageBuffer + uiSenLen,
|
|
uiStorageLength - uiSenLen);
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Reads and returns the value of the SEN indicating the number of
|
|
characters encoded into the storage (UTF-8) string
|
|
****************************************************************************/
|
|
RCODE flmGetCharCountFromStorageBuf(
|
|
const FLMBYTE ** ppucBuf,
|
|
FLMUINT uiBufSize,
|
|
FLMUINT * puiNumChars,
|
|
FLMUINT * puiSenLen)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMUINT uiSenLen;
|
|
FLMUINT uiNumChars;
|
|
|
|
if( !uiBufSize)
|
|
{
|
|
if( puiNumChars)
|
|
{
|
|
*puiNumChars = 0;
|
|
}
|
|
|
|
if( puiSenLen)
|
|
{
|
|
*puiSenLen = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if( (uiSenLen = f_getSENLength( (*ppucBuf)[ 0])) >= uiBufSize)
|
|
{
|
|
rc = RC_SET( NE_SFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = f_decodeSEN( ppucBuf, *ppucBuf + uiSenLen, &uiNumChars)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( puiNumChars)
|
|
{
|
|
*puiNumChars = uiNumChars;
|
|
}
|
|
|
|
if( puiSenLen)
|
|
{
|
|
*puiSenLen = uiSenLen;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: This routine converts an internal number to internal (ASCII) text.
|
|
Notes: If the buffer pointer is NULL, the routine just determines how
|
|
much buffer space is needed to store the number in a text string.
|
|
****************************************************************************/
|
|
RCODE flmStorageNum2StorageText(
|
|
const FLMBYTE * pucNum,
|
|
FLMUINT uiNumLen,
|
|
FLMBYTE * pucBuffer,
|
|
FLMUINT * puiBufLen)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMUINT64 ui64Num;
|
|
FLMINT64 i64Num;
|
|
FLMUINT uiOffset = 0;
|
|
FLMBOOL bNeg = FALSE;
|
|
char szTmpBuf[ 64];
|
|
|
|
if( RC_BAD( rc = flmStorage2Number64( SFLM_NUMBER_TYPE, uiNumLen,
|
|
pucNum, &ui64Num, NULL)))
|
|
{
|
|
if( rc == NE_SFLM_CONV_NUM_UNDERFLOW)
|
|
{
|
|
if( RC_BAD( rc = flmStorage2Number64( SFLM_NUMBER_TYPE, uiNumLen,
|
|
pucNum, NULL, &i64Num)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ui64Num = (FLMUINT64)-i64Num;
|
|
bNeg = TRUE;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( bNeg)
|
|
{
|
|
szTmpBuf[ uiOffset++] = '-';
|
|
}
|
|
|
|
uiOffset += f_sprintf( &szTmpBuf[ uiOffset], "%I64u", ui64Num);
|
|
|
|
if( RC_BAD( rc = flmNative2Storage( szTmpBuf, uiOffset,
|
|
pucBuffer, puiBufLen, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|