EVOLUTION-MANAGER
Edit File: hdf5dataset.cpp
/****************************************************************************** * $Id: hdf5dataset.cpp 28365 2015-01-27 10:39:30Z rouault $ * * Project: Hierarchical Data Format Release 5 (HDF5) * Purpose: HDF5 Datasets. Open HDF5 file, fetch metadata and list of * subdatasets. * This driver initially based on code supplied by Markus Neteler * Author: Denis Nadeau <denis.nadeau@gmail.com> * ****************************************************************************** * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com> * Copyright (c) 2008-2013, 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. ****************************************************************************/ #define H5_USE_16_API #define MAX_METADATA_LEN 32768 #include "hdf5.h" #include "gdal_priv.h" #include "cpl_string.h" #include "hdf5dataset.h" CPL_CVSID("$Id: hdf5dataset.cpp 28365 2015-01-27 10:39:30Z rouault $"); CPL_C_START void GDALRegister_HDF5(void); CPL_C_END /************************************************************************/ /* ==================================================================== */ /* HDF5Dataset */ /* ==================================================================== */ /************************************************************************/ /************************************************************************/ /* GDALRegister_HDF5() */ /************************************************************************/ void GDALRegister_HDF5() { GDALDriver *poDriver; if( GDALGetDriverByName("HDF5") == NULL ) { poDriver = new GDALDriver(); poDriver->SetDescription("HDF5"); poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Hierarchical Data Format Release 5"); poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "frmt_hdf5.html"); poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "hdf5"); poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES"); poDriver->pfnOpen = HDF5Dataset::Open; poDriver->pfnIdentify = HDF5Dataset::Identify; GetGDALDriverManager()->RegisterDriver(poDriver); } #ifdef HDF5_PLUGIN GDALRegister_HDF5Image(); #endif } /************************************************************************/ /* HDF5Dataset() */ /************************************************************************/ HDF5Dataset::HDF5Dataset() { papszSubDatasets = NULL; papszMetadata = NULL; poH5RootGroup = NULL; nSubDataCount = 0; hHDF5 = -1; hGroupID = -1; bIsHDFEOS = FALSE; nDatasetType = -1; } /************************************************************************/ /* ~HDF5Dataset() */ /************************************************************************/ HDF5Dataset::~HDF5Dataset() { CSLDestroy( papszMetadata ); if( hGroupID > 0 ) H5Gclose( hGroupID ); if( hHDF5 > 0 ) H5Fclose( hHDF5 ); CSLDestroy( papszSubDatasets ); if( poH5RootGroup != NULL ) { DestroyH5Objects( poH5RootGroup ); CPLFree( poH5RootGroup->pszName ); CPLFree( poH5RootGroup->pszPath ); CPLFree( poH5RootGroup->pszUnderscorePath ); CPLFree( poH5RootGroup->poHchild ); CPLFree( poH5RootGroup ); } } /************************************************************************/ /* GetDataType() */ /* */ /* Transform HDF5 datatype to GDAL datatype */ /************************************************************************/ GDALDataType HDF5Dataset::GetDataType(hid_t TypeID) { if( H5Tequal( H5T_NATIVE_CHAR, TypeID ) ) return GDT_Byte; else if( H5Tequal( H5T_NATIVE_SCHAR, TypeID ) ) return GDT_Byte; else if( H5Tequal( H5T_NATIVE_UCHAR, TypeID ) ) return GDT_Byte; else if( H5Tequal( H5T_NATIVE_SHORT, TypeID ) ) return GDT_Int16; else if( H5Tequal( H5T_NATIVE_USHORT, TypeID ) ) return GDT_UInt16; else if( H5Tequal( H5T_NATIVE_INT, TypeID ) ) return GDT_Int32; else if( H5Tequal( H5T_NATIVE_UINT, TypeID ) ) return GDT_UInt32; else if( H5Tequal( H5T_NATIVE_LONG, TypeID ) ) { if( sizeof(long) == 4 ) return GDT_Int32; else return GDT_Unknown; } else if( H5Tequal( H5T_NATIVE_ULONG, TypeID ) ) { if( sizeof(unsigned long) == 4 ) return GDT_UInt32; else return GDT_Unknown; } else if( H5Tequal( H5T_NATIVE_FLOAT, TypeID ) ) return GDT_Float32; else if( H5Tequal( H5T_NATIVE_DOUBLE, TypeID ) ) return GDT_Float64; else if( H5Tequal( H5T_NATIVE_LLONG, TypeID ) ) return GDT_Unknown; else if( H5Tequal( H5T_NATIVE_ULLONG, TypeID ) ) return GDT_Unknown; else if( H5Tequal( H5T_NATIVE_DOUBLE, TypeID ) ) return GDT_Unknown; return GDT_Unknown; } /************************************************************************/ /* GetDataTypeName() */ /* */ /* Return the human readable name of data type */ /************************************************************************/ const char *HDF5Dataset::GetDataTypeName(hid_t TypeID) { if( H5Tequal( H5T_NATIVE_CHAR, TypeID ) ) return "8-bit character"; else if( H5Tequal( H5T_NATIVE_SCHAR, TypeID ) ) return "8-bit signed character"; else if( H5Tequal( H5T_NATIVE_UCHAR, TypeID ) ) return "8-bit unsigned character"; else if( H5Tequal( H5T_NATIVE_SHORT, TypeID ) ) return "16-bit integer"; else if( H5Tequal( H5T_NATIVE_USHORT, TypeID ) ) return "16-bit unsigned integer"; else if( H5Tequal( H5T_NATIVE_INT, TypeID ) ) return "32-bit integer"; else if( H5Tequal( H5T_NATIVE_UINT, TypeID ) ) return "32-bit unsigned integer"; else if( H5Tequal( H5T_NATIVE_LONG, TypeID ) ) return "32/64-bit integer"; else if( H5Tequal( H5T_NATIVE_ULONG, TypeID ) ) return "32/64-bit unsigned integer"; else if( H5Tequal( H5T_NATIVE_FLOAT, TypeID ) ) return "32-bit floating-point"; else if( H5Tequal( H5T_NATIVE_DOUBLE, TypeID ) ) return "64-bit floating-point"; else if( H5Tequal( H5T_NATIVE_LLONG, TypeID ) ) return "64-bit integer"; else if( H5Tequal( H5T_NATIVE_ULLONG, TypeID ) ) return "64-bit unsigned integer"; else if( H5Tequal( H5T_NATIVE_DOUBLE, TypeID ) ) return "64-bit floating-point"; return "Unknown"; } /************************************************************************/ /* Identify() */ /************************************************************************/ int HDF5Dataset::Identify( GDALOpenInfo * poOpenInfo ) { /* -------------------------------------------------------------------- */ /* Is it an HDF5 file? */ /* -------------------------------------------------------------------- */ static const char achSignature[] = "\211HDF\r\n\032\n"; if( poOpenInfo->pabyHeader ) { if( memcmp(poOpenInfo->pabyHeader,achSignature,8) == 0 ) return TRUE; if( memcmp(poOpenInfo->pabyHeader,"<HDF_UserBlock>",15) == 0) { if( H5Fis_hdf5(poOpenInfo->pszFilename) ) return TRUE; } } return FALSE; } /************************************************************************/ /* Open() */ /************************************************************************/ GDALDataset *HDF5Dataset::Open( GDALOpenInfo * poOpenInfo ) { HDF5Dataset *poDS; if( !Identify( poOpenInfo ) ) return NULL; /* -------------------------------------------------------------------- */ /* Create datasource. */ /* -------------------------------------------------------------------- */ poDS = new HDF5Dataset(); poDS->SetDescription( poOpenInfo->pszFilename ); /* -------------------------------------------------------------------- */ /* Try opening the dataset. */ /* -------------------------------------------------------------------- */ poDS->hHDF5 = H5Fopen( poOpenInfo->pszFilename, H5F_ACC_RDONLY, H5P_DEFAULT ); if( poDS->hHDF5 < 0 ) { delete poDS; return NULL; } poDS->hGroupID = H5Gopen( poDS->hHDF5, "/" ); if( poDS->hGroupID < 0 ) { poDS->bIsHDFEOS=false; delete poDS; return NULL; } poDS->bIsHDFEOS=true; poDS->ReadGlobalAttributes( true ); poDS->SetMetadata( poDS->papszMetadata ); if ( CSLCount( poDS->papszSubDatasets ) / 2 >= 1 ) poDS->SetMetadata( poDS->papszSubDatasets, "SUBDATASETS" ); // Make sure we don't try to do any pam stuff with this dataset. poDS->nPamFlags |= GPF_NOSAVE; /* -------------------------------------------------------------------- */ /* If we have single subdataset only, open it immediately */ /* -------------------------------------------------------------------- */ int nSubDatasets = CSLCount( poDS->papszSubDatasets ) / 2; if( nSubDatasets == 1 ) { CPLString osDSName = CSLFetchNameValue( poDS->papszSubDatasets, "SUBDATASET_1_NAME" ); delete poDS; return (GDALDataset *) GDALOpen( osDSName, poOpenInfo->eAccess ); } else { /* -------------------------------------------------------------------- */ /* Confirm the requested access is supported. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->eAccess == GA_Update ) { delete poDS; CPLError( CE_Failure, CPLE_NotSupported, "The HDF5 driver does not support update access to existing" " datasets.\n" ); return NULL; } } return( poDS ); } /************************************************************************/ /* DestroyH5Objects() */ /* */ /* Erase all objects */ /************************************************************************/ void HDF5Dataset::DestroyH5Objects( HDF5GroupObjects *poH5Object ) { unsigned i; /* -------------------------------------------------------------------- */ /* Visit all objects */ /* -------------------------------------------------------------------- */ for( i=0; i < poH5Object->nbObjs; i++ ) if( poH5Object->poHchild+i != NULL ) DestroyH5Objects( poH5Object->poHchild+i ); if( poH5Object->poHparent ==NULL ) return; /* -------------------------------------------------------------------- */ /* Erase some data */ /* -------------------------------------------------------------------- */ CPLFree( poH5Object->paDims ); poH5Object->paDims = NULL; CPLFree( poH5Object->pszPath ); poH5Object->pszPath = NULL; CPLFree( poH5Object->pszName ); poH5Object->pszName = NULL; CPLFree( poH5Object->pszUnderscorePath ); poH5Object->pszUnderscorePath = NULL; if( poH5Object->native > 0 ) H5Tclose( poH5Object->native ); poH5Object->native = 0; /* -------------------------------------------------------------------- */ /* All Children are visited and can be deleted. */ /* -------------------------------------------------------------------- */ if( ( i==poH5Object->nbObjs ) && ( poH5Object->nbObjs!=0 ) ) { CPLFree( poH5Object->poHchild ); poH5Object->poHchild = NULL; } } /************************************************************************/ /* CreatePath() */ /* */ /* Find Dataset path for HDopen */ /************************************************************************/ char* CreatePath( HDF5GroupObjects *poH5Object ) { char pszPath[8192]; char pszUnderscoreSpaceInName[8192]; char *popszPath; int i; char **papszPath; /* -------------------------------------------------------------------- */ /* Recurse to the root path */ /* -------------------------------------------------------------------- */ pszPath[0]='\0'; if( poH5Object->poHparent !=NULL ) { popszPath=CreatePath( poH5Object->poHparent ); strcpy( pszPath,popszPath ); } /* -------------------------------------------------------------------- */ /* add name to the path */ /* -------------------------------------------------------------------- */ if( !EQUAL( poH5Object->pszName,"/" ) ){ strcat( pszPath,"/" ); strcat( pszPath,poH5Object->pszName ); } /* -------------------------------------------------------------------- */ /* fill up path for each object */ /* -------------------------------------------------------------------- */ if( poH5Object->pszPath == NULL ) { if( strlen( poH5Object->pszName ) == 1 ) { strcat(pszPath, poH5Object->pszName ); strcpy(pszUnderscoreSpaceInName, poH5Object->pszName); } else { /* -------------------------------------------------------------------- */ /* Change space for underscore */ /* -------------------------------------------------------------------- */ papszPath = CSLTokenizeString2( pszPath, " ", CSLT_HONOURSTRINGS ); strcpy(pszUnderscoreSpaceInName,papszPath[0]); for( i=1; i < CSLCount( papszPath ); i++ ) { strcat( pszUnderscoreSpaceInName, "_" ); strcat( pszUnderscoreSpaceInName, papszPath[ i ] ); } CSLDestroy(papszPath); } poH5Object->pszUnderscorePath = CPLStrdup( pszUnderscoreSpaceInName ); poH5Object->pszPath = CPLStrdup( pszPath ); } return( poH5Object->pszPath ); } /************************************************************************/ /* HDF5GroupCheckDuplicate() */ /* */ /* Returns TRUE if an ancestor has the same objno[] as passed */ /* in - used to avoid looping in files with "links up" #(3218). */ /************************************************************************/ static int HDF5GroupCheckDuplicate( HDF5GroupObjects *poHparent, unsigned long *objno ) { while( poHparent != NULL ) { if( poHparent->objno[0] == objno[0] && poHparent->objno[1] == objno[1] ) return TRUE; poHparent = poHparent->poHparent; } return FALSE; } /************************************************************************/ /* HDF5CreateGroupObjs() */ /* */ /* Create HDF5 hierarchy into a linked list */ /************************************************************************/ herr_t HDF5CreateGroupObjs(hid_t hHDF5, const char *pszObjName, void *poHObjParent) { hid_t hGroupID; /* identifier of group */ hid_t hDatasetID; /* identifier of dataset */ hsize_t nbObjs=0; /* number of objects in a group */ int nbAttrs=0; /* number of attributes in object */ unsigned idx; int n_dims; H5G_stat_t oStatbuf; hsize_t *dims=NULL; hsize_t *maxdims=NULL; hid_t datatype; hid_t dataspace; hid_t native; HDF5GroupObjects *poHchild; HDF5GroupObjects *poHparent; poHparent = ( HDF5GroupObjects * ) poHObjParent; poHchild=poHparent->poHchild; if( H5Gget_objinfo( hHDF5, pszObjName, FALSE, &oStatbuf ) < 0 ) return -1; /* -------------------------------------------------------------------- */ /* Look for next child */ /* -------------------------------------------------------------------- */ for( idx=0; idx < poHparent->nbObjs; idx++ ) { if( poHchild->pszName == NULL ) break; poHchild++; } if( idx == poHparent->nbObjs ) return -1; // all children parsed /* -------------------------------------------------------------------- */ /* Save child information */ /* -------------------------------------------------------------------- */ poHchild->pszName = CPLStrdup( pszObjName ); poHchild->nType = oStatbuf.type; poHchild->nIndex = idx; poHchild->poHparent = poHparent; poHchild->nRank = 0; poHchild->paDims = 0; poHchild->HDatatype = 0; poHchild->objno[0] = oStatbuf.objno[0]; poHchild->objno[1] = oStatbuf.objno[1]; if( poHchild->pszPath == NULL ) { poHchild->pszPath = CreatePath( poHchild ); } if( poHparent->pszPath == NULL ) { poHparent->pszPath = CreatePath( poHparent ); } switch ( oStatbuf.type ) { case H5G_LINK: poHchild->nbAttrs = 0; poHchild->nbObjs = 0; poHchild->poHchild = NULL; poHchild->nRank = 0; poHchild->paDims = 0; poHchild->HDatatype = 0; break; case H5G_GROUP: if( ( hGroupID = H5Gopen( hHDF5, pszObjName ) ) == -1 ) { printf( "Error: unable to access \"%s\" group.\n", pszObjName ); return -1; } nbAttrs = H5Aget_num_attrs( hGroupID ); H5Gget_num_objs( hGroupID, &nbObjs ); poHchild->nbAttrs= nbAttrs; poHchild->nbObjs = (int) nbObjs; poHchild->nRank = 0; poHchild->paDims = 0; poHchild->HDatatype = 0; if( nbObjs > 0 ) { poHchild->poHchild =( HDF5GroupObjects * ) CPLCalloc( (int)nbObjs, sizeof( HDF5GroupObjects ) ); memset( poHchild->poHchild, 0, (size_t) (sizeof( HDF5GroupObjects ) * nbObjs) ); } else poHchild->poHchild = NULL; if( !HDF5GroupCheckDuplicate( poHparent, oStatbuf.objno ) ) H5Giterate( hHDF5, pszObjName, NULL, HDF5CreateGroupObjs, (void*) poHchild ); else CPLDebug( "HDF5", "avoiding link looping on node '%s'.", pszObjName ); H5Gclose( hGroupID ); break; case H5G_DATASET: if( ( hDatasetID = H5Dopen( hHDF5, pszObjName ) ) == -1 ) { printf( "Error: unable to access \"%s\" dataset.\n", pszObjName ); return -1; } nbAttrs = H5Aget_num_attrs( hDatasetID ); datatype = H5Dget_type( hDatasetID ); dataspace = H5Dget_space( hDatasetID ); n_dims = H5Sget_simple_extent_ndims( dataspace ); native = H5Tget_native_type( datatype, H5T_DIR_ASCEND ); if( n_dims > 0 ) { dims = (hsize_t *) CPLCalloc( n_dims,sizeof( hsize_t ) ); maxdims = (hsize_t *) CPLCalloc( n_dims,sizeof( hsize_t ) ); } H5Sget_simple_extent_dims( dataspace, dims, maxdims ); if( maxdims != NULL ) CPLFree( maxdims ); if( n_dims > 0 ) { poHchild->nRank = n_dims; // rank of the array poHchild->paDims = dims; // dimmension of the array. poHchild->HDatatype = datatype; // HDF5 datatype } else { poHchild->nRank = -1; poHchild->paDims = NULL; poHchild->HDatatype = 0; } poHchild->nbAttrs = nbAttrs; poHchild->nbObjs = 0; poHchild->poHchild = NULL; poHchild->native = native; H5Tclose( datatype ); H5Sclose( dataspace ); H5Dclose( hDatasetID ); break; case H5G_TYPE: poHchild->nbAttrs = 0; poHchild->nbObjs = 0; poHchild->poHchild = NULL; poHchild->nRank = 0; poHchild->paDims = 0; poHchild->HDatatype = 0; break; default: break; } return 0; } /************************************************************************/ /* HDF5AttrIterate() */ /************************************************************************/ herr_t HDF5AttrIterate( hid_t hH5ObjID, const char *pszAttrName, void *pDS ) { hid_t hAttrID; hid_t hAttrTypeID; hid_t hAttrNativeType; hid_t hAttrSpace; char *szData = NULL; hsize_t nSize[64]; unsigned int nAttrElmts; hsize_t nAttrSize; hsize_t i; void *buf = NULL; unsigned int nAttrDims; char **papszTokens; HDF5Dataset *poDS; CPLString osKey; char *szValue = NULL; poDS = (HDF5Dataset *) pDS; // Convert "/" into "_" for the path component const char* pszPath = poDS->poH5CurrentObject->pszUnderscorePath; if(pszPath != NULL && strlen(pszPath) > 0) { papszTokens = CSLTokenizeString2( pszPath, "/", CSLT_HONOURSTRINGS ); for( i = 0; papszTokens != NULL && papszTokens[i] != NULL; ++i ) { if( i != 0) osKey += '_'; osKey += papszTokens[i]; } CSLDestroy( papszTokens ); } // Convert whitespaces into "_" for the attribute name component papszTokens = CSLTokenizeString2( pszAttrName, " ", CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES ); for( i = 0; papszTokens != NULL && papszTokens[i] != NULL; ++i ) { if(!osKey.empty()) osKey += '_'; osKey += papszTokens[i]; } CSLDestroy( papszTokens ); hAttrID = H5Aopen_name( hH5ObjID, pszAttrName ); hAttrTypeID = H5Aget_type( hAttrID ); hAttrNativeType = H5Tget_native_type( hAttrTypeID, H5T_DIR_DEFAULT ); hAttrSpace = H5Aget_space( hAttrID ); nAttrDims = H5Sget_simple_extent_dims( hAttrSpace, nSize, NULL ); nAttrElmts = 1; for( i=0; i < nAttrDims; i++ ) { nAttrElmts *= (int) nSize[i]; } if( H5Tget_class( hAttrNativeType ) == H5T_STRING ) { if ( H5Tis_variable_str(hAttrNativeType) ) { char** papszStrings; papszStrings = (char**) CPLMalloc( nAttrElmts * sizeof(char*) ); // Read the values H5Aread( hAttrID, hAttrNativeType, papszStrings ); // Concatenate all values as one string (separated by a space) CPLString osVal = papszStrings[0]; for( i=1; i < nAttrElmts; i++ ) { osVal += " "; osVal += papszStrings[i]; } szValue = (char*) CPLMalloc(osVal.length() + 1); strcpy( szValue, osVal.c_str() ); H5Dvlen_reclaim( hAttrNativeType, hAttrSpace, H5P_DEFAULT, papszStrings ); CPLFree( papszStrings ); } else { nAttrSize = H5Aget_storage_size( hAttrID ); szValue = (char*) CPLMalloc((size_t) (nAttrSize+1)); H5Aread( hAttrID, hAttrNativeType, szValue ); szValue[nAttrSize] = '\0'; } } else { if( nAttrElmts > 0 ) { buf = (void *) CPLMalloc( nAttrElmts* H5Tget_size( hAttrNativeType )); szData = (char*) CPLMalloc( 8192 ); szValue = (char*) CPLMalloc( MAX_METADATA_LEN ); szData[0] = '\0'; szValue[0] ='\0'; H5Aread( hAttrID, hAttrNativeType, buf ); } if( H5Tequal( H5T_NATIVE_CHAR, hAttrNativeType ) || H5Tequal( H5T_NATIVE_SCHAR, hAttrNativeType ) ) { for( i=0; i < nAttrElmts; i++ ) { sprintf( szData, "%c ", ((char *) buf)[i]); if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >= MAX_METADATA_LEN ) CPLError( CE_Warning, CPLE_OutOfMemory, "Header data too long. Truncated\n"); } } else if( H5Tequal( H5T_NATIVE_UCHAR, hAttrNativeType ) ) { for( i=0; i < nAttrElmts; i++ ) { sprintf( szData, "%c", ((char *) buf)[i] ); if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >= MAX_METADATA_LEN ) CPLError( CE_Warning, CPLE_OutOfMemory, "Header data too long. Truncated\n"); } } else if( H5Tequal( H5T_NATIVE_SHORT, hAttrNativeType ) ) { for( i=0; i < nAttrElmts; i++ ) { sprintf( szData, "%d ", ((short *) buf)[i] ); if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >= MAX_METADATA_LEN ) CPLError( CE_Warning, CPLE_OutOfMemory, "Header data too long. Truncated\n"); } } else if( H5Tequal( H5T_NATIVE_USHORT, hAttrNativeType ) ) { for( i=0; i < nAttrElmts; i++ ) { sprintf( szData, "%ud ", ((unsigned short *) buf)[i] ); if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >= MAX_METADATA_LEN ) CPLError( CE_Warning, CPLE_OutOfMemory, "Header data too long. Truncated\n"); } } else if( H5Tequal( H5T_NATIVE_INT, hAttrNativeType ) ) { for( i=0; i < nAttrElmts; i++ ) { sprintf( szData, "%d ", ((int *) buf)[i] ); if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >= MAX_METADATA_LEN ) CPLError( CE_Warning, CPLE_OutOfMemory, "Header data too long. Truncated\n"); } } else if( H5Tequal( H5T_NATIVE_UINT, hAttrNativeType ) ) { for( i=0; i < nAttrElmts; i++ ) { sprintf( szData, "%ud ", ((unsigned int *) buf)[i] ); if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >= MAX_METADATA_LEN ) CPLError( CE_Warning, CPLE_OutOfMemory, "Header data too long. Truncated\n"); } } else if( H5Tequal( H5T_NATIVE_LONG, hAttrNativeType ) ) { for( i=0; i < nAttrElmts; i++ ) { sprintf( szData, "%ld ", ((long *)buf)[i] ); if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >= MAX_METADATA_LEN ) CPLError( CE_Warning, CPLE_OutOfMemory, "Header data too long. Truncated\n"); } } else if( H5Tequal( H5T_NATIVE_ULONG, hAttrNativeType ) ) { for( i=0; i < nAttrElmts; i++ ) { sprintf( szData, "%ld ", ((unsigned long *)buf)[i] ); if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >= MAX_METADATA_LEN ) CPLError( CE_Warning, CPLE_OutOfMemory, "Header data too long. Truncated\n"); } } else if( H5Tequal( H5T_NATIVE_FLOAT, hAttrNativeType ) ) { for( i=0; i < nAttrElmts; i++ ) { sprintf( szData, "%.8g ", ((float *)buf)[i] ); if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >= MAX_METADATA_LEN ) CPLError( CE_Warning, CPLE_OutOfMemory, "Header data too long. Truncated\n"); } } else if( H5Tequal( H5T_NATIVE_DOUBLE, hAttrNativeType ) ) { for( i=0; i < nAttrElmts; i++ ) { sprintf( szData, "%.15g ", ((double *)buf)[i] ); if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >= MAX_METADATA_LEN ) CPLError( CE_Warning, CPLE_OutOfMemory, "Header data too long. Truncated\n"); } } CPLFree( buf ); } H5Sclose(hAttrSpace); H5Tclose(hAttrNativeType); H5Tclose(hAttrTypeID); H5Aclose( hAttrID ); poDS->papszMetadata = CSLSetNameValue( poDS->papszMetadata, osKey, szValue); CPLFree( szData ); CPLFree( szValue ); return 0; } /************************************************************************/ /* CreateMetadata() */ /************************************************************************/ CPLErr HDF5Dataset::CreateMetadata( HDF5GroupObjects *poH5Object, int nType) { hid_t hGroupID; /* identifier of group */ hid_t hDatasetID; int nbAttrs; HDF5Dataset *poDS; if( !poH5Object->pszPath ) return CE_None; poDS = this; poH5CurrentObject = poH5Object; nbAttrs = poH5Object->nbAttrs; if( poH5Object->pszPath == NULL || EQUAL(poH5Object->pszPath, "" ) ) return CE_None; switch( nType ) { case H5G_GROUP: if( nbAttrs > 0 ) { hGroupID = H5Gopen( hHDF5, poH5Object->pszPath ); H5Aiterate( hGroupID, NULL, HDF5AttrIterate, (void *)poDS ); H5Gclose( hGroupID ); } break; case H5G_DATASET: if( nbAttrs > 0 ) { hDatasetID = H5Dopen(hHDF5, poH5Object->pszPath ); H5Aiterate( hDatasetID, NULL, HDF5AttrIterate, (void *)poDS ); H5Dclose( hDatasetID ); } break; default: break; } return CE_None; } /************************************************************************/ /* HDF5FindDatasetObjectsbyPath() */ /* Find object by name */ /************************************************************************/ HDF5GroupObjects* HDF5Dataset::HDF5FindDatasetObjectsbyPath ( HDF5GroupObjects *poH5Objects, const char* pszDatasetPath ) { unsigned i; HDF5Dataset *poDS; HDF5GroupObjects *poObjectsFound; poDS=this; if( poH5Objects->nType == H5G_DATASET && EQUAL( poH5Objects->pszUnderscorePath,pszDatasetPath ) ) { /* printf("found it! %ld\n",(long) poH5Objects);*/ return( poH5Objects ); } if( poH5Objects->nbObjs >0 ) for( i=0; i <poH5Objects->nbObjs; i++ ) { poObjectsFound= poDS->HDF5FindDatasetObjectsbyPath( poH5Objects->poHchild+i, pszDatasetPath ); /* -------------------------------------------------------------------- */ /* Is this our dataset?? */ /* -------------------------------------------------------------------- */ if( poObjectsFound != NULL ) return( poObjectsFound ); } /* -------------------------------------------------------------------- */ /* Dataset has not been found! */ /* -------------------------------------------------------------------- */ return( NULL ); } /************************************************************************/ /* HDF5FindDatasetObjects() */ /* Find object by name */ /************************************************************************/ HDF5GroupObjects* HDF5Dataset::HDF5FindDatasetObjects ( HDF5GroupObjects *poH5Objects, const char* pszDatasetName ) { unsigned i; HDF5Dataset *poDS; HDF5GroupObjects *poObjectsFound; poDS=this; if( poH5Objects->nType == H5G_DATASET && EQUAL( poH5Objects->pszName,pszDatasetName ) ) { /* printf("found it! %ld\n",(long) poH5Objects);*/ return( poH5Objects ); } if( poH5Objects->nbObjs >0 ) for( i=0; i <poH5Objects->nbObjs; i++ ) { poObjectsFound= poDS->HDF5FindDatasetObjects( poH5Objects->poHchild+i, pszDatasetName ); /* -------------------------------------------------------------------- */ /* Is this our dataset?? */ /* -------------------------------------------------------------------- */ if( poObjectsFound != NULL ) return( poObjectsFound ); } /* -------------------------------------------------------------------- */ /* Dataset has not been found! */ /* -------------------------------------------------------------------- */ return( NULL ); } /************************************************************************/ /* HDF5ListGroupObjects() */ /* */ /* List all objects in HDF5 */ /************************************************************************/ CPLErr HDF5Dataset::HDF5ListGroupObjects( HDF5GroupObjects *poRootGroup, int bSUBDATASET ) { char szTemp[8192]; char szDim[8192]; HDF5Dataset *poDS; poDS=this; if( poRootGroup->nbObjs >0 ) for( hsize_t i=0; i < poRootGroup->nbObjs; i++ ) { poDS->HDF5ListGroupObjects( poRootGroup->poHchild+i, bSUBDATASET ); } if( poRootGroup->nType == H5G_GROUP ) { CreateMetadata( poRootGroup, H5G_GROUP ); } /* -------------------------------------------------------------------- */ /* Create Sub dataset list */ /* -------------------------------------------------------------------- */ if( (poRootGroup->nType == H5G_DATASET ) && bSUBDATASET && poDS->GetDataType( poRootGroup->native ) == GDT_Unknown ) { CPLDebug( "HDF5", "Skipping unsupported %s of type %s", poRootGroup->pszUnderscorePath, poDS->GetDataTypeName( poRootGroup->native ) ); } else if( (poRootGroup->nType == H5G_DATASET ) && bSUBDATASET ) { CreateMetadata( poRootGroup, H5G_DATASET ); szDim[0]='\0'; switch( poRootGroup->nRank ) { case 3: sprintf( szTemp,"%dx%dx%d", (int)poRootGroup->paDims[0], (int)poRootGroup->paDims[1], (int)poRootGroup->paDims[2] ); break; case 2: sprintf( szTemp,"%dx%d", (int)poRootGroup->paDims[0], (int)poRootGroup->paDims[1] ); break; default: return CE_None; } strcat( szDim,szTemp ); sprintf( szTemp, "SUBDATASET_%d_NAME", ++(poDS->nSubDataCount) ); poDS->papszSubDatasets = CSLSetNameValue( poDS->papszSubDatasets, szTemp, CPLSPrintf( "HDF5:\"%s\":%s", poDS->GetDescription(), poRootGroup->pszUnderscorePath ) ); sprintf( szTemp, "SUBDATASET_%d_DESC", poDS->nSubDataCount ); poDS->papszSubDatasets = CSLSetNameValue( poDS->papszSubDatasets, szTemp, CPLSPrintf( "[%s] %s (%s)", szDim, poRootGroup->pszUnderscorePath, poDS->GetDataTypeName ( poRootGroup->native ) ) ); } return CE_None; } /************************************************************************/ /* ReadGlobalAttributes() */ /************************************************************************/ CPLErr HDF5Dataset::ReadGlobalAttributes(int bSUBDATASET) { HDF5GroupObjects *poRootGroup; poRootGroup = (HDF5GroupObjects*) CPLCalloc(sizeof(HDF5GroupObjects), 1); poH5RootGroup=poRootGroup; poRootGroup->pszName = CPLStrdup( "/" ); poRootGroup->nType = H5G_GROUP; poRootGroup->poHparent = NULL; poRootGroup->pszPath = NULL; poRootGroup->pszUnderscorePath = NULL; if( hHDF5 < 0 ) { printf( "hHDF5 <0!!\n" ); return CE_None; } H5G_stat_t oStatbuf; if( H5Gget_objinfo( hHDF5, "/", FALSE, &oStatbuf ) < 0 ) return CE_Failure; poRootGroup->objno[0] = oStatbuf.objno[0]; poRootGroup->objno[1] = oStatbuf.objno[1]; if( hGroupID > 0 ) H5Gclose( hGroupID ); hGroupID = H5Gopen( hHDF5, "/" ); if( hGroupID < 0 ){ printf( "hGroupID <0!!\n" ); return CE_None; } poRootGroup->nbAttrs = H5Aget_num_attrs( hGroupID ); H5Gget_num_objs( hGroupID, &( poRootGroup->nbObjs ) ); if( poRootGroup->nbObjs > 0 ) { poRootGroup->poHchild = ( HDF5GroupObjects * ) CPLCalloc( poRootGroup->nbObjs, sizeof( HDF5GroupObjects ) ); H5Giterate( hGroupID, "/", NULL, HDF5CreateGroupObjs, (void *)poRootGroup ); } else poRootGroup->poHchild = NULL; HDF5ListGroupObjects( poRootGroup, bSUBDATASET ); return CE_None; } /** * Reads an array of double attributes from the HDF5 metadata. * It reads the attributes directly on it's binary form directly, * thus avoiding string conversions. * * Important: It allocates the memory for the attributes internally, * so the caller must free the returned array after using it. * @param pszAttrName Name of the attribute to be read. * the attribute name must be the form: * root attribute name * SUBDATASET/subdataset attribute name * @param pdfValues pointer wich will store the array of doubles read. * @param nLen it stores the length of the array read. If NULL it doesn't * inform the lenght of the array. * @return CPLErr CE_None in case of success, CE_Failure in case of failure */ CPLErr HDF5Dataset::HDF5ReadDoubleAttr(const char* pszAttrFullPath, double **pdfValues,int *nLen) { CPLErr retVal = CE_Failure; hid_t hAttrID=-1; hid_t hAttrTypeID=-1; hid_t hAttrNativeType=-1; hid_t hAttrSpace=-1; hid_t hObjAttrID=-1; hsize_t nSize[64]; unsigned int nAttrElmts; hsize_t i; unsigned int nAttrDims; size_t nSlashPos; CPLString osAttrFullPath(pszAttrFullPath); CPLString osObjName; CPLString osAttrName; //Search for the last "/" in order to get the //Path to the attribute nSlashPos = osAttrFullPath.find_last_of("/"); //If objects name have been found if(nSlashPos != CPLString::npos ) { //Split Object name (dataset, group) osObjName = osAttrFullPath.substr(0,nSlashPos); //Split attribute name osAttrName = osAttrFullPath.substr(nSlashPos+1); } else { //By default the group is root, and //the attribute is the full path osObjName = "/"; osAttrName = pszAttrFullPath; } hObjAttrID = H5Oopen( hHDF5, osObjName.c_str(),H5P_DEFAULT); if(hObjAttrID < 0) { CPLError( CE_Failure, CPLE_OpenFailed, "Object %s could not be opened\n", pszAttrFullPath); retVal = CE_Failure; } else { //Open attribute handler by name, from the object handler opened //earlier hAttrID = H5Aopen_name( hObjAttrID, osAttrName.c_str()); //Check for errors opening the attribute if(hAttrID <0) { CPLError( CE_Failure, CPLE_OpenFailed, "Attribute %s could not be opened\n", pszAttrFullPath); retVal = CE_Failure; } else { hAttrTypeID = H5Aget_type( hAttrID ); hAttrNativeType = H5Tget_native_type( hAttrTypeID, H5T_DIR_DEFAULT ); hAttrSpace = H5Aget_space( hAttrID ); nAttrDims = H5Sget_simple_extent_dims( hAttrSpace, nSize, NULL ); if( !H5Tequal( H5T_NATIVE_DOUBLE, hAttrNativeType ) ) { CPLError( CE_Failure, CPLE_OpenFailed, "Attribute %s is not of type double\n", pszAttrFullPath); retVal = CE_Failure; } else { //Get the ammount of elements nAttrElmts = 1; for( i=0; i < nAttrDims; i++ ) { //For multidimensional attributes nAttrElmts *= nSize[i]; } if(nLen != NULL) *nLen = nAttrElmts; (*pdfValues) = (double *) CPLMalloc(nAttrElmts*sizeof(double)); //Read the attribute contents if(H5Aread( hAttrID, hAttrNativeType, *pdfValues )<0) { CPLError( CE_Failure, CPLE_OpenFailed, "Attribute %s could not be opened\n", pszAttrFullPath); retVal = CE_Failure; } else { retVal = CE_None; } } H5Tclose(hAttrNativeType); H5Tclose(hAttrTypeID); H5Sclose(hAttrSpace); H5Aclose(hAttrID); } H5Oclose(hObjAttrID); } return retVal; }