ultimatepp/bazaar/plugin/gdal/frmts/hfa/hfaentry.cpp
cxl 23ff1e7e82 .gdal moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2015-12-07 13:36:24 +00:00

1131 lines
39 KiB
C++

/******************************************************************************
* $Id: hfaentry.cpp 28275 2015-01-02 18:45:58Z rouault $
*
* Project: Erdas Imagine (.img) Translator
* Purpose: Implementation of the HFAEntry class for reading and relating
* one node in the HFA object tree structure.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Intergraph Corporation
* Copyright (c) 2008-2011, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* hfaentry.cpp
*
* Implementation of the HFAEntry class.
*
*/
#include "hfa_p.h"
#include "cpl_conv.h"
CPL_CVSID("$Id: hfaentry.cpp 28275 2015-01-02 18:45:58Z rouault $");
/************************************************************************/
/* HFAEntry() */
/************************************************************************/
HFAEntry::HFAEntry()
{
psHFA = NULL;
nFilePos = 0;
bDirty = FALSE;
bIsMIFObject = FALSE;
poParent = NULL;
poPrev = NULL;
poNext = poChild = NULL;
nDataPos = nDataSize = 0;
nNextPos = nChildPos = 0;
szName[0] = szType[0] = '\0';
pabyData = NULL;
poType = NULL;
}
/************************************************************************/
/* HFAEntry() */
/* */
/* Construct an HFAEntry from the source file. */
/************************************************************************/
HFAEntry* HFAEntry::New( HFAInfo_t * psHFAIn, GUInt32 nPos,
HFAEntry * poParentIn, HFAEntry * poPrevIn )
{
HFAEntry* poEntry = new HFAEntry;
poEntry->psHFA = psHFAIn;
poEntry->nFilePos = nPos;
poEntry->poParent = poParentIn;
poEntry->poPrev = poPrevIn;
/* -------------------------------------------------------------------- */
/* Read the entry information from the file. */
/* -------------------------------------------------------------------- */
GInt32 anEntryNums[6];
int i;
if( VSIFSeekL( poEntry->psHFA->fp, poEntry->nFilePos, SEEK_SET ) == -1
|| VSIFReadL( anEntryNums, sizeof(GInt32), 6, poEntry->psHFA->fp ) < 1 )
{
CPLError( CE_Failure, CPLE_FileIO,
"VSIFReadL(%p,6*4) @ %d failed in HFAEntry().\n%s",
poEntry->psHFA->fp, poEntry->nFilePos, VSIStrerror( errno ) );
delete poEntry;
return NULL;
}
for( i = 0; i < 6; i++ )
HFAStandard( 4, anEntryNums + i );
poEntry->nNextPos = anEntryNums[0];
poEntry->nChildPos = anEntryNums[3];
poEntry->nDataPos = anEntryNums[4];
poEntry->nDataSize = anEntryNums[5];
/* -------------------------------------------------------------------- */
/* Read the name, and type. */
/* -------------------------------------------------------------------- */
if( VSIFReadL( poEntry->szName, 1, 64, poEntry->psHFA->fp ) < 1
|| VSIFReadL( poEntry->szType, 1, 32, poEntry->psHFA->fp ) < 1 )
{
poEntry->szName[sizeof(poEntry->szName)-1] = '\0';
poEntry->szType[sizeof(poEntry->szType)-1] = '\0';
CPLError( CE_Failure, CPLE_FileIO,
"VSIFReadL() failed in HFAEntry()." );
delete poEntry;
return NULL;
}
poEntry->szName[sizeof(poEntry->szName)-1] = '\0';
poEntry->szType[sizeof(poEntry->szType)-1] = '\0';
return poEntry;
}
/************************************************************************/
/* HFAEntry() */
/* */
/* Construct an HFAEntry in memory, with the intention that it */
/* would be written to disk later. */
/************************************************************************/
HFAEntry::HFAEntry( HFAInfo_t * psHFAIn,
const char * pszNodeName,
const char * pszTypeName,
HFAEntry * poParentIn )
{
/* -------------------------------------------------------------------- */
/* Initialize Entry */
/* -------------------------------------------------------------------- */
psHFA = psHFAIn;
nFilePos = 0;
bIsMIFObject = FALSE;
poParent = poParentIn;
poPrev = poNext = poChild = NULL;
nDataPos = nDataSize = 0;
nNextPos = nChildPos = 0;
SetName( pszNodeName );
memset( szType, 0, sizeof(szType) );
strncpy( szType, pszTypeName, sizeof(szType) );
szType[sizeof(szType)-1] = '\0';
pabyData = NULL;
poType = NULL;
/* -------------------------------------------------------------------- */
/* Update the previous or parent node to refer to this one. */
/* -------------------------------------------------------------------- */
if( poParent == NULL )
{
/* do nothing */
}
else if( poParent->poChild == NULL )
{
poParent->poChild = this;
poParent->MarkDirty();
}
else
{
poPrev = poParent->poChild;
while( poPrev->poNext != NULL )
poPrev = poPrev->poNext;
poPrev->poNext = this;
poPrev->MarkDirty();
}
MarkDirty();
}
/************************************************************************/
/* BuildEntryFromMIFObject() */
/* */
/* Create a pseudo-HFAEntry wrapping a MIFObject. */
/************************************************************************/
HFAEntry* HFAEntry::BuildEntryFromMIFObject( HFAEntry *poContainer, const char *pszMIFObjectPath )
{
const char* pszField;
CPLString osFieldName;
osFieldName.Printf("%s.%s", pszMIFObjectPath, "MIFDictionary" );
pszField = poContainer->GetStringField( osFieldName.c_str() );
if (pszField == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s entry",
osFieldName.c_str());
return NULL;
}
CPLString osDictionnary = pszField;
osFieldName.Printf("%s.%s", pszMIFObjectPath, "type.string" );
pszField = poContainer->GetStringField( osFieldName.c_str() );
if (pszField == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s entry",
osFieldName.c_str());
return NULL;
}
CPLString osType = pszField;
osFieldName.Printf("%s.%s", pszMIFObjectPath, "MIFObject" );
int nRemainingDataSize = 0;
pszField = poContainer->GetStringField( osFieldName.c_str(),
NULL, &nRemainingDataSize );
if (pszField == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s entry",
osFieldName.c_str());
return NULL;
}
GInt32 nMIFObjectSize;
// we rudely look before the field data to get at the pointer/size info
memcpy( &nMIFObjectSize, pszField-8, 4 );
HFAStandard( 4, &nMIFObjectSize );
if (nMIFObjectSize <= 0)
{
CPLError(CE_Failure, CPLE_AppDefined, "Invalid MIF object size (%d)",
nMIFObjectSize);
return NULL;
}
// check that we won't copy more bytes than available in the buffer
if (nMIFObjectSize > nRemainingDataSize)
{
CPLError(CE_Failure, CPLE_AppDefined, "Invalid MIF object size (%d > %d)",
nMIFObjectSize, nRemainingDataSize);
return NULL;
}
GByte* pabyData = (GByte *) VSIMalloc(nMIFObjectSize);
if (pabyData == NULL)
return NULL;
memcpy( pabyData, pszField, nMIFObjectSize );
return new HFAEntry(poContainer, pszMIFObjectPath,
osDictionnary, osType,
nMIFObjectSize, pabyData);
}
/************************************************************************/
/* HFAEntry() */
/* */
/* Create a pseudo-HFAEntry wrapping a MIFObject. */
/************************************************************************/
HFAEntry::HFAEntry( CPL_UNUSED HFAEntry * poContainer,
CPL_UNUSED const char *pszMIFObjectPath,
const char * pszDictionnary,
const char * pszTypeName,
int nDataSizeIn,
GByte* pabyDataIn )
{
/* -------------------------------------------------------------------- */
/* Initialize Entry */
/* -------------------------------------------------------------------- */
nFilePos = 0;
poParent = poPrev = poNext = poChild = NULL;
bIsMIFObject = TRUE;
nDataPos = nDataSize = 0;
nNextPos = nChildPos = 0;
memset( szName, 0, sizeof(szName) );
/* -------------------------------------------------------------------- */
/* Create a dummy HFAInfo_t. */
/* -------------------------------------------------------------------- */
psHFA = (HFAInfo_t *) CPLCalloc(sizeof(HFAInfo_t),1);
psHFA->eAccess = HFA_ReadOnly;
psHFA->bTreeDirty = FALSE;
psHFA->poRoot = this;
psHFA->poDictionary = new HFADictionary( pszDictionnary );
/* -------------------------------------------------------------------- */
/* Work out the type for this MIFObject. */
/* -------------------------------------------------------------------- */
memset( szType, 0, sizeof(szType) );
strncpy( szType, pszTypeName, sizeof(szType) );
szType[sizeof(szType)-1] = '\0';
poType = psHFA->poDictionary->FindType( szType );
nDataSize = nDataSizeIn;
pabyData = pabyDataIn;
}
/************************************************************************/
/* ~HFAEntry() */
/* */
/* Ensure that children are cleaned up when this node is */
/* cleaned up. */
/************************************************************************/
HFAEntry::~HFAEntry()
{
CPLFree( pabyData );
if( poNext != NULL )
delete poNext;
if( poChild != NULL )
delete poChild;
if( bIsMIFObject )
{
delete psHFA->poDictionary;
CPLFree( psHFA );
}
}
/************************************************************************/
/* RemoveAndDestroy() */
/* */
/* Removes this entry, and it's children from the current */
/* tree. The parent and/or siblings are appropriately updated */
/* so that they will be flushed back to disk without the */
/* reference to this node. */
/************************************************************************/
CPLErr HFAEntry::RemoveAndDestroy()
{
if( poPrev != NULL )
{
poPrev->poNext = poNext;
if( poNext != NULL )
poPrev->nNextPos = poNext->nFilePos;
else
poPrev->nNextPos = 0;
poPrev->MarkDirty();
}
if( poParent != NULL && poParent->poChild == this )
{
poParent->poChild = poNext;
if( poNext )
poParent->nChildPos = poNext->nFilePos;
else
poParent->nChildPos = 0;
poParent->MarkDirty();
}
if( poNext != NULL )
{
poNext->poPrev = poPrev;
}
poNext = NULL;
poPrev = NULL;
poParent = NULL;
delete this;
return CE_None;
}
/************************************************************************/
/* SetName() */
/* */
/* Changes the name assigned to this node */
/************************************************************************/
void HFAEntry::SetName( const char *pszNodeName )
{
memset( szName, 0, sizeof(szName) );
strncpy( szName, pszNodeName, sizeof(szName) );
szName[sizeof(szName)-1] = '\0';
MarkDirty();
}
/************************************************************************/
/* GetChild() */
/************************************************************************/
HFAEntry *HFAEntry::GetChild()
{
/* -------------------------------------------------------------------- */
/* Do we need to create the child node? */
/* -------------------------------------------------------------------- */
if( poChild == NULL && nChildPos != 0 )
{
poChild = HFAEntry::New( psHFA, nChildPos, this, NULL );
if( poChild == NULL )
nChildPos = 0;
}
return( poChild );
}
/************************************************************************/
/* GetNext() */
/************************************************************************/
HFAEntry *HFAEntry::GetNext()
{
/* -------------------------------------------------------------------- */
/* Do we need to create the next node? */
/* -------------------------------------------------------------------- */
if( poNext == NULL && nNextPos != 0 )
{
// Check if we have a loop on the next node in this sibling chain.
HFAEntry *poPast;
for( poPast = this;
poPast != NULL && poPast->nFilePos != nNextPos;
poPast = poPast->poPrev ) {}
if( poPast != NULL )
{
CPLError( CE_Warning, CPLE_AppDefined,
"Corrupt (looping) entry in %s, ignoring some entries after %s.",
psHFA->pszFilename,
szName );
nNextPos = 0;
return NULL;
}
poNext = HFAEntry::New( psHFA, nNextPos, poParent, this );
if( poNext == NULL )
nNextPos = 0;
}
return( poNext );
}
/************************************************************************/
/* LoadData() */
/* */
/* Load the data for this entry, and build up the field */
/* information for it. */
/************************************************************************/
void HFAEntry::LoadData()
{
if( pabyData != NULL || nDataSize == 0 )
return;
/* -------------------------------------------------------------------- */
/* Allocate buffer, and read data. */
/* -------------------------------------------------------------------- */
pabyData = (GByte *) VSIMalloc(nDataSize + 1);
if (pabyData == NULL)
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"VSIMalloc() failed in HFAEntry::LoadData()." );
return;
}
if( VSIFSeekL( psHFA->fp, nDataPos, SEEK_SET ) < 0 )
{
CPLError( CE_Failure, CPLE_FileIO,
"VSIFSeekL() failed in HFAEntry::LoadData()." );
return;
}
if( VSIFReadL( pabyData, 1, nDataSize, psHFA->fp ) < 1 )
{
CPLError( CE_Failure, CPLE_FileIO,
"VSIFReadL() failed in HFAEntry::LoadData()." );
return;
}
/* Make sure the buffer is always null terminated to avoid */
/* issues when extracting strings from a corrupted file */
pabyData[nDataSize] = '\0';
/* -------------------------------------------------------------------- */
/* Get the type corresponding to this entry. */
/* -------------------------------------------------------------------- */
poType = psHFA->poDictionary->FindType( szType );
if( poType == NULL )
return;
}
/************************************************************************/
/* GetTypeObject() */
/************************************************************************/
HFAType *HFAEntry::GetTypeObject()
{
if( poType == NULL )
poType = psHFA->poDictionary->FindType( szType );
return poType;
}
/************************************************************************/
/* MakeData() */
/* */
/* Create a data block on the this HFAEntry in memory. By */
/* default it will create the data the correct size for fixed */
/* sized types, or do nothing for variable length types. */
/* However, the caller can supply a desired size for variable */
/* sized fields. */
/************************************************************************/
GByte *HFAEntry::MakeData( int nSize )
{
if( poType == NULL )
{
poType = psHFA->poDictionary->FindType( szType );
if( poType == NULL )
return NULL;
}
if( nSize == 0 && poType->nBytes > 0 )
nSize = poType->nBytes;
if( (int) nDataSize < nSize && nSize > 0 )
{
pabyData = (GByte *) CPLRealloc(pabyData, nSize);
memset( pabyData + nDataSize, 0, nSize - nDataSize );
nDataSize = nSize;
MarkDirty();
/* -------------------------------------------------------------------- */
/* If the data already had a file position, we now need to */
/* clear that, forcing it to be rewritten at the end of the */
/* file. Referencing nodes will need to be marked dirty so */
/* they are rewritten. */
/* -------------------------------------------------------------------- */
if( nFilePos != 0 )
{
nFilePos = 0;
nDataPos = 0;
if (poPrev != NULL) poPrev->MarkDirty();
if (poNext != NULL) poNext->MarkDirty();
if (poChild != NULL) poChild->MarkDirty();
if (poParent != NULL) poParent->MarkDirty();
}
}
else
LoadData(); // make sure the data is loaded before we return pointer.
return pabyData;
}
/************************************************************************/
/* DumpFieldValues() */
/************************************************************************/
void HFAEntry::DumpFieldValues( FILE * fp, const char * pszPrefix )
{
if( pszPrefix == NULL )
pszPrefix = "";
LoadData();
if( pabyData == NULL || poType == NULL )
return;
poType->DumpInstValue( fp,
pabyData, nDataPos, nDataSize,
pszPrefix );
}
/************************************************************************/
/* FindChildren() */
/* */
/* Find all the children of the current node that match the */
/* name and type provided. Either may be NULL if it is not a */
/* factor. The pszName should be just the node name, not a */
/* path. */
/************************************************************************/
std::vector<HFAEntry*> HFAEntry::FindChildren( const char *pszName,
const char *pszType,
int nRecLevel,
int* pbErrorDetected )
{
std::vector<HFAEntry*> apoChildren;
HFAEntry *poEntry;
if( *pbErrorDetected )
return apoChildren;
if( nRecLevel == 50 )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Bad entry structure: recursion detected !");
*pbErrorDetected = TRUE;
return apoChildren;
}
for( poEntry = GetChild(); poEntry != NULL; poEntry = poEntry->GetNext() )
{
std::vector<HFAEntry*> apoEntryChildren;
size_t i;
if( (pszName == NULL || EQUAL(poEntry->GetName(),pszName))
&& (pszType == NULL || EQUAL(poEntry->GetType(),pszType)) )
apoChildren.push_back( poEntry );
apoEntryChildren = poEntry->FindChildren( pszName, pszType, nRecLevel + 1,
pbErrorDetected);
if( *pbErrorDetected )
return apoChildren;
for( i = 0; i < apoEntryChildren.size(); i++ )
apoChildren.push_back( apoEntryChildren[i] );
}
return apoChildren;
}
std::vector<HFAEntry*> HFAEntry::FindChildren( const char *pszName,
const char *pszType)
{
int bErrorDetected = FALSE;
return FindChildren(pszName, pszType, 0, &bErrorDetected);
}
/************************************************************************/
/* GetNamedChild() */
/************************************************************************/
HFAEntry *HFAEntry::GetNamedChild( const char * pszName )
{
int nNameLen;
HFAEntry *poEntry;
/* -------------------------------------------------------------------- */
/* Establish how much of this name path is for the next child. */
/* Up to the '.' or end of estring. */
/* -------------------------------------------------------------------- */
for( nNameLen = 0;
pszName[nNameLen] != '.'
&& pszName[nNameLen] != '\0'
&& pszName[nNameLen] != ':';
nNameLen++ ) {}
/* -------------------------------------------------------------------- */
/* Scan children looking for this name. */
/* -------------------------------------------------------------------- */
for( poEntry = GetChild(); poEntry != NULL; poEntry = poEntry->GetNext() )
{
if( EQUALN(poEntry->GetName(),pszName,nNameLen)
&& (int) strlen(poEntry->GetName()) == nNameLen )
{
if( pszName[nNameLen] == '.' )
{
HFAEntry *poResult;
poResult = poEntry->GetNamedChild( pszName+nNameLen+1 );
if( poResult != NULL )
return poResult;
}
else
return poEntry;
}
}
return NULL;
}
/************************************************************************/
/* GetFieldValue() */
/************************************************************************/
int HFAEntry::GetFieldValue( const char * pszFieldPath,
char chReqType, void *pReqReturn,
int *pnRemainingDataSize)
{
HFAEntry *poEntry = this;
/* -------------------------------------------------------------------- */
/* Is there a node path in this string? */
/* -------------------------------------------------------------------- */
if( strchr(pszFieldPath,':') != NULL )
{
poEntry = GetNamedChild( pszFieldPath );
if( poEntry == NULL )
return FALSE;
pszFieldPath = strchr(pszFieldPath,':') + 1;
}
/* -------------------------------------------------------------------- */
/* Do we have the data and type for this node? */
/* -------------------------------------------------------------------- */
LoadData();
if( pabyData == NULL )
return FALSE;
if( poType == NULL )
return FALSE;
/* -------------------------------------------------------------------- */
/* Extract the instance information. */
/* -------------------------------------------------------------------- */
return( poType->ExtractInstValue( pszFieldPath,
pabyData, nDataPos, nDataSize,
chReqType, pReqReturn, pnRemainingDataSize ) );
}
/************************************************************************/
/* GetFieldCount() */
/************************************************************************/
int HFAEntry::GetFieldCount( const char * pszFieldPath, CPL_UNUSED CPLErr *peErr )
{
HFAEntry *poEntry = this;
/* -------------------------------------------------------------------- */
/* Is there a node path in this string? */
/* -------------------------------------------------------------------- */
if( strchr(pszFieldPath,':') != NULL )
{
poEntry = GetNamedChild( pszFieldPath );
if( poEntry == NULL )
return -1;
pszFieldPath = strchr(pszFieldPath,':') + 1;
}
/* -------------------------------------------------------------------- */
/* Do we have the data and type for this node? */
/* -------------------------------------------------------------------- */
LoadData();
if( pabyData == NULL )
return -1;
if( poType == NULL )
return -1;
/* -------------------------------------------------------------------- */
/* Extract the instance information. */
/* -------------------------------------------------------------------- */
return( poType->GetInstCount( pszFieldPath,
pabyData, nDataPos, nDataSize ) );
}
/************************************************************************/
/* GetIntField() */
/************************************************************************/
GInt32 HFAEntry::GetIntField( const char * pszFieldPath, CPLErr *peErr )
{
GInt32 nIntValue;
if( !GetFieldValue( pszFieldPath, 'i', &nIntValue, NULL ) )
{
if( peErr != NULL )
*peErr = CE_Failure;
return 0;
}
else
{
if( peErr != NULL )
*peErr = CE_None;
return nIntValue;
}
}
/************************************************************************/
/* GetBigIntField() */
/* */
/* This is just a helper method that reads two ULONG array */
/* entries as a GBigInt. The passed name should be the name of */
/* the array with no array index. Array indexes 0 and 1 will */
/* be concatenated. */
/************************************************************************/
GIntBig HFAEntry::GetBigIntField( const char *pszFieldPath, CPLErr *peErr )
{
GUInt32 nLower, nUpper;
char szFullFieldPath[1024];
sprintf( szFullFieldPath, "%s[0]", pszFieldPath );
nLower = GetIntField( szFullFieldPath, peErr );
if( peErr != NULL && *peErr != CE_None )
return 0;
sprintf( szFullFieldPath, "%s[1]", pszFieldPath );
nUpper = GetIntField( szFullFieldPath, peErr );
if( peErr != NULL && *peErr != CE_None )
return 0;
return nLower + (((GIntBig) nUpper) << 32);
}
/************************************************************************/
/* GetDoubleField() */
/************************************************************************/
double HFAEntry::GetDoubleField( const char * pszFieldPath, CPLErr *peErr )
{
double dfDoubleValue;
if( !GetFieldValue( pszFieldPath, 'd', &dfDoubleValue, NULL ) )
{
if( peErr != NULL )
*peErr = CE_Failure;
return 0.0;
}
else
{
if( peErr != NULL )
*peErr = CE_None;
return dfDoubleValue;
}
}
/************************************************************************/
/* GetStringField() */
/************************************************************************/
const char *HFAEntry::GetStringField( const char * pszFieldPath, CPLErr *peErr,
int *pnRemainingDataSize)
{
char *pszResult = NULL;
if( !GetFieldValue( pszFieldPath, 's', &pszResult, pnRemainingDataSize ) )
{
if( peErr != NULL )
*peErr = CE_Failure;
return NULL;
}
else
{
if( peErr != NULL )
*peErr = CE_None;
return pszResult;
}
}
/************************************************************************/
/* SetFieldValue() */
/************************************************************************/
CPLErr HFAEntry::SetFieldValue( const char * pszFieldPath,
char chReqType, void *pValue )
{
HFAEntry *poEntry = this;
/* -------------------------------------------------------------------- */
/* Is there a node path in this string? */
/* -------------------------------------------------------------------- */
if( strchr(pszFieldPath,':') != NULL )
{
poEntry = GetNamedChild( pszFieldPath );
if( poEntry == NULL )
return CE_Failure;
pszFieldPath = strchr(pszFieldPath,':') + 1;
}
/* -------------------------------------------------------------------- */
/* Do we have the data and type for this node? Try loading */
/* from a file, or instantiating a new node. */
/* -------------------------------------------------------------------- */
LoadData();
if( MakeData() == NULL
|| pabyData == NULL
|| poType == NULL )
{
CPLAssert( FALSE );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Extract the instance information. */
/* -------------------------------------------------------------------- */
MarkDirty();
return( poType->SetInstValue( pszFieldPath,
pabyData, nDataPos, nDataSize,
chReqType, pValue ) );
}
/************************************************************************/
/* SetStringField() */
/************************************************************************/
CPLErr HFAEntry::SetStringField( const char * pszFieldPath,
const char * pszValue )
{
return SetFieldValue( pszFieldPath, 's', (void *) pszValue );
}
/************************************************************************/
/* SetIntField() */
/************************************************************************/
CPLErr HFAEntry::SetIntField( const char * pszFieldPath, int nValue )
{
return SetFieldValue( pszFieldPath, 'i', &nValue );
}
/************************************************************************/
/* SetDoubleField() */
/************************************************************************/
CPLErr HFAEntry::SetDoubleField( const char * pszFieldPath,
double dfValue )
{
return SetFieldValue( pszFieldPath, 'd', &dfValue );
}
/************************************************************************/
/* SetPosition() */
/* */
/* Set the disk position for this entry, and recursively apply */
/* to any children of this node. The parent will take care of */
/* our siblings. */
/************************************************************************/
void HFAEntry::SetPosition()
{
/* -------------------------------------------------------------------- */
/* Establish the location of this entry, and it's data. */
/* -------------------------------------------------------------------- */
if( nFilePos == 0 )
{
nFilePos = HFAAllocateSpace( psHFA,
psHFA->nEntryHeaderLength
+ nDataSize );
if( nDataSize > 0 )
nDataPos = nFilePos + psHFA->nEntryHeaderLength;
}
/* -------------------------------------------------------------------- */
/* Force all children to set their position. */
/* -------------------------------------------------------------------- */
for( HFAEntry *poThisChild = poChild;
poThisChild != NULL;
poThisChild = poThisChild->poNext )
{
poThisChild->SetPosition();
}
}
/************************************************************************/
/* FlushToDisk() */
/* */
/* Write this entry, and it's data to disk if the entries */
/* information is dirty. Also force children to do the same. */
/************************************************************************/
CPLErr HFAEntry::FlushToDisk()
{
CPLErr eErr = CE_None;
/* -------------------------------------------------------------------- */
/* If we are the root node, call SetPosition() on the whole */
/* tree to ensure that all entries have an allocated position. */
/* -------------------------------------------------------------------- */
if( poParent == NULL )
SetPosition();
/* ==================================================================== */
/* Only write this node out if it is dirty. */
/* ==================================================================== */
if( bDirty )
{
/* -------------------------------------------------------------------- */
/* Ensure we know where the relative entries are located. */
/* -------------------------------------------------------------------- */
if( poNext != NULL )
nNextPos = poNext->nFilePos;
if( poChild != NULL )
nChildPos = poChild->nFilePos;
/* -------------------------------------------------------------------- */
/* Write the Ehfa_Entry fields. */
/* -------------------------------------------------------------------- */
GUInt32 nLong;
//VSIFFlushL( psHFA->fp );
if( VSIFSeekL( psHFA->fp, nFilePos, SEEK_SET ) != 0 )
{
CPLError( CE_Failure, CPLE_FileIO,
"Failed to seek to %d for writing, out of disk space?",
nFilePos );
return CE_Failure;
}
nLong = nNextPos;
HFAStandard( 4, &nLong );
VSIFWriteL( &nLong, 4, 1, psHFA->fp );
if( poPrev != NULL )
nLong = poPrev->nFilePos;
else
nLong = 0;
HFAStandard( 4, &nLong );
VSIFWriteL( &nLong, 4, 1, psHFA->fp );
if( poParent != NULL )
nLong = poParent->nFilePos;
else
nLong = 0;
HFAStandard( 4, &nLong );
VSIFWriteL( &nLong, 4, 1, psHFA->fp );
nLong = nChildPos;
HFAStandard( 4, &nLong );
VSIFWriteL( &nLong, 4, 1, psHFA->fp );
nLong = nDataPos;
HFAStandard( 4, &nLong );
VSIFWriteL( &nLong, 4, 1, psHFA->fp );
nLong = nDataSize;
HFAStandard( 4, &nLong );
VSIFWriteL( &nLong, 4, 1, psHFA->fp );
VSIFWriteL( szName, 1, 64, psHFA->fp );
VSIFWriteL( szType, 1, 32, psHFA->fp );
nLong = 0; /* Should we keep the time, or set it more reasonably? */
if( VSIFWriteL( &nLong, 4, 1, psHFA->fp ) != 1 )
{
CPLError( CE_Failure, CPLE_FileIO,
"Failed to write HFAEntry %s(%s), out of disk space?",
szName, szType );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Write out the data. */
/* -------------------------------------------------------------------- */
//VSIFFlushL( psHFA->fp );
if( nDataSize > 0 && pabyData != NULL )
{
if( VSIFSeekL( psHFA->fp, nDataPos, SEEK_SET ) != 0
|| VSIFWriteL( pabyData, nDataSize, 1, psHFA->fp ) != 1 )
{
CPLError( CE_Failure, CPLE_FileIO,
"Failed to write %d bytes HFAEntry %s(%s) data,\n"
"out of disk space?",
nDataSize, szName, szType );
return CE_Failure;
}
}
//VSIFFlushL( psHFA->fp );
}
/* -------------------------------------------------------------------- */
/* Process all the children of this node */
/* -------------------------------------------------------------------- */
for( HFAEntry *poThisChild = poChild;
poThisChild != NULL;
poThisChild = poThisChild->poNext )
{
eErr = poThisChild->FlushToDisk();
if( eErr != CE_None )
return eErr;
}
bDirty = FALSE;
return CE_None;
}
/************************************************************************/
/* MarkDirty() */
/* */
/* Mark this node as dirty (in need of writing to disk), and */
/* also mark the tree as a whole as being dirty. */
/************************************************************************/
void HFAEntry::MarkDirty()
{
bDirty = TRUE;
psHFA->bTreeDirty = TRUE;
}