mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-19 14:15:21 -06:00
1593 lines
50 KiB
C++
1593 lines
50 KiB
C++
/******************************************************************************
|
|
* $Id: hfafield.cpp 27942 2014-11-11 00:57:41Z rouault $
|
|
*
|
|
* Project: Erdas Imagine (.img) Translator
|
|
* Purpose: Implementation of the HFAField class for managing information
|
|
* about one field in a HFA dictionary type. Managed by HFAType.
|
|
* Author: Frank Warmerdam, warmerdam@pobox.com
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 1999, Intergraph Corporation
|
|
* Copyright (c) 2009-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.
|
|
****************************************************************************/
|
|
|
|
#include "hfa_p.h"
|
|
|
|
CPL_CVSID("$Id: hfafield.cpp 27942 2014-11-11 00:57:41Z rouault $");
|
|
|
|
#define MAX_ENTRY_REPORT 16
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* HFAField */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
/************************************************************************/
|
|
/* HFAField() */
|
|
/************************************************************************/
|
|
|
|
HFAField::HFAField()
|
|
|
|
{
|
|
nBytes = 0;
|
|
|
|
nItemCount = 0;
|
|
chPointer = '\0';
|
|
chItemType = '\0';
|
|
|
|
pszItemObjectType = NULL;
|
|
poItemObjectType = NULL;
|
|
|
|
papszEnumNames = NULL;
|
|
|
|
pszFieldName = NULL;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~HFAField() */
|
|
/************************************************************************/
|
|
|
|
HFAField::~HFAField()
|
|
|
|
{
|
|
CPLFree( pszItemObjectType );
|
|
CSLDestroy( papszEnumNames );
|
|
CPLFree( pszFieldName );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Initialize() */
|
|
/************************************************************************/
|
|
|
|
const char *HFAField::Initialize( const char * pszInput )
|
|
|
|
{
|
|
int i;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Read the number. */
|
|
/* -------------------------------------------------------------------- */
|
|
nItemCount = atoi(pszInput);
|
|
|
|
while( *pszInput != '\0' && *pszInput != ':' )
|
|
pszInput++;
|
|
|
|
if( *pszInput == '\0' )
|
|
return NULL;
|
|
|
|
pszInput++;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Is this a pointer? */
|
|
/* -------------------------------------------------------------------- */
|
|
if( *pszInput == 'p' || *pszInput == '*' )
|
|
chPointer = *(pszInput++);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Get the general type */
|
|
/* -------------------------------------------------------------------- */
|
|
if( *pszInput == '\0' )
|
|
return NULL;
|
|
|
|
chItemType = *(pszInput++);
|
|
|
|
if ( strchr( "124cCesStlLfdmMbox", chItemType) == NULL )
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"Unrecognized item type : %c", chItemType);
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* If this is an object, we extract the type of the object. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( chItemType == 'o' )
|
|
{
|
|
for( i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++ ) {}
|
|
if (pszInput[i] == '\0')
|
|
return NULL;
|
|
|
|
pszItemObjectType = (char *) CPLMalloc(i+1);
|
|
strncpy( pszItemObjectType, pszInput, i );
|
|
pszItemObjectType[i] = '\0';
|
|
|
|
pszInput += i+1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* If this is an inline object, we need to skip past the */
|
|
/* definition, and then extract the object class name. */
|
|
/* */
|
|
/* We ignore the actual definition, so if the object type isn't */
|
|
/* already defined, things will not work properly. See the */
|
|
/* file lceugr250_00_pct.aux for an example of inline defs. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( chItemType == 'x' && *pszInput == '{' )
|
|
{
|
|
int nBraceDepth = 1;
|
|
pszInput++;
|
|
|
|
// Skip past the definition.
|
|
while( nBraceDepth > 0 && *pszInput != '\0' )
|
|
{
|
|
if( *pszInput == '{' )
|
|
nBraceDepth++;
|
|
else if( *pszInput == '}' )
|
|
nBraceDepth--;
|
|
|
|
pszInput++;
|
|
}
|
|
if (*pszInput == '\0')
|
|
return NULL;
|
|
|
|
chItemType = 'o';
|
|
|
|
// find the comma terminating the type name.
|
|
for( i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++ ) {}
|
|
if (pszInput[i] == '\0')
|
|
return NULL;
|
|
|
|
pszItemObjectType = (char *) CPLMalloc(i+1);
|
|
strncpy( pszItemObjectType, pszInput, i );
|
|
pszItemObjectType[i] = '\0';
|
|
|
|
pszInput += i+1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* If this is an enumeration we have to extract all the */
|
|
/* enumeration values. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( chItemType == 'e' )
|
|
{
|
|
int nEnumCount = atoi(pszInput);
|
|
int iEnum;
|
|
|
|
if (nEnumCount < 0 || nEnumCount > 100000)
|
|
return NULL;
|
|
|
|
pszInput = strchr(pszInput,':');
|
|
if( pszInput == NULL )
|
|
return NULL;
|
|
|
|
pszInput++;
|
|
|
|
papszEnumNames = (char **) VSICalloc(sizeof(char *), nEnumCount+1);
|
|
if (papszEnumNames == NULL)
|
|
return NULL;
|
|
|
|
for( iEnum = 0; iEnum < nEnumCount; iEnum++ )
|
|
{
|
|
char *pszToken;
|
|
|
|
for( i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++ ) {}
|
|
|
|
if( pszInput[i] != ',' )
|
|
return NULL;
|
|
|
|
pszToken = (char *) CPLMalloc(i+1);
|
|
strncpy( pszToken, pszInput, i );
|
|
pszToken[i] = '\0';
|
|
|
|
papszEnumNames[iEnum] = pszToken;
|
|
|
|
pszInput += i+1;
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Extract the field name. */
|
|
/* -------------------------------------------------------------------- */
|
|
for( i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++ ) {}
|
|
if (pszInput[i] == '\0')
|
|
return NULL;
|
|
|
|
pszFieldName = (char *) CPLMalloc(i+1);
|
|
strncpy( pszFieldName, pszInput, i );
|
|
pszFieldName[i] = '\0';
|
|
|
|
pszInput += i+1;
|
|
|
|
return( pszInput );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CompleteDefn() */
|
|
/* */
|
|
/* Establish size, and pointers to component types. */
|
|
/************************************************************************/
|
|
|
|
void HFAField::CompleteDefn( HFADictionary * poDict )
|
|
|
|
{
|
|
/* -------------------------------------------------------------------- */
|
|
/* Get a reference to the type object if we have a type name */
|
|
/* for this field (not a built in). */
|
|
/* -------------------------------------------------------------------- */
|
|
if( pszItemObjectType != NULL )
|
|
poItemObjectType = poDict->FindType( pszItemObjectType );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Figure out the size. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( chPointer == 'p' )
|
|
{
|
|
nBytes = -1; /* we can't know the instance size */
|
|
}
|
|
else if( poItemObjectType != NULL )
|
|
{
|
|
poItemObjectType->CompleteDefn( poDict );
|
|
if( poItemObjectType->nBytes == -1 )
|
|
nBytes = -1;
|
|
else
|
|
nBytes = poItemObjectType->nBytes * nItemCount;
|
|
|
|
if( chPointer == '*' && nBytes != -1 )
|
|
nBytes += 8; /* count, and offset */
|
|
}
|
|
else
|
|
{
|
|
nBytes = poDict->GetItemSize( chItemType ) * nItemCount;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Dump() */
|
|
/************************************************************************/
|
|
|
|
void HFAField::Dump( FILE * fp )
|
|
|
|
{
|
|
const char *pszTypeName;
|
|
|
|
switch( chItemType )
|
|
{
|
|
case '1':
|
|
pszTypeName = "U1";
|
|
break;
|
|
|
|
case '2':
|
|
pszTypeName = "U2";
|
|
break;
|
|
|
|
case '4':
|
|
pszTypeName = "U4";
|
|
break;
|
|
|
|
case 'c':
|
|
pszTypeName = "UCHAR";
|
|
break;
|
|
|
|
case 'C':
|
|
pszTypeName = "CHAR";
|
|
break;
|
|
|
|
case 'e':
|
|
pszTypeName = "ENUM";
|
|
break;
|
|
|
|
case 's':
|
|
pszTypeName = "USHORT";
|
|
break;
|
|
|
|
case 'S':
|
|
pszTypeName = "SHORT";
|
|
break;
|
|
|
|
case 't':
|
|
pszTypeName = "TIME";
|
|
break;
|
|
|
|
case 'l':
|
|
pszTypeName = "ULONG";
|
|
break;
|
|
|
|
case 'L':
|
|
pszTypeName = "LONG";
|
|
break;
|
|
|
|
case 'f':
|
|
pszTypeName = "FLOAT";
|
|
break;
|
|
|
|
case 'd':
|
|
pszTypeName = "DOUBLE";
|
|
break;
|
|
|
|
case 'm':
|
|
pszTypeName = "COMPLEX";
|
|
break;
|
|
|
|
case 'M':
|
|
pszTypeName = "DCOMPLEX";
|
|
break;
|
|
|
|
case 'b':
|
|
pszTypeName = "BASEDATA";
|
|
break;
|
|
|
|
case 'o':
|
|
pszTypeName = pszItemObjectType;
|
|
break;
|
|
|
|
case 'x':
|
|
pszTypeName = "InlineType";
|
|
break;
|
|
|
|
default:
|
|
CPLAssert( FALSE );
|
|
pszTypeName = "Unknown";
|
|
}
|
|
|
|
VSIFPrintf( fp, " %-19s %c %s[%d];\n",
|
|
pszTypeName,
|
|
chPointer ? chPointer : ' ',
|
|
pszFieldName, nItemCount );
|
|
|
|
if( papszEnumNames != NULL )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; papszEnumNames[i] != NULL; i++ )
|
|
{
|
|
VSIFPrintf( fp, " %s=%d\n",
|
|
papszEnumNames[i], i );
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetInstValue() */
|
|
/************************************************************************/
|
|
|
|
CPLErr
|
|
HFAField::SetInstValue( const char * pszField, int nIndexValue,
|
|
GByte *pabyData, GUInt32 nDataOffset, int nDataSize,
|
|
char chReqType, void *pValue )
|
|
|
|
{
|
|
/* -------------------------------------------------------------------- */
|
|
/* If this field contains a pointer, then we will adjust the */
|
|
/* data offset relative to it. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( chPointer != '\0' )
|
|
{
|
|
GUInt32 nCount;
|
|
GUInt32 nOffset;
|
|
|
|
/* set the count for fixed sized arrays */
|
|
if( nBytes > -1 )
|
|
nCount = nItemCount;
|
|
|
|
// The count returned for BASEDATA's are the contents,
|
|
// but here we really want to mark it as one BASEDATA instance
|
|
// (see #2144)
|
|
if( chItemType == 'b' )
|
|
nCount = 1;
|
|
|
|
/* Set the size from string length */
|
|
else if( chReqType == 's' && (chItemType == 'c' || chItemType == 'C'))
|
|
{
|
|
if( pValue == NULL )
|
|
nCount = 0;
|
|
else
|
|
nCount = strlen((char *) pValue) + 1;
|
|
}
|
|
|
|
/* set size based on index ... assumes in-order setting of array */
|
|
else
|
|
nCount = nIndexValue+1;
|
|
|
|
if( (int) nCount + 8 > nDataSize )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to extend field %s in node past end of data,\n"
|
|
"not currently supported.",
|
|
pszField );
|
|
return CE_Failure;
|
|
}
|
|
|
|
// we will update the object count iff we are writing beyond the end
|
|
memcpy( &nOffset, pabyData, 4 );
|
|
HFAStandard( 4, &nOffset );
|
|
if( nOffset < nCount )
|
|
{
|
|
nOffset = nCount;
|
|
HFAStandard( 4, &nOffset );
|
|
memcpy( pabyData, &nOffset, 4 );
|
|
}
|
|
|
|
if( pValue == NULL )
|
|
nOffset = 0;
|
|
else
|
|
nOffset = nDataOffset + 8;
|
|
HFAStandard( 4, &nOffset );
|
|
memcpy( pabyData+4, &nOffset, 4 );
|
|
|
|
pabyData += 8;
|
|
|
|
nDataOffset += 8;
|
|
nDataSize -= 8;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* pointers to char or uchar arrays requested as strings are */
|
|
/* handled as a special case. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( (chItemType == 'c' || chItemType == 'C') && chReqType == 's' )
|
|
{
|
|
int nBytesToCopy;
|
|
|
|
if( nBytes == -1 )
|
|
{
|
|
if( pValue == NULL )
|
|
nBytesToCopy = 0;
|
|
else
|
|
nBytesToCopy = strlen((char *) pValue) + 1;
|
|
}
|
|
else
|
|
nBytesToCopy = nBytes;
|
|
|
|
if( nBytesToCopy > nDataSize )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to extend field %s in node past end of data,\n"
|
|
"not currently supported.",
|
|
pszField );
|
|
return CE_Failure;
|
|
}
|
|
|
|
memset( pabyData, 0, nBytesToCopy );
|
|
|
|
if( pValue != NULL )
|
|
strncpy( (char *) pabyData, (char *) pValue, nBytesToCopy );
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Translate the passed type into different representations. */
|
|
/* -------------------------------------------------------------------- */
|
|
int nIntValue;
|
|
double dfDoubleValue;
|
|
|
|
if( chReqType == 's' )
|
|
{
|
|
nIntValue = atoi((char *) pValue);
|
|
dfDoubleValue = CPLAtof((char *) pValue);
|
|
}
|
|
else if( chReqType == 'd' )
|
|
{
|
|
dfDoubleValue = *((double *) pValue);
|
|
if( dfDoubleValue > INT_MAX )
|
|
nIntValue = INT_MAX;
|
|
else if( dfDoubleValue < INT_MIN )
|
|
nIntValue = INT_MIN;
|
|
else
|
|
nIntValue = (int) dfDoubleValue;
|
|
}
|
|
else if( chReqType == 'i' )
|
|
{
|
|
dfDoubleValue = *((int *) pValue);
|
|
nIntValue = *((int *) pValue);
|
|
}
|
|
else if( chReqType == 'p' )
|
|
{
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"HFAField::SetInstValue() not supported yet for pointer values." );
|
|
|
|
return CE_Failure;
|
|
}
|
|
else
|
|
{
|
|
CPLAssert( FALSE );
|
|
return CE_Failure;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Handle by type. */
|
|
/* -------------------------------------------------------------------- */
|
|
switch( chItemType )
|
|
{
|
|
case 'c':
|
|
case 'C':
|
|
if( nIndexValue + 1 > nDataSize )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to extend field %s in node past end of data,\n"
|
|
"not currently supported.",
|
|
pszField );
|
|
return CE_Failure;
|
|
}
|
|
|
|
if( chReqType == 's' )
|
|
pabyData[nIndexValue] = ((char *) pValue)[0];
|
|
else
|
|
pabyData[nIndexValue] = (char) nIntValue;
|
|
break;
|
|
|
|
case 'e':
|
|
case 's':
|
|
{
|
|
if( chItemType == 'e' && chReqType == 's' )
|
|
{
|
|
nIntValue = CSLFindString( papszEnumNames, (char *) pValue );
|
|
if( nIntValue == -1 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to set enumerated field with unknown"
|
|
" value `%s'.",
|
|
(char *) pValue );
|
|
return CE_Failure;
|
|
}
|
|
}
|
|
|
|
unsigned short nNumber = (unsigned short) nIntValue;
|
|
|
|
if( nIndexValue*2 + 2 > nDataSize )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to extend field %s in node past end of data,\n"
|
|
"not currently supported.",
|
|
pszField );
|
|
return CE_Failure;
|
|
}
|
|
|
|
HFAStandard( 2, &nNumber );
|
|
memcpy( pabyData + nIndexValue*2, &nNumber, 2 );
|
|
}
|
|
break;
|
|
|
|
case 'S':
|
|
{
|
|
short nNumber;
|
|
|
|
if( nIndexValue*2 + 2 > nDataSize )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to extend field %s in node past end of data,\n"
|
|
"not currently supported.",
|
|
pszField );
|
|
return CE_Failure;
|
|
}
|
|
|
|
nNumber = (short) nIntValue;
|
|
HFAStandard( 2, &nNumber );
|
|
memcpy( pabyData + nIndexValue*2, &nNumber, 2 );
|
|
}
|
|
break;
|
|
|
|
case 't':
|
|
case 'l':
|
|
{
|
|
GUInt32 nNumber = nIntValue;
|
|
|
|
if( nIndexValue*4 + 4 > nDataSize )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to extend field %s in node past end of data,\n"
|
|
"not currently supported.",
|
|
pszField );
|
|
return CE_Failure;
|
|
}
|
|
|
|
HFAStandard( 4, &nNumber );
|
|
memcpy( pabyData + nIndexValue*4, &nNumber, 4 );
|
|
}
|
|
break;
|
|
|
|
case 'L':
|
|
{
|
|
GInt32 nNumber = nIntValue;
|
|
|
|
if( nIndexValue*4 + 4 > nDataSize )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to extend field %s in node past end of data,\n"
|
|
"not currently supported.",
|
|
pszField );
|
|
return CE_Failure;
|
|
}
|
|
|
|
HFAStandard( 4, &nNumber );
|
|
memcpy( pabyData + nIndexValue*4, &nNumber, 4 );
|
|
}
|
|
break;
|
|
|
|
case 'f':
|
|
{
|
|
float fNumber = (float) dfDoubleValue;
|
|
|
|
if( nIndexValue*4 + 4 > nDataSize )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to extend field %s in node past end of data,\n"
|
|
"not currently supported.",
|
|
pszField );
|
|
return CE_Failure;
|
|
}
|
|
|
|
HFAStandard( 4, &fNumber );
|
|
memcpy( pabyData + nIndexValue*4, &fNumber, 4 );
|
|
}
|
|
break;
|
|
|
|
case 'd':
|
|
{
|
|
double dfNumber = dfDoubleValue;
|
|
|
|
if( nIndexValue*8 + 8 > nDataSize )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to extend field %s in node past end of data,\n"
|
|
"not currently supported.",
|
|
pszField );
|
|
return CE_Failure;
|
|
}
|
|
|
|
HFAStandard( 8, &dfNumber );
|
|
memcpy( pabyData + nIndexValue*8, &dfNumber, 8 );
|
|
}
|
|
break;
|
|
|
|
case 'b':
|
|
{
|
|
GInt32 nRows = 1;
|
|
GInt32 nColumns = 1;
|
|
GInt16 nBaseItemType;
|
|
|
|
// Extract existing rows, columns, and datatype.
|
|
memcpy( &nRows, pabyData, 4 );
|
|
HFAStandard( 4, &nRows );
|
|
memcpy( &nColumns, pabyData+4, 4 );
|
|
HFAStandard( 4, &nColumns );
|
|
memcpy( &nBaseItemType, pabyData+8, 2 );
|
|
HFAStandard( 2, &nBaseItemType );
|
|
|
|
// Are we using special index values to update the rows, columnrs
|
|
// or type?
|
|
|
|
if( nIndexValue == -3 )
|
|
nBaseItemType = (GInt16) nIntValue;
|
|
else if( nIndexValue == -2 )
|
|
nColumns = nIntValue;
|
|
else if( nIndexValue == -1 )
|
|
nRows = nIntValue;
|
|
|
|
if( nIndexValue < -3 || nIndexValue >= nRows * nColumns )
|
|
return CE_Failure;
|
|
|
|
// Write back the rows, columns and basedatatype.
|
|
HFAStandard( 4, &nRows );
|
|
memcpy( pabyData, &nRows, 4 );
|
|
HFAStandard( 4, &nColumns );
|
|
memcpy( pabyData+4, &nColumns, 4 );
|
|
HFAStandard( 2, &nBaseItemType );
|
|
memcpy ( pabyData + 8, &nBaseItemType, 2 );
|
|
HFAStandard( 2, &nBaseItemType ); // swap back for our use.
|
|
|
|
// We ignore the 2 byte objecttype value.
|
|
|
|
nDataSize -= 12;
|
|
|
|
if( nIndexValue >= 0 )
|
|
{
|
|
if( (nIndexValue+1) * (HFAGetDataTypeBits(nBaseItemType)/8)
|
|
> nDataSize )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to extend field %s in node past end of data,\n"
|
|
"not currently supported.",
|
|
pszField );
|
|
return CE_Failure;
|
|
}
|
|
|
|
if( nBaseItemType == EPT_f64 )
|
|
{
|
|
double dfNumber = dfDoubleValue;
|
|
|
|
HFAStandard( 8, &dfNumber );
|
|
memcpy( pabyData + 12 + nIndexValue * 8, &dfNumber, 8 );
|
|
}
|
|
else if (nBaseItemType == EPT_u8)
|
|
{
|
|
unsigned char nNumber = (unsigned char)dfDoubleValue;
|
|
memcpy( pabyData + 12 + nIndexValue, &nNumber, 1);
|
|
}
|
|
else
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Setting basedata field %s with type %s not currently supported.",
|
|
pszField, HFAGetDataTypeName( nBaseItemType ) );
|
|
return CE_Failure;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'o':
|
|
if( poItemObjectType != NULL )
|
|
{
|
|
int nExtraOffset = 0;
|
|
int iIndexCounter;
|
|
|
|
if( poItemObjectType->nBytes > 0 )
|
|
{
|
|
if (nIndexValue != 0 && poItemObjectType->nBytes > INT_MAX / nIndexValue)
|
|
return CE_Failure;
|
|
nExtraOffset = poItemObjectType->nBytes * nIndexValue;
|
|
}
|
|
else
|
|
{
|
|
for( iIndexCounter = 0;
|
|
iIndexCounter < nIndexValue && nExtraOffset < nDataSize;
|
|
iIndexCounter++ )
|
|
{
|
|
int nInc = poItemObjectType->GetInstBytes(pabyData + nExtraOffset,
|
|
nDataSize - nExtraOffset);
|
|
if (nInc < 0 || nExtraOffset > INT_MAX - nInc)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
|
|
return CE_Failure;
|
|
}
|
|
|
|
nExtraOffset += nInc;
|
|
}
|
|
}
|
|
|
|
if (nExtraOffset >= nDataSize)
|
|
return CE_Failure;
|
|
|
|
if( pszField != NULL && strlen(pszField) > 0 )
|
|
{
|
|
return( poItemObjectType->
|
|
SetInstValue( pszField, pabyData + nExtraOffset,
|
|
nDataOffset + nExtraOffset,
|
|
nDataSize - nExtraOffset,
|
|
chReqType, pValue ) );
|
|
}
|
|
else
|
|
{
|
|
CPLAssert( FALSE );
|
|
return CE_Failure;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CPLAssert( FALSE );
|
|
return CE_Failure;
|
|
break;
|
|
}
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ExtractInstValue() */
|
|
/* */
|
|
/* Extract the value of an instance of a field. */
|
|
/* */
|
|
/* pszField should be NULL if this field is not a */
|
|
/* substructure. */
|
|
/************************************************************************/
|
|
|
|
int
|
|
HFAField::ExtractInstValue( const char * pszField, int nIndexValue,
|
|
GByte *pabyData, GUInt32 nDataOffset, int nDataSize,
|
|
char chReqType, void *pReqReturn, int *pnRemainingDataSize )
|
|
|
|
{
|
|
char *pszStringRet = NULL;
|
|
int nIntRet = 0;
|
|
double dfDoubleRet = 0.0;
|
|
int nInstItemCount = GetInstCount( pabyData, nDataSize );
|
|
GByte *pabyRawData = NULL;
|
|
|
|
if (pnRemainingDataSize)
|
|
*pnRemainingDataSize = -1;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Check the index value is valid. */
|
|
/* */
|
|
/* Eventually this will have to account for variable fields. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( nIndexValue < 0 || nIndexValue >= nInstItemCount )
|
|
{
|
|
if( chItemType == 'b' && nIndexValue >= -3 && nIndexValue < 0 )
|
|
/* ok - special index values */;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* If this field contains a pointer, then we will adjust the */
|
|
/* data offset relative to it. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( chPointer != '\0' )
|
|
{
|
|
GUInt32 nOffset;
|
|
|
|
if (nDataSize < 8)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy( &nOffset, pabyData+4, 4 );
|
|
HFAStandard( 4, &nOffset );
|
|
|
|
if( nOffset != (GUInt32) (nDataOffset + 8) )
|
|
{
|
|
#ifdef notdef
|
|
CPLError( CE_Warning, CPLE_AppDefined,
|
|
"%s.%s points at %d, not %d as expected\n",
|
|
pszFieldName, pszField ? pszField : "",
|
|
nOffset, nDataOffset+8 );
|
|
#endif
|
|
}
|
|
|
|
pabyData += 8;
|
|
|
|
nDataOffset += 8;
|
|
nDataSize -= 8;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* pointers to char or uchar arrays requested as strings are */
|
|
/* handled as a special case. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( (chItemType == 'c' || chItemType == 'C') && chReqType == 's' )
|
|
{
|
|
*((GByte **)pReqReturn) = pabyData;
|
|
if (pnRemainingDataSize)
|
|
*pnRemainingDataSize = nDataSize;
|
|
return( pabyData != NULL );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Handle by type. */
|
|
/* -------------------------------------------------------------------- */
|
|
switch( chItemType )
|
|
{
|
|
case 'c':
|
|
case 'C':
|
|
if (nIndexValue >= nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
nIntRet = pabyData[nIndexValue];
|
|
dfDoubleRet = nIntRet;
|
|
break;
|
|
|
|
case 'e':
|
|
case 's':
|
|
{
|
|
unsigned short nNumber;
|
|
if (nIndexValue*2 + 2 > nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
memcpy( &nNumber, pabyData + nIndexValue*2, 2 );
|
|
HFAStandard( 2, &nNumber );
|
|
nIntRet = nNumber;
|
|
dfDoubleRet = nIntRet;
|
|
|
|
if( chItemType == 'e'
|
|
&& nIntRet >= 0 && nIntRet < CSLCount(papszEnumNames) )
|
|
{
|
|
pszStringRet = papszEnumNames[nIntRet];
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'S':
|
|
{
|
|
short nNumber;
|
|
if (nIndexValue*2 + 2 > nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
memcpy( &nNumber, pabyData + nIndexValue*2, 2 );
|
|
HFAStandard( 2, &nNumber );
|
|
nIntRet = nNumber;
|
|
dfDoubleRet = nIntRet;
|
|
}
|
|
break;
|
|
|
|
case 't':
|
|
case 'l':
|
|
{
|
|
GUInt32 nNumber;
|
|
if (nIndexValue*4 + 4 > nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
memcpy( &nNumber, pabyData + nIndexValue*4, 4 );
|
|
HFAStandard( 4, &nNumber );
|
|
nIntRet = nNumber;
|
|
dfDoubleRet = nIntRet;
|
|
}
|
|
break;
|
|
|
|
case 'L':
|
|
{
|
|
GInt32 nNumber;
|
|
if (nIndexValue*4 + 4 > nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
memcpy( &nNumber, pabyData + nIndexValue*4, 4 );
|
|
HFAStandard( 4, &nNumber );
|
|
nIntRet = nNumber;
|
|
dfDoubleRet = nIntRet;
|
|
}
|
|
break;
|
|
|
|
case 'f':
|
|
{
|
|
float fNumber;
|
|
if (nIndexValue*4 + 4 > nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
memcpy( &fNumber, pabyData + nIndexValue*4, 4 );
|
|
HFAStandard( 4, &fNumber );
|
|
dfDoubleRet = fNumber;
|
|
nIntRet = (int) fNumber;
|
|
}
|
|
break;
|
|
|
|
case 'd':
|
|
{
|
|
double dfNumber;
|
|
if (nIndexValue*8 + 8 > nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
memcpy( &dfNumber, pabyData + nIndexValue*8, 8 );
|
|
HFAStandard( 8, &dfNumber );
|
|
dfDoubleRet = dfNumber;
|
|
nIntRet = (int) dfNumber;
|
|
}
|
|
break;
|
|
|
|
case 'b':
|
|
{
|
|
GInt32 nRows, nColumns;
|
|
GInt16 nBaseItemType;
|
|
|
|
if( nDataSize < 12 )
|
|
return FALSE;
|
|
|
|
memcpy( &nRows, pabyData, 4 );
|
|
HFAStandard( 4, &nRows );
|
|
memcpy( &nColumns, pabyData+4, 4 );
|
|
HFAStandard( 4, &nColumns );
|
|
memcpy( &nBaseItemType, pabyData+8, 2 );
|
|
HFAStandard( 2, &nBaseItemType );
|
|
// We ignore the 2 byte objecttype value.
|
|
|
|
if( nIndexValue < -3 || nIndexValue >= nRows * nColumns )
|
|
return FALSE;
|
|
|
|
pabyData += 12;
|
|
nDataSize -= 12;
|
|
|
|
if( nIndexValue == -3 )
|
|
{
|
|
dfDoubleRet = nIntRet = nBaseItemType;
|
|
}
|
|
else if( nIndexValue == -2 )
|
|
{
|
|
dfDoubleRet = nIntRet = nColumns;
|
|
}
|
|
else if( nIndexValue == -1 )
|
|
{
|
|
dfDoubleRet = nIntRet = nRows;
|
|
}
|
|
else if( nBaseItemType == EPT_u1 )
|
|
{
|
|
if (nIndexValue*8 >= nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
|
|
if( pabyData[nIndexValue>>3] & (1 << (nIndexValue & 0x7)) )
|
|
{
|
|
dfDoubleRet = 1;
|
|
nIntRet = 1;
|
|
}
|
|
else
|
|
{
|
|
dfDoubleRet = 0.0;
|
|
nIntRet = 0;
|
|
}
|
|
}
|
|
else if( nBaseItemType == EPT_u2 )
|
|
{
|
|
int nBitOffset = nIndexValue & 0x3;
|
|
int nByteOffset = nIndexValue >> 2;
|
|
int nMask = 0x3;
|
|
|
|
if (nByteOffset >= nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
|
|
nIntRet = (pabyData[nByteOffset] >> nBitOffset) & nMask;
|
|
dfDoubleRet = nIntRet;
|
|
}
|
|
else if( nBaseItemType == EPT_u4 )
|
|
{
|
|
int nBitOffset = nIndexValue & 0x7;
|
|
int nByteOffset = nIndexValue >> 3;
|
|
int nMask = 0x7;
|
|
|
|
if (nByteOffset >= nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
|
|
nIntRet = (pabyData[nByteOffset] >> nBitOffset) & nMask;
|
|
dfDoubleRet = nIntRet;
|
|
}
|
|
else if( nBaseItemType == EPT_u8 )
|
|
{
|
|
if (nIndexValue >= nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
dfDoubleRet = pabyData[nIndexValue];
|
|
nIntRet = pabyData[nIndexValue];
|
|
}
|
|
else if( nBaseItemType == EPT_s8 )
|
|
{
|
|
if (nIndexValue >= nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
dfDoubleRet = ((signed char *)pabyData)[nIndexValue];
|
|
nIntRet = ((signed char *)pabyData)[nIndexValue];
|
|
}
|
|
else if( nBaseItemType == EPT_s16 )
|
|
{
|
|
GInt16 nValue;
|
|
if (nIndexValue*2 + 2 > nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
memcpy( &nValue, pabyData + 2*nIndexValue, 2 );
|
|
HFAStandard( 2, &nValue );
|
|
|
|
dfDoubleRet = nValue;
|
|
nIntRet = nValue;
|
|
}
|
|
else if( nBaseItemType == EPT_u16 )
|
|
{
|
|
GUInt16 nValue;
|
|
if (nIndexValue*2 + 2 > nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
memcpy( &nValue, pabyData + 2*nIndexValue, 2 );
|
|
HFAStandard( 2, &nValue );
|
|
|
|
dfDoubleRet = nValue;
|
|
nIntRet = nValue;
|
|
}
|
|
else if( nBaseItemType == EPT_s32 )
|
|
{
|
|
GInt32 nValue;
|
|
if (nIndexValue*4 + 4 > nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
memcpy( &nValue, pabyData + 4*nIndexValue, 4 );
|
|
HFAStandard( 4, &nValue );
|
|
|
|
dfDoubleRet = nValue;
|
|
nIntRet = nValue;
|
|
}
|
|
else if( nBaseItemType == EPT_u32 )
|
|
{
|
|
GUInt32 nValue;
|
|
if (nIndexValue*4 + 4 > nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
memcpy( &nValue, pabyData + 4*nIndexValue, 4 );
|
|
HFAStandard( 4, &nValue );
|
|
|
|
dfDoubleRet = nValue;
|
|
nIntRet = nValue;
|
|
}
|
|
else if( nBaseItemType == EPT_f32 )
|
|
{
|
|
float fValue;
|
|
if (nIndexValue*4 + 4 > nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
memcpy( &fValue, pabyData + 4*nIndexValue, 4 );
|
|
HFAStandard( 4, &fValue );
|
|
|
|
dfDoubleRet = fValue;
|
|
nIntRet = (int) fValue;
|
|
}
|
|
else if( nBaseItemType == EPT_f64 )
|
|
{
|
|
double dfValue;
|
|
if (nIndexValue*8 + 8 > nDataSize)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return FALSE;
|
|
}
|
|
memcpy( &dfValue, pabyData+8*nIndexValue, 8 );
|
|
HFAStandard( 8, &dfValue );
|
|
|
|
dfDoubleRet = dfValue;
|
|
if( dfDoubleRet > INT_MAX )
|
|
nIntRet = INT_MAX;
|
|
else if( dfDoubleRet < INT_MIN )
|
|
nIntRet = INT_MIN;
|
|
else
|
|
nIntRet = (int) dfDoubleRet;
|
|
}
|
|
else
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Unknown base item type : %d", nBaseItemType);
|
|
return FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'o':
|
|
if( poItemObjectType != NULL )
|
|
{
|
|
int nExtraOffset = 0;
|
|
int iIndexCounter;
|
|
|
|
if( poItemObjectType->nBytes > 0 )
|
|
{
|
|
if (nIndexValue != 0 && poItemObjectType->nBytes > INT_MAX / nIndexValue)
|
|
return CE_Failure;
|
|
nExtraOffset = poItemObjectType->nBytes * nIndexValue;
|
|
}
|
|
else
|
|
{
|
|
for( iIndexCounter = 0;
|
|
iIndexCounter < nIndexValue && nExtraOffset < nDataSize;
|
|
iIndexCounter++ )
|
|
{
|
|
int nInc = poItemObjectType->GetInstBytes(pabyData + nExtraOffset,
|
|
nDataSize - nExtraOffset);
|
|
if (nInc < 0 || nExtraOffset > INT_MAX - nInc)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
|
|
return CE_Failure;
|
|
}
|
|
|
|
nExtraOffset += nInc;
|
|
}
|
|
}
|
|
|
|
if (nExtraOffset >= nDataSize)
|
|
return CE_Failure;
|
|
|
|
pabyRawData = pabyData + nExtraOffset;
|
|
|
|
if( pszField != NULL && strlen(pszField) > 0 )
|
|
{
|
|
return( poItemObjectType->
|
|
ExtractInstValue( pszField, pabyRawData,
|
|
nDataOffset + nExtraOffset,
|
|
nDataSize - nExtraOffset,
|
|
chReqType, pReqReturn, pnRemainingDataSize ) );
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
break;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Return the appropriate representation. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( chReqType == 's' )
|
|
{
|
|
if( pszStringRet == NULL )
|
|
{
|
|
/* HFAEntry:: BuildEntryFromMIFObject() expects to have always */
|
|
/* 8 bytes before the data. In normal situations, it should */
|
|
/* not go here, but that can happen if the file is corrupted */
|
|
/* so reserve the first 8 bytes before the string to contain null bytes */
|
|
memset(szNumberString, 0, 8);
|
|
CPLsprintf( szNumberString + 8, "%.14g", dfDoubleRet );
|
|
pszStringRet = szNumberString + 8;
|
|
}
|
|
|
|
*((char **) pReqReturn) = pszStringRet;
|
|
return( TRUE );
|
|
}
|
|
else if( chReqType == 'd' )
|
|
{
|
|
*((double *)pReqReturn) = dfDoubleRet;
|
|
return( TRUE );
|
|
}
|
|
else if( chReqType == 'i' )
|
|
{
|
|
*((int *) pReqReturn) = nIntRet;
|
|
return( TRUE );
|
|
}
|
|
else if( chReqType == 'p' )
|
|
{
|
|
*((GByte **) pReqReturn) = pabyRawData;
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
CPLAssert( FALSE );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetInstBytes() */
|
|
/* */
|
|
/* Get the number of bytes in a particular instance of a */
|
|
/* field. This will normally be the fixed internal nBytes */
|
|
/* value, but for pointer objects will include the variable */
|
|
/* portion. */
|
|
/************************************************************************/
|
|
|
|
int HFAField::GetInstBytes( GByte *pabyData, int nDataSize )
|
|
|
|
{
|
|
int nCount;
|
|
int nInstBytes = 0;
|
|
|
|
if( nBytes > -1 )
|
|
return nBytes;
|
|
|
|
if( chPointer != '\0' )
|
|
{
|
|
if (nDataSize < 4)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return -1;
|
|
}
|
|
|
|
memcpy( &nCount, pabyData, 4 );
|
|
HFAStandard( 4, &nCount );
|
|
|
|
pabyData += 8;
|
|
nInstBytes += 8;
|
|
}
|
|
else
|
|
nCount = 1;
|
|
|
|
if( chItemType == 'b' && nCount != 0 ) // BASEDATA
|
|
{
|
|
if (nDataSize - nInstBytes < 4+4+2)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
|
|
return -1;
|
|
}
|
|
|
|
GInt32 nRows, nColumns;
|
|
GInt16 nBaseItemType;
|
|
|
|
memcpy( &nRows, pabyData, 4 );
|
|
HFAStandard( 4, &nRows );
|
|
memcpy( &nColumns, pabyData+4, 4 );
|
|
HFAStandard( 4, &nColumns );
|
|
memcpy( &nBaseItemType, pabyData+8, 2 );
|
|
HFAStandard( 2, &nBaseItemType );
|
|
|
|
nInstBytes += 12;
|
|
|
|
if (nRows < 0 || nColumns < 0)
|
|
return -1;
|
|
if (nColumns != 0 && nRows > INT_MAX / nColumns)
|
|
return -1;
|
|
if (nColumns != 0 && ((HFAGetDataTypeBits(nBaseItemType) + 7) / 8) * nRows > INT_MAX / nColumns)
|
|
return -1;
|
|
if (((HFAGetDataTypeBits(nBaseItemType) + 7) / 8) * nRows * nColumns > INT_MAX - nInstBytes)
|
|
return -1;
|
|
|
|
nInstBytes +=
|
|
((HFAGetDataTypeBits(nBaseItemType) + 7) / 8) * nRows * nColumns;
|
|
}
|
|
else if( poItemObjectType == NULL )
|
|
{
|
|
if (nCount != 0 && HFADictionary::GetItemSize(chItemType) > INT_MAX / nCount)
|
|
return -1;
|
|
nInstBytes += nCount * HFADictionary::GetItemSize(chItemType);
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < nCount &&
|
|
nInstBytes < nDataSize &&
|
|
nInstBytes >= 0; i++ )
|
|
{
|
|
int nThisBytes;
|
|
|
|
nThisBytes =
|
|
poItemObjectType->GetInstBytes( pabyData,
|
|
nDataSize - nInstBytes );
|
|
if (nThisBytes < 0 || nInstBytes > INT_MAX - nThisBytes)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
|
|
return -1;
|
|
}
|
|
|
|
nInstBytes += nThisBytes;
|
|
pabyData += nThisBytes;
|
|
}
|
|
}
|
|
|
|
return( nInstBytes );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetInstCount() */
|
|
/* */
|
|
/* Get the count for a particular instance of a field. This */
|
|
/* will normally be the built in value, but for variable fields */
|
|
/* this is extracted from the data itself. */
|
|
/************************************************************************/
|
|
|
|
int HFAField::GetInstCount( GByte * pabyData, int nDataSize )
|
|
|
|
{
|
|
if( chPointer == '\0' )
|
|
return nItemCount;
|
|
else if( chItemType == 'b' )
|
|
{
|
|
GInt32 nRows, nColumns;
|
|
|
|
if( nDataSize < 20 )
|
|
return 0;
|
|
|
|
memcpy( &nRows, pabyData+8, 4 );
|
|
HFAStandard( 4, &nRows );
|
|
memcpy( &nColumns, pabyData+12, 4 );
|
|
HFAStandard( 4, &nColumns );
|
|
|
|
if (nRows < 0 || nColumns < 0)
|
|
return 0;
|
|
if (nColumns != 0 && nRows > INT_MAX / nColumns)
|
|
return 0;
|
|
|
|
return nRows * nColumns;
|
|
}
|
|
else
|
|
{
|
|
GInt32 nCount;
|
|
|
|
if( nDataSize < 4 )
|
|
return 0;
|
|
|
|
memcpy( &nCount, pabyData, 4 );
|
|
HFAStandard( 4, &nCount );
|
|
return nCount;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* DumpInstValue() */
|
|
/************************************************************************/
|
|
|
|
void HFAField::DumpInstValue( FILE *fpOut,
|
|
GByte *pabyData, GUInt32 nDataOffset, int nDataSize,
|
|
const char *pszPrefix )
|
|
|
|
{
|
|
int iEntry, nEntries;
|
|
void *pReturn;
|
|
char szLongFieldName[256];
|
|
|
|
nEntries = GetInstCount( pabyData, nDataSize );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Special case for arrays of chars or uchars which are printed */
|
|
/* as a string. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( (chItemType == 'c' || chItemType == 'C') && nEntries > 0 )
|
|
{
|
|
if( ExtractInstValue( NULL, 0,
|
|
pabyData, nDataOffset, nDataSize,
|
|
's', &pReturn ) )
|
|
VSIFPrintf( fpOut, "%s%s = `%s'\n",
|
|
pszPrefix, pszFieldName,
|
|
(char *) pReturn );
|
|
else
|
|
VSIFPrintf( fpOut, "%s%s = (access failed)\n",
|
|
pszPrefix, pszFieldName );
|
|
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* For BASEDATA objects, we want to first dump their dimension */
|
|
/* and type. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( chItemType == 'b' )
|
|
{
|
|
int nDataType, nRows, nColumns;
|
|
int bSuccess = ExtractInstValue( NULL, -3, pabyData, nDataOffset,
|
|
nDataSize, 'i', &nDataType );
|
|
if (bSuccess)
|
|
{
|
|
ExtractInstValue( NULL, -2, pabyData, nDataOffset,
|
|
nDataSize, 'i', &nColumns );
|
|
ExtractInstValue( NULL, -1, pabyData, nDataOffset,
|
|
nDataSize, 'i', &nRows );
|
|
VSIFPrintf( fpOut, "%sBASEDATA(%s): %dx%d of %s\n",
|
|
pszPrefix, pszFieldName,
|
|
nColumns, nRows, HFAGetDataTypeName( nDataType ) );
|
|
}
|
|
else
|
|
{
|
|
VSIFPrintf( fpOut, "%sBASEDATA(%s): empty\n",
|
|
pszPrefix, pszFieldName );
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Dump each entry in the field array. */
|
|
/* -------------------------------------------------------------------- */
|
|
for( iEntry = 0; iEntry < MIN(MAX_ENTRY_REPORT,nEntries); iEntry++ )
|
|
{
|
|
if( nEntries == 1 )
|
|
VSIFPrintf( fpOut, "%s%s = ", pszPrefix, pszFieldName );
|
|
else
|
|
VSIFPrintf( fpOut, "%s%s[%d] = ",
|
|
pszPrefix, pszFieldName, iEntry );
|
|
|
|
switch( chItemType )
|
|
{
|
|
case 'f':
|
|
case 'd':
|
|
{
|
|
double dfValue;
|
|
if( ExtractInstValue( NULL, iEntry,
|
|
pabyData, nDataOffset, nDataSize,
|
|
'd', &dfValue ) )
|
|
VSIFPrintf( fpOut, "%f\n", dfValue );
|
|
else
|
|
VSIFPrintf( fpOut, "(access failed)\n" );
|
|
}
|
|
break;
|
|
|
|
case 'b':
|
|
{
|
|
double dfValue;
|
|
|
|
if( ExtractInstValue( NULL, iEntry,
|
|
pabyData, nDataOffset, nDataSize,
|
|
'd', &dfValue ) )
|
|
VSIFPrintf( fpOut, "%s%.15g\n", pszPrefix, dfValue );
|
|
else
|
|
VSIFPrintf( fpOut, "%s(access failed)\n", pszPrefix );
|
|
}
|
|
break;
|
|
|
|
case 'e':
|
|
if( ExtractInstValue( NULL, iEntry,
|
|
pabyData, nDataOffset, nDataSize,
|
|
's', &pReturn ) )
|
|
VSIFPrintf( fpOut, "%s\n", (char *) pReturn );
|
|
else
|
|
VSIFPrintf( fpOut, "(access failed)\n" );
|
|
break;
|
|
|
|
case 'o':
|
|
if( !ExtractInstValue( NULL, iEntry,
|
|
pabyData, nDataOffset, nDataSize,
|
|
'p', &pReturn ) )
|
|
{
|
|
VSIFPrintf( fpOut, "(access failed)\n" );
|
|
}
|
|
else
|
|
{
|
|
int nByteOffset;
|
|
|
|
VSIFPrintf( fpOut, "\n" );
|
|
|
|
nByteOffset = ((GByte *) pReturn) - pabyData;
|
|
|
|
sprintf( szLongFieldName, "%s ", pszPrefix );
|
|
|
|
if( poItemObjectType )
|
|
poItemObjectType->DumpInstValue( fpOut,
|
|
pabyData + nByteOffset,
|
|
nDataOffset + nByteOffset,
|
|
nDataSize - nByteOffset,
|
|
szLongFieldName );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
GInt32 nIntValue;
|
|
|
|
if( ExtractInstValue( NULL, iEntry,
|
|
pabyData, nDataOffset, nDataSize,
|
|
'i', &nIntValue ) )
|
|
VSIFPrintf( fpOut, "%d\n", nIntValue );
|
|
else
|
|
VSIFPrintf( fpOut, "(access failed)\n" );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( nEntries > MAX_ENTRY_REPORT )
|
|
printf( "%s ... remaining instances omitted ...\n", pszPrefix );
|
|
|
|
if( nEntries == 0 )
|
|
VSIFPrintf( fpOut, "%s%s = (no values)\n", pszPrefix, pszFieldName );
|
|
|
|
}
|