git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
1423 lines
24 KiB
C++
1423 lines
24 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: Data input stream class.
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1998-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: fcs_dis.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FCS_DIS::FCS_DIS( void)
|
|
{
|
|
m_pIStream = NULL;
|
|
m_uiBOffset = m_uiBDataSize = 0;
|
|
m_bSetupCalled = FALSE;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FCS_DIS::~FCS_DIS( void)
|
|
{
|
|
if( m_bSetupCalled)
|
|
{
|
|
(void)close();
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::setup(
|
|
FCS_ISTM * pIStream)
|
|
{
|
|
m_pIStream = pIStream;
|
|
m_bSetupCalled = TRUE;
|
|
|
|
return( FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::readByte(
|
|
FLMBYTE * pValue)
|
|
{
|
|
return( read( pValue, 1, NULL));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::readShort(
|
|
FLMINT16 * pValue)
|
|
{
|
|
FLMUINT16 ui16Value;
|
|
RCODE rc;
|
|
|
|
// Read the data.
|
|
|
|
if( RC_OK( rc = read( (FLMBYTE *)pValue, 2, NULL)))
|
|
{
|
|
ui16Value = byteToInt( (FLMBYTE *)pValue);
|
|
*pValue = *((FLMINT16 *)&ui16Value);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::readUShort(
|
|
FLMUINT16 * pValue)
|
|
{
|
|
RCODE rc;
|
|
|
|
// Read the data.
|
|
|
|
if( RC_OK( rc = read( (FLMBYTE *)pValue, 2, NULL)))
|
|
{
|
|
*pValue = byteToInt( (FLMBYTE *)pValue);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::readInt(
|
|
FLMINT32 * pValue)
|
|
{
|
|
FLMUINT32 ui32Value;
|
|
RCODE rc;
|
|
|
|
// Read the data.
|
|
|
|
if( RC_OK( rc = read( (FLMBYTE *)pValue, 4, NULL)))
|
|
{
|
|
ui32Value = byteToLong( (FLMBYTE *)pValue);
|
|
*pValue = *((FLMINT32 *)&ui32Value);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::readUInt(
|
|
FLMUINT32 * pValue)
|
|
{
|
|
RCODE rc;
|
|
|
|
// Read the data.
|
|
|
|
if( RC_OK( rc = read( (FLMBYTE *)pValue, 4, NULL)))
|
|
{
|
|
*pValue = byteToLong( (FLMBYTE *)pValue);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::readInt64(
|
|
FLMINT64 * pValue)
|
|
{
|
|
FLMUINT64 ui64Value;
|
|
RCODE rc;
|
|
|
|
// Read the data.
|
|
|
|
if( RC_OK( rc = read( (FLMBYTE *)pValue, 8, NULL)))
|
|
{
|
|
ui64Value = byteToLong64( (FLMBYTE *)pValue);
|
|
*pValue = *((FLMINT64 *)&ui64Value);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::readUInt64(
|
|
FLMUINT64 * pValue)
|
|
{
|
|
RCODE rc;
|
|
|
|
// Read the data.
|
|
|
|
if( RC_OK( rc = read( (FLMBYTE *)pValue, 8, NULL)))
|
|
{
|
|
*pValue = byteToLong64( (FLMBYTE *)pValue);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::skip(
|
|
FLMUINT uiBytesToSkip)
|
|
{
|
|
return( read( NULL, uiBytesToSkip, NULL));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Flushes any pending data and closes the DIS
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::close( void)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
|
|
/*
|
|
Verify that Setup has been called.
|
|
*/
|
|
|
|
flmAssert( m_bSetupCalled == TRUE);
|
|
|
|
/*
|
|
Terminate and flush.
|
|
*/
|
|
|
|
if( RC_BAD( rc = endMessage()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
Reset the member variables.
|
|
*/
|
|
|
|
m_pIStream = NULL;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Desc: Returns the state of the stream (open == TRUE, closed == FALSE)
|
|
****************************************************************************/
|
|
FLMBOOL FCS_DIS::isOpen( void)
|
|
{
|
|
/*
|
|
Verify that Setup has been called.
|
|
*/
|
|
|
|
flmAssert( m_bSetupCalled == TRUE);
|
|
|
|
if( m_pIStream && m_pIStream->isOpen())
|
|
{
|
|
return( TRUE);
|
|
}
|
|
|
|
return( FALSE);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Flushes and terminates the current parent stream message
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::endMessage( void)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
|
|
/*
|
|
Verify that Setup has been called.
|
|
*/
|
|
|
|
flmAssert( m_bSetupCalled == TRUE);
|
|
|
|
if( !m_pIStream)
|
|
{
|
|
rc = RC_SET( FERR_FAILURE);
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
Flush any pending data.
|
|
*/
|
|
|
|
if( RC_BAD( rc = flush()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
Terminate the message.
|
|
*/
|
|
|
|
if( RC_BAD( rc = m_pIStream->endMessage()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Desc: Flushes any pending data
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::flush( void)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
|
|
/*
|
|
Verify that Setup has been called.
|
|
*/
|
|
|
|
flmAssert( m_bSetupCalled == TRUE);
|
|
|
|
if( !m_pIStream)
|
|
{
|
|
rc = RC_SET( FERR_FAILURE);
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
Flush the passed-in input stream.
|
|
*/
|
|
|
|
if( RC_BAD( rc = m_pIStream->flush()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Desc: Reads the specified number of bytes.
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::read(
|
|
FLMBYTE * pucData,
|
|
FLMUINT uiLength,
|
|
FLMUINT * puiBytesRead)
|
|
{
|
|
FLMUINT uiCopySize;
|
|
FLMUINT uiReadLen;
|
|
FLMBYTE * pucPos = NULL;
|
|
RCODE rc = FERR_OK;
|
|
|
|
/*
|
|
Verify that Setup has been called.
|
|
*/
|
|
|
|
flmAssert( m_bSetupCalled == TRUE);
|
|
|
|
if( !m_pIStream)
|
|
{
|
|
rc = RC_SET( FERR_FAILURE);
|
|
goto Exit;
|
|
}
|
|
|
|
if( puiBytesRead)
|
|
{
|
|
*puiBytesRead = uiLength;
|
|
}
|
|
|
|
pucPos = pucData;
|
|
while( uiLength)
|
|
{
|
|
if( m_uiBOffset == m_uiBDataSize)
|
|
{
|
|
m_uiBOffset = m_uiBDataSize = 0;
|
|
|
|
if( RC_BAD( rc = m_pIStream->read( m_pucBuffer,
|
|
FCS_DIS_BUFFER_SIZE, &uiReadLen)))
|
|
{
|
|
if( uiReadLen)
|
|
{
|
|
rc = FERR_OK;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
m_uiBDataSize = uiReadLen;
|
|
}
|
|
|
|
uiCopySize = m_uiBDataSize - m_uiBOffset;
|
|
if( uiLength < uiCopySize)
|
|
{
|
|
uiCopySize = uiLength;
|
|
}
|
|
|
|
if( pucPos)
|
|
{
|
|
#if defined( FLM_NLM) || defined( FLM_WIN)
|
|
if( uiCopySize == 1)
|
|
{
|
|
*pucPos = m_pucBuffer[ m_uiBOffset];
|
|
}
|
|
else if( uiLength == 2)
|
|
{
|
|
*(FLMUINT16 *)pucPos = *((FLMUINT16 *)&m_pucBuffer[ m_uiBOffset]);
|
|
}
|
|
else if( uiLength == 4)
|
|
{
|
|
*(FLMUINT32 *)pucPos = *((FLMUINT32 *)&m_pucBuffer[ m_uiBOffset]);
|
|
}
|
|
else
|
|
{
|
|
f_memcpy( pucPos, &(m_pucBuffer[ m_uiBOffset]), uiCopySize);
|
|
}
|
|
#else
|
|
f_memcpy( pucPos, &(m_pucBuffer[ m_uiBOffset]), uiCopySize);
|
|
#endif
|
|
pucPos += uiCopySize;
|
|
}
|
|
m_uiBOffset += uiCopySize;
|
|
uiLength -= uiCopySize;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_OK( rc) && uiLength)
|
|
{
|
|
/*
|
|
Unable to satisfy the read request.
|
|
*/
|
|
|
|
rc = RC_SET( FERR_EOF_HIT);
|
|
}
|
|
|
|
if( puiBytesRead)
|
|
{
|
|
(*puiBytesRead) -= uiLength;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Desc: Reads a binary token from the stream. The token is tagged with a
|
|
length.
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::readBinary(
|
|
POOL * pPool,
|
|
FLMBYTE ** ppValue,
|
|
FLMUINT * puiDataSize)
|
|
{
|
|
FLMUINT16 ui16DataSize;
|
|
RCODE rc = FERR_OK;
|
|
|
|
if( RC_BAD( rc = readUShort( &ui16DataSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pPool)
|
|
{
|
|
/*
|
|
If the data size is non-zero, allocate a buffer and
|
|
read the entire binary value.
|
|
*/
|
|
|
|
if( ui16DataSize)
|
|
{
|
|
if( (*ppValue = (FLMBYTE *)GedPoolAlloc( pPool, ui16DataSize)) == NULL)
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = read( *ppValue, ui16DataSize, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*ppValue = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
The application is not interested in the value. Just skip the
|
|
to the end of the value.
|
|
*/
|
|
|
|
if( RC_BAD( rc = skip( ui16DataSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( puiDataSize)
|
|
{
|
|
*puiDataSize = ui16DataSize;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Desc: Reads a large binary token from the stream. The token is tagged with a
|
|
length.
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::readLargeBinary(
|
|
POOL * pPool,
|
|
FLMBYTE ** ppValue,
|
|
FLMUINT * puiDataSize)
|
|
{
|
|
FLMUINT32 ui32DataSize;
|
|
RCODE rc = FERR_OK;
|
|
|
|
if( RC_BAD( rc = readUInt( &ui32DataSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pPool)
|
|
{
|
|
/*
|
|
If the data size is non-zero, allocate a buffer and
|
|
read the entire binary value.
|
|
*/
|
|
|
|
if( ui32DataSize)
|
|
{
|
|
if( (*ppValue = (FLMBYTE *)GedPoolAlloc( pPool, ui32DataSize)) == NULL)
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = read( *ppValue, ui32DataSize, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*ppValue = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
The application is not interested in the value. Just skip the
|
|
to the end of the value.
|
|
*/
|
|
|
|
if( RC_BAD( rc = skip( ui32DataSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( puiDataSize)
|
|
{
|
|
*puiDataSize = (FLMUINT)ui32DataSize;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Desc: Reads a UTF-8 string from the stream.
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::readUTF(
|
|
POOL * pPool,
|
|
FLMUNICODE ** ppValue)
|
|
{
|
|
FLMBYTE ucByte1;
|
|
FLMBYTE ucByte2;
|
|
FLMBYTE ucByte3;
|
|
FLMBYTE ucLoByte;
|
|
FLMBYTE ucHiByte;
|
|
FLMUINT16 ui16UTFLen;
|
|
FLMUINT uiOffset = 0;
|
|
RCODE rc = FERR_OK;
|
|
|
|
/*
|
|
Read the data.
|
|
*/
|
|
|
|
if( RC_BAD( rc = readUShort( &ui16UTFLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
Check the size of the UTF string. FLAIM does not support
|
|
strings that are larger than 32K characters.
|
|
*/
|
|
|
|
if( ui16UTFLen >= 32767)
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
Allocate space for the string.
|
|
*/
|
|
|
|
if( pPool)
|
|
{
|
|
*ppValue = (FLMUNICODE *)GedPoolAlloc( pPool,
|
|
(FLMUINT)((FLMUINT)sizeof( FLMUNICODE) * (FLMUINT)(ui16UTFLen + 1)));
|
|
}
|
|
else if( ppValue)
|
|
{
|
|
*ppValue = NULL;
|
|
}
|
|
|
|
while( ui16UTFLen)
|
|
{
|
|
/*
|
|
Read and decode the bytes.
|
|
*/
|
|
|
|
if( RC_BAD( rc = read( &ucByte1, 1, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (ucByte1 & 0xC0) != 0xC0)
|
|
{
|
|
ucHiByte = 0;
|
|
ucLoByte = ucByte1;
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = read( &ucByte2, 1, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (ucByte1 & 0xE0) == 0xE0)
|
|
{
|
|
if( RC_BAD( rc = read( &ucByte3, 1, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ucHiByte =
|
|
(FLMBYTE)(((ucByte1 & 0x0F) << 4) | ((ucByte2 & 0x3C) >> 2));
|
|
ucLoByte = (FLMBYTE)(((ucByte2 & 0x03) << 6) | (ucByte3 & 0x3F));
|
|
}
|
|
else
|
|
{
|
|
ucHiByte = (FLMBYTE)(((ucByte1 & 0x1C) >> 2));
|
|
ucLoByte = (FLMBYTE)(((ucByte1 & 0x03) << 6) | (ucByte2 & 0x3F));
|
|
}
|
|
}
|
|
|
|
if( pPool)
|
|
{
|
|
(*ppValue)[ uiOffset] =
|
|
(FLMUNICODE)(((((FLMUNICODE)(ucHiByte)) << 8) |
|
|
((FLMUNICODE)(ucLoByte))));
|
|
}
|
|
|
|
uiOffset++;
|
|
ui16UTFLen--;
|
|
}
|
|
|
|
if( pPool)
|
|
{
|
|
(*ppValue)[ uiOffset] = 0;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Reads an Hierarchical Tagged Data record from the stream.
|
|
****************************************************************************/
|
|
RCODE FCS_DIS::readHTD(
|
|
POOL * pPool,
|
|
FLMUINT uiContainer,
|
|
FLMUINT uiDrn,
|
|
NODE ** ppNode,
|
|
FlmRecord ** ppRecord)
|
|
{
|
|
|
|
FLMBYTE ucType;
|
|
FLMBYTE ucLevel = 0;
|
|
FLMBYTE ucPrevLevel = 0;
|
|
FLMBYTE ucDescriptor;
|
|
FLMBYTE ucFlags;
|
|
FLMUINT16 ui16Tag;
|
|
FLMBOOL bHasValue;
|
|
FLMBOOL bChild;
|
|
FLMBOOL bSibling;
|
|
FLMBOOL bLeftTruncated;
|
|
FLMBOOL bRightTruncated;
|
|
NODE * pRoot = NULL;
|
|
NODE * pNode = NULL;
|
|
NODE * pPrevNode = NULL;
|
|
void * pField = NULL;
|
|
void * pvMark = NULL;
|
|
RCODE rc = FERR_OK;
|
|
|
|
if( pPool)
|
|
{
|
|
pvMark = GedPoolMark( pPool);
|
|
}
|
|
|
|
for( ;;)
|
|
{
|
|
/*
|
|
Reset variables.
|
|
*/
|
|
|
|
bChild = FALSE;
|
|
bSibling = FALSE;
|
|
|
|
/*
|
|
Read the attribute's tag number.
|
|
*/
|
|
|
|
if( RC_BAD( rc = readUShort( &ui16Tag)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
A tag number of 0 indicates that the end of the HTD data
|
|
stream has been reached.
|
|
*/
|
|
|
|
if( !ui16Tag)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/*
|
|
Read the attribute's descriptor.
|
|
*/
|
|
|
|
if( RC_BAD(rc = read( &ucDescriptor, 1, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
Set the flag indicating whether or not the
|
|
attribute has a value.
|
|
*/
|
|
|
|
bHasValue = (FLMBOOL)((ucDescriptor & HTD_HAS_VALUE_FLAG)
|
|
? (FLMBOOL)TRUE
|
|
: (FLMBOOL)FALSE);
|
|
|
|
/*
|
|
Set the value type.
|
|
*/
|
|
|
|
ucType = (FLMBYTE)((ucDescriptor & HTD_VALUE_TYPE_MASK));
|
|
|
|
/*
|
|
Get the attribute's level.
|
|
*/
|
|
|
|
switch( (ucDescriptor & HTD_LEVEL_MASK) >> HTD_LEVEL_POS)
|
|
{
|
|
case HTD_LEVEL_SIBLING:
|
|
{
|
|
bSibling = TRUE;
|
|
ucLevel = ucPrevLevel;
|
|
break;
|
|
}
|
|
|
|
case HTD_LEVEL_CHILD:
|
|
{
|
|
if( ucLevel < 0xFF)
|
|
{
|
|
bChild = TRUE;
|
|
ucLevel = (FLMBYTE)(ucPrevLevel + 1);
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( FERR_BAD_FIELD_LEVEL);
|
|
goto Exit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case HTD_LEVEL_BACK:
|
|
{
|
|
if( ucLevel > 0)
|
|
{
|
|
ucLevel = (FLMBYTE)(ucPrevLevel - 1);
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( FERR_BAD_FIELD_LEVEL);
|
|
goto Exit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case HTD_LEVEL_BACK_X:
|
|
{
|
|
FLMBYTE ucLevelsBack;
|
|
|
|
if( RC_BAD(rc = read( &ucLevelsBack, 1, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ucPrevLevel >= ucLevelsBack)
|
|
{
|
|
ucLevel = (FLMBYTE)(ucPrevLevel - ucLevelsBack);
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( FERR_BAD_FIELD_LEVEL);
|
|
goto Exit;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Allocate the record object
|
|
*/
|
|
|
|
if( ppRecord && ucLevel == 0)
|
|
{
|
|
if( *ppRecord)
|
|
{
|
|
if( (*ppRecord)->isReadOnly() ||
|
|
(*ppRecord)->getRefCount() > 1)
|
|
{
|
|
(*ppRecord)->Release();
|
|
|
|
if( (*ppRecord = f_new FlmRecord) == NULL)
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Reuse the existing FlmRecord object.
|
|
(*ppRecord)->clear();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( (*ppRecord = f_new FlmRecord) == NULL)
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
}
|
|
(*ppRecord)->setContainerID( uiContainer);
|
|
(*ppRecord)->setID( uiDrn);
|
|
}
|
|
|
|
/*
|
|
Allocate the attribute.
|
|
*/
|
|
|
|
if( pPool && ppNode)
|
|
{
|
|
pNode = GedNodeMake( pPool, ui16Tag, &rc);
|
|
if( RC_BAD( rc))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
bLeftTruncated = FALSE;
|
|
bRightTruncated = FALSE;
|
|
|
|
/*
|
|
Read the attribute's value.
|
|
*/
|
|
|
|
switch( ucType)
|
|
{
|
|
case HTD_TYPE_UNICODE:
|
|
{
|
|
FLMUNICODE * pUTF;
|
|
|
|
if( pNode)
|
|
{
|
|
GedValTypeSet( pNode, FLM_TEXT_TYPE);
|
|
}
|
|
|
|
if( ppRecord)
|
|
{
|
|
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
|
|
ui16Tag, FLM_TEXT_TYPE, &pField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( !bHasValue)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/*
|
|
Read UNICODE text in UTF-8 format.
|
|
*/
|
|
|
|
if( pPool)
|
|
{
|
|
if( RC_BAD( rc = readUTF( pPool, &pUTF)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pNode)
|
|
{
|
|
if( RC_BAD( rc = GedPutUNICODE( pPool, pNode, pUTF)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( ppRecord)
|
|
{
|
|
if( RC_BAD( rc = (*ppRecord)->setUnicode( pField, pUTF)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = readUTF( NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case HTD_TYPE_UINT:
|
|
{
|
|
FLMUINT32 ui32Value;
|
|
|
|
if( pNode)
|
|
{
|
|
GedValTypeSet( pNode, FLM_NUMBER_TYPE);
|
|
}
|
|
|
|
if( ppRecord)
|
|
{
|
|
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
|
|
ui16Tag, FLM_NUMBER_TYPE, &pField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( !bHasValue)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/*
|
|
Read an unsigned 32-bit integer.
|
|
*/
|
|
|
|
if( RC_BAD( rc = readUInt( &ui32Value)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pNode)
|
|
{
|
|
if( RC_BAD( rc = GedPutUINT( pPool, pNode, ui32Value)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( ppRecord)
|
|
{
|
|
if( RC_BAD( rc = (*ppRecord)->setUINT( pField, ui32Value)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case HTD_TYPE_INT:
|
|
{
|
|
FLMINT32 i32Value;
|
|
|
|
if( pNode)
|
|
{
|
|
GedValTypeSet( pNode, FLM_NUMBER_TYPE);
|
|
}
|
|
|
|
if( ppRecord)
|
|
{
|
|
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
|
|
ui16Tag, FLM_NUMBER_TYPE, &pField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( !bHasValue)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/*
|
|
Read a signed 32-bit integer.
|
|
*/
|
|
|
|
if( RC_BAD( rc = readInt( &i32Value)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pNode)
|
|
{
|
|
if( RC_BAD( rc = GedPutINT( pPool, pNode, i32Value)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( ppRecord)
|
|
{
|
|
if( RC_BAD( rc = (*ppRecord)->setINT( pField, i32Value)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case HTD_TYPE_CONTEXT:
|
|
{
|
|
FLMUINT32 ui32Value;
|
|
|
|
if( pNode)
|
|
{
|
|
GedValTypeSet( pNode, FLM_CONTEXT_TYPE);
|
|
}
|
|
|
|
if( ppRecord)
|
|
{
|
|
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
|
|
ui16Tag, FLM_CONTEXT_TYPE, &pField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( !bHasValue)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/*
|
|
Read an unsigned 32-bit integer.
|
|
*/
|
|
|
|
if( RC_BAD( rc = readUInt( &ui32Value)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pNode)
|
|
{
|
|
if( RC_BAD( rc = GedPutRecPtr( pPool, pNode, ui32Value)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( ppRecord)
|
|
{
|
|
if( RC_BAD( rc = (*ppRecord)->setRecPointer( pField, ui32Value)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case HTD_TYPE_BINARY:
|
|
{
|
|
FLMUINT16 ui16DataSize;
|
|
FLMBYTE * pucData = NULL;
|
|
|
|
if( pNode)
|
|
{
|
|
GedValTypeSet( pNode, FLM_BINARY_TYPE);
|
|
}
|
|
|
|
if( ppRecord)
|
|
{
|
|
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
|
|
ui16Tag, FLM_BINARY_TYPE, &pField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( !bHasValue)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/*
|
|
Read a binary data stream.
|
|
*/
|
|
|
|
if( RC_BAD( rc = readUShort( &ui16DataSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pPool)
|
|
{
|
|
if( pNode)
|
|
{
|
|
if( (pucData = (FLMBYTE *)GedAllocSpace( pPool, pNode,
|
|
FLM_BINARY_TYPE, ui16DataSize)) == NULL)
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( ppRecord)
|
|
{
|
|
if( RC_BAD(rc = (*ppRecord)->allocStorageSpace( pField,
|
|
FLM_BINARY_TYPE, ui16DataSize, 0, 0, 0, &pucData, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = read( pucData, ui16DataSize, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pNode)
|
|
{
|
|
if( ppRecord)
|
|
{
|
|
if( RC_BAD( rc = (*ppRecord)->setBinary( pField, pucData, ui16DataSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = skip( ui16DataSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case HTD_TYPE_DATE:
|
|
{
|
|
rc = RC_SET( FERR_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
case HTD_TYPE_GEDCOM:
|
|
{
|
|
FLMBYTE ucGedType;
|
|
FLMUINT16 ui16DataSize;
|
|
FLMBYTE * pucData = NULL;
|
|
|
|
/*
|
|
Read the GEDCOM data type and flags
|
|
*/
|
|
|
|
if( RC_BAD( rc = read( &ucGedType, 1, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
ucFlags = ucGedType & 0xF0;
|
|
ucGedType &= 0x0F;
|
|
|
|
if( ucFlags & 0x10)
|
|
{
|
|
bLeftTruncated = TRUE;
|
|
}
|
|
|
|
if( ucFlags & 0x20)
|
|
{
|
|
bRightTruncated = TRUE;
|
|
}
|
|
|
|
if( ucGedType != FLM_TEXT_TYPE &&
|
|
ucGedType != FLM_NUMBER_TYPE &&
|
|
ucGedType != FLM_BINARY_TYPE &&
|
|
ucGedType != FLM_BLOB_TYPE &&
|
|
ucGedType != FLM_CONTEXT_TYPE)
|
|
{
|
|
rc = RC_SET( FERR_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
if( pNode)
|
|
{
|
|
GedValTypeSet( pNode, ucGedType);
|
|
if( bLeftTruncated)
|
|
{
|
|
GedSetLeftTruncated( pNode);
|
|
}
|
|
|
|
if( bRightTruncated)
|
|
{
|
|
GedSetRightTruncated( pNode);
|
|
}
|
|
}
|
|
|
|
if( ppRecord)
|
|
{
|
|
if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel,
|
|
ui16Tag, ucGedType, &pField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bLeftTruncated)
|
|
{
|
|
(*ppRecord)->setLeftTruncated( pField, TRUE);
|
|
}
|
|
|
|
if( bRightTruncated)
|
|
{
|
|
(*ppRecord)->setRightTruncated( pField, TRUE);
|
|
}
|
|
}
|
|
|
|
if( !bHasValue)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/*
|
|
Read the data size.
|
|
*/
|
|
|
|
if( RC_BAD( rc = readUShort( &ui16DataSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
Read the data value.
|
|
*/
|
|
|
|
if( pPool)
|
|
{
|
|
if( pNode)
|
|
{
|
|
if( (pucData = (FLMBYTE *)GedAllocSpace( pPool, pNode,
|
|
ucGedType, ui16DataSize)) == NULL)
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( ppRecord)
|
|
{
|
|
if (RC_BAD( rc = (*ppRecord)->allocStorageSpace( pField,
|
|
ucGedType, ui16DataSize, 0, 0, 0, &pucData, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = read( pucData, ui16DataSize, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pNode)
|
|
{
|
|
if( ppRecord)
|
|
{
|
|
if( RC_BAD( rc = (*ppRecord)->setBinary( pField, pucData, ui16DataSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = skip( ui16DataSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = RC_SET( FERR_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Set the truncation flags
|
|
*/
|
|
|
|
if( ucType != HTD_TYPE_GEDCOM)
|
|
{
|
|
if( pNode)
|
|
{
|
|
if( bLeftTruncated)
|
|
{
|
|
GedSetLeftTruncated( pNode);
|
|
}
|
|
|
|
if( bRightTruncated)
|
|
{
|
|
GedSetRightTruncated( pNode);
|
|
}
|
|
}
|
|
else if( pField)
|
|
{
|
|
if( bLeftTruncated)
|
|
{
|
|
(*ppRecord)->setLeftTruncated( pField, TRUE);
|
|
}
|
|
|
|
if( bRightTruncated)
|
|
{
|
|
(*ppRecord)->setRightTruncated( pField, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Graft the attribute into the tree.
|
|
*/
|
|
|
|
if( pNode)
|
|
{
|
|
if( pRoot == NULL)
|
|
{
|
|
pRoot = pNode;
|
|
}
|
|
else
|
|
{
|
|
if( bSibling)
|
|
{
|
|
pPrevNode->next = pNode;
|
|
pNode->prior = pPrevNode;
|
|
GedNodeLevelSet( pNode, GedNodeLevel( pPrevNode));
|
|
}
|
|
else if( bChild)
|
|
{
|
|
pPrevNode->next = pNode;
|
|
pNode->prior = pPrevNode;
|
|
GedNodeLevelSet( pNode, GedNodeLevel( pPrevNode) + 1);
|
|
}
|
|
else
|
|
{
|
|
pPrevNode->next = pNode;
|
|
pNode->prior = pPrevNode;
|
|
GedNodeLevelSet( pNode, ucLevel);
|
|
}
|
|
}
|
|
}
|
|
|
|
ucPrevLevel = ucLevel;
|
|
pPrevNode = pNode;
|
|
|
|
/*
|
|
Reset the pool if a GEDCOM record is not
|
|
going to be returned.
|
|
*/
|
|
|
|
if( pPool && !ppNode)
|
|
{
|
|
GedPoolReset( pPool, pvMark);
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_OK( rc))
|
|
{
|
|
if( ppNode)
|
|
{
|
|
*ppNode = pRoot;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( ppRecord && *ppRecord)
|
|
{
|
|
(*ppRecord)->Release();
|
|
}
|
|
}
|
|
|
|
if( pPool && !ppNode)
|
|
{
|
|
GedPoolReset( pPool, pvMark);
|
|
}
|
|
|
|
return( rc);
|
|
}
|