[Gdal-dev] HFA no data value support followup

Brian Claywell brian.claywell at gmail.com
Sun Apr 1 23:20:54 EDT 2007


Frank et al,

I spoke to you on #gdal the other day regarding my work implementing no
data value support in the HFA driver, and I wanted to update you on my
progress and doublecheck that what I was doing was acceptable.

I toyed around with your suggestion to add a case 'b': to SetInstValue()
in HFAField similar to the one in ExtractInstValue(), but couldn't come
up with an elegant solution to handling the number of rows, number of
columns, and base item type fields in the basedata structure, since that
would at the very least require multiple calls to SetInstValue(), which
would have to check to see which field we were currently on, etc., so I
abandoned that idea and instead went with the idea of serializing the
basedata structure before the call to SetInstValue(), which I modified
slightly to add a special case (like the string case) which writes out
the entire serialized structure at once.

One thing that I'm uncertain about is my handling of the structure in
SetInstValue(), where I decode the first three fields of the serialized
data to see exactly how much data to write out. It would certainly be
easier to simply write out nDataSize bytes, but I wasn't confident in
the safety of doing it like that.

I've attached a (very rough!) diff which illustrates what I've done so
far. Please keep in mind that I'm an electrical engineer by training and
not a code wizard :) Without modifying any of the read routines, the
statistics routines correctly honored the no-data value I set in a
simple test case.

Let me know if this approach is acceptable to you, and if there are any
changes you'd like to see before I submit a cleaner version of the patch
with some more error checking/handling and some streamlining.

-- 
Brian Claywell
brian.claywell at gmail.com
-------------- next part --------------
diff -r /usr/src/gdal-1.4.0/frmts/hfa/hfa.h frmts/hfa/hfa.h
219a220
> CPLErr CPL_DLL HFASetBandNoData( HFAHandle hHFA, int nBand, double dfValue );
diff -r /usr/src/gdal-1.4.0/frmts/hfa/hfa_p.h frmts/hfa/hfa_p.h
228a229,233
>     GByte * SerializeBasedata( GInt32 nRows, 
> 							   GInt32 nColumns,
> 							   GInt16 nBaseDataType,
> 							   void * pValue );
>     
260c265,266
< 
---
>     CPLErr SetNoDataValue( double dfValue );
>     
338a345
>     CPLErr 		SetBasedataField( const char *, const GByte * );
diff -r /usr/src/gdal-1.4.0/frmts/hfa/hfaband.cpp frmts/hfa/hfaband.cpp
1437a1438,1587
> /*                         SetNoDataValue()                             */
> /*                                                                      */
> /*      Set the layer no data value                                     */
> /************************************************************************/
> 
> CPLErr HFABand::SetNoDataValue( double dfValue )
> {
> 	CPLErr eErr = CE_Failure;
> 	
> 	if ( psInfo->eAccess == HFA_Update )
> 	{
> 		HFAEntry *poNDNode = poNode->GetNamedChild( "Eimg_NonInitializedValue" );
> 		
> 		if ( poNDNode == NULL )
> 		{
> 			poNDNode = new HFAEntry ( psInfo,
> 									  "Eimg_NonInitializedValue",
> 									  "Eimg_NonInitializedValue",
> 									  poNode );
> 		}
> 		
> 		// serialize basedata structure
> 		GByte *pszSerData = SerializeBasedata( 1, 1, EPT_f64, (void *) &dfValue );
> 		
> 		if ( pszSerData != NULL )
> 		{
> 			poNDNode->MakeData( 8 + 12 + 8 );
> 			poNDNode->SetPosition();
> 			
> 			poNDNode->DumpFieldValues(stdout, "poNDNode: ");
> 			
> 			/*	SetStringField won't work here, because we can't depend
> 			 * 	on not having values of 0x00 somewhere in the serialized
> 			 * 	data. What we really need is something *akin* to SetStringField
> 			 * 	that doesn't use strlen to figure out how many bytes to write.
> 			 */
> #if 1
> 			if ( poNDNode->SetBasedataField( "valueBD", pszSerData ) != CE_Failure )
> 			{
> 				CPLDebug( "HFABand",
> 						  "poNDNode->SetBasedataField returned success" );
> 				
> 				bNoDataSet = TRUE;
> 				dfNoData = dfValue;
> 				eErr = CE_None;
> 			}
> #endif		
> 			CPLFree( pszSerData );
> 
> 		}	/* end if ( pszSerData != NULL ) */
> 		/* else eErr = CE_Failure; */
> 		
> 	}	/* end if ( psInfo->eAccess == HFA_Update ) */
> 	/* else eErr = CE_Failure; */
> 	
> 	return eErr;
> }
> 
> /************************************************************************/
> /*                         SerializeBasedata()                          */
> /*                                                                      */
> /*      Package basedata into a serial byte structure                   */
> /************************************************************************/
> 
> GByte * HFABand::SerializeBasedata( GInt32 nRows, 
> 								    GInt32 nColumns,
> 								    GInt16 nBaseItemType,
> 								    void *pValue )
> {
> 	if ( nRows < 1 || nColumns < 1 ) {
> 		CPLAssert( FALSE );
> 		return NULL;
> 	}
> 	
> 	int nBaseItemSize = 0;
> 	
> 	switch (nBaseItemType)
> 	{
> 		/*	at this point, sub-byte datatypes are stored as one byte each. */
> 		case EPT_u1:
> 		case EPT_u2:
> 		case EPT_u4:
> 		case EPT_u8:
> 		case EPT_s8:
> 			nBaseItemSize = 1;
> 			break;
> 			
> 		case EPT_u16:
> 		case EPT_s16:
> 			nBaseItemSize = 2;
> 			break;
> 			
> 		case EPT_u32:
> 		case EPT_s32:
> 		case EPT_f32:
> 			nBaseItemSize = 4;
> 			break;
> 			
> 		case EPT_f64:
> 		case EPT_c64:
> 			nBaseItemSize = 8;
> 			break;
> 			
> 		case EPT_c128:
> 			nBaseItemSize = 16;
> 			break;
> 			
> 		default:
> 			return NULL;
> 			break;
> 			
> 	}
> 	
> 	GByte *pszSerData = NULL;
> 	pszSerData = (GByte *) CPLMalloc( 12 + nRows*nColumns*nBaseItemSize );
> 	
> 	if ( pszSerData == NULL )
> 	{
> 		CPLError( CE_Failure, CPLE_OutOfMemory, 
> 				  "Out of memory allocating pszSerData for basedata serialization" );
> 		return NULL;
> 	}
> 	
> 	HFAStandard( 4, &nRows );
> 	memcpy( pszSerData, &nRows, 4 );
> 	
> 	HFAStandard( 4, &nColumns );
> 	memcpy( pszSerData+4, &nColumns, 4 );
> 	
> 	HFAStandard( 2, &nBaseDataType );
> 	memcpy( pszSerData+8, &nBaseItemType, 2 );
> 	
> 	/*	objecttype should probably be set here	*/
> 	
> 	GByte *pSrc = (GByte *) pValue;
> 	GByte *pDst = pszSerData + 12;
> 	
> 	/*	standardize the remaining data and store to memory */
> 	for ( int i = 0; i < nRows*nColumns; i++ )
> 	{
> 		memcpy( pDst, pSrc, nBaseItemSize );
> 		HFAStandard( nBaseItemSize, pDst );
> 		pDst += nBaseItemSize;
> 		pSrc += nBaseItemSize;
> 	}
> 	
> 	return pszSerData;
> }
> 
> /************************************************************************/
diff -r /usr/src/gdal-1.4.0/frmts/hfa/hfadataset.cpp frmts/hfa/hfadataset.cpp
499c499,500
< 
---
>     virtual CPLErr SetNoDataValue( double dfValue );
>     
817a819,827
> /*                             SetNoData()                              */
> /************************************************************************/
> 
> CPLErr HFARasterBand::SetNoDataValue( double dfValue )
> {
> 	return HFASetBandNoData( hHFA, nBand, dfValue );
> }
> 
> /************************************************************************/
diff -r /usr/src/gdal-1.4.0/frmts/hfa/hfaentry.cpp frmts/hfa/hfaentry.cpp
664a665,675
> /*                           SetBasedataField()                         */
> /************************************************************************/
> 
> CPLErr HFAEntry::SetBasedataField( const char * pszFieldPath, 
>                                    const GByte * pszValue )
> 
> {
>     return SetFieldValue( pszFieldPath, 'b', (void *) pszValue );
> }
> 
> /************************************************************************/
diff -r /usr/src/gdal-1.4.0/frmts/hfa/hfafield.cpp frmts/hfa/hfafield.cpp
525a546,620
>     
>     else if ( chReqType == 'b' )
>     {
>     	
>     	GInt32 nRows;
>     	GInt32 nColumns;
>     	GInt16 nBaseItemType;
>     	
>     	memcpy( &nRows, pValue, 4 );
>     	HFAStandard(4, &nRows );
>     	
>     	memcpy( &nColumns, pValue, 4 );
>     	HFAStandard(4, &nColumns );
>     	
>     	memcpy( &nBaseItemType, pValue, 2 );
>     	HFAStandard(2, &nBaseItemType );
>     	
>     	int nBaseItemSize = 0;
>     	
>     	switch (nBaseItemType)
>     	{
>     		/*	at this point, sub-byte datatypes are stored as one byte each. */
>     		case EPT_u1:
>     		case EPT_u2:
>     		case EPT_u4:
>     		case EPT_u8:
>     		case EPT_s8:
>     			nBaseItemSize = 1;
>     			break;
>     			
>     		case EPT_u16:
>     		case EPT_s16:
>     			nBaseItemSize = 2;
>     			break;
>     			
>     		case EPT_u32:
>     		case EPT_s32:
>     		case EPT_f32:
>     			nBaseItemSize = 4;
>     			break;
>     			
>     		case EPT_f64:
>     		case EPT_c64:
>     			nBaseItemSize = 8;
>     			break;
>     			
>     		case EPT_c128:
>     			nBaseItemSize = 16;
>     			break;
>     			
>     		default:
>     			CPLDebug( "HFAField",
>     					  "Bad nBaseItemType in SetInstValue()" );
>     			
>     			return CE_Failure;
>     			break;
>     			
>     	}
>     	
>     	int	nBytesToCopy = 12 + nRows*nColumns*nBaseItemSize;
>     	
>     	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;
>     	}
>     	
>     	memcpy( pabyData, pValue, nBytesToCopy );
>     	
>     	return CE_None;
>     	
>     }
diff -r /usr/src/gdal-1.4.0/frmts/hfa/hfaopen.cpp frmts/hfa/hfaopen.cpp
673a674,693
> /*                          HFASetBandNoData()                          */
> /*                                                                      */
> /*      attempts to set the no data value on the band                   */
> /************************************************************************/
> 
> CPLErr HFASetBandNoData( HFAHandle hHFA, int nBand, double dfValue )
> {
> 	if ( nBand < 0 || nBand > hHFA->nBands )
> 	{
> 		CPLAssert( FALSE );
> 		return CE_Failure;
> 	}
> 	
> 	HFABand *poBand = hHFA->papoBand[nBand-1];
> 	
> 	return poBand->SetNoDataValue( dfValue );
> 	
> }
> 
> /************************************************************************/


More information about the Gdal-dev mailing list