1 : /******************************************************************************
2 : * $Id: hdf5dataset.cpp 23068 2011-09-06 20:50:23Z antonio $
3 : *
4 : * Project: Hierarchical Data Format Release 5 (HDF5)
5 : * Purpose: HDF5 Datasets. Open HDF5 file, fetch metadata and list of
6 : * subdatasets.
7 : * This driver initially based on code supplied by Markus Neteler
8 : * Author: Denis Nadeau <denis.nadeau@gmail.com>
9 : *
10 : ******************************************************************************
11 : * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #define H5_USE_16_API
33 :
34 : #define MAX_METADATA_LEN 32768
35 :
36 : #include "hdf5.h"
37 :
38 : #include "gdal_priv.h"
39 : #include "cpl_string.h"
40 : #include "hdf5dataset.h"
41 :
42 : CPL_CVSID("$Id: hdf5dataset.cpp 23068 2011-09-06 20:50:23Z antonio $");
43 :
44 : CPL_C_START
45 : void GDALRegister_HDF5(void);
46 : CPL_C_END
47 :
48 :
49 :
50 : /************************************************************************/
51 : /* ==================================================================== */
52 : /* HDF5Dataset */
53 : /* ==================================================================== */
54 : /************************************************************************/
55 :
56 : /************************************************************************/
57 : /* GDALRegister_HDF5() */
58 : /************************************************************************/
59 1135 : void GDALRegister_HDF5()
60 :
61 : {
62 : GDALDriver *poDriver;
63 1135 : if( GDALGetDriverByName("HDF5") == NULL )
64 : {
65 1093 : poDriver = new GDALDriver();
66 1093 : poDriver->SetDescription("HDF5");
67 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
68 1093 : "Hierarchical Data Format Release 5");
69 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
70 1093 : "frmt_hdf5.html");
71 1093 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "hdf5");
72 1093 : poDriver->pfnOpen = HDF5Dataset::Open;
73 1093 : poDriver->pfnIdentify = HDF5Dataset::Identify;
74 1093 : GetGDALDriverManager()->RegisterDriver(poDriver);
75 : }
76 1135 : }
77 :
78 : /************************************************************************/
79 : /* HDF5Dataset() */
80 : /************************************************************************/
81 28 : HDF5Dataset::HDF5Dataset()
82 : {
83 28 : papszSubDatasets = NULL;
84 28 : papszMetadata = NULL;
85 28 : poH5RootGroup = NULL;
86 28 : nSubDataCount = 0;
87 28 : hHDF5 = -1;
88 28 : hDatasetID = -1;
89 28 : hGroupID = -1;
90 28 : bIsHDFEOS = FALSE;
91 28 : nDatasetType = -1;
92 28 : }
93 :
94 : /************************************************************************/
95 : /* ~HDF5Dataset() */
96 : /************************************************************************/
97 28 : HDF5Dataset::~HDF5Dataset()
98 : {
99 28 : CSLDestroy( papszMetadata );
100 28 : if( hHDF5 > 0 )
101 28 : H5Fclose( hHDF5 );
102 28 : if( hGroupID > 0 )
103 28 : H5Gclose( hGroupID );
104 28 : CSLDestroy( papszSubDatasets );
105 28 : if( poH5RootGroup != NULL ) {
106 28 : DestroyH5Objects( poH5RootGroup );
107 28 : CPLFree( poH5RootGroup->pszName );
108 28 : CPLFree( poH5RootGroup->pszPath );
109 28 : CPLFree( poH5RootGroup->pszUnderscorePath );
110 28 : CPLFree( poH5RootGroup->poHchild );
111 28 : CPLFree( poH5RootGroup );
112 : }
113 28 : }
114 :
115 : /************************************************************************/
116 : /* GetDataType() */
117 : /* */
118 : /* Transform HDF5 datatype to GDAL datatype */
119 : /************************************************************************/
120 106 : GDALDataType HDF5Dataset::GetDataType(hid_t TypeID)
121 : {
122 106 : if( H5Tequal( H5T_NATIVE_CHAR, TypeID ) )
123 0 : return GDT_Byte;
124 106 : else if( H5Tequal( H5T_NATIVE_UCHAR, TypeID ) )
125 12 : return GDT_Byte;
126 94 : else if( H5Tequal( H5T_NATIVE_SHORT, TypeID ) )
127 2 : return GDT_Int16;
128 92 : else if( H5Tequal( H5T_NATIVE_USHORT, TypeID ) )
129 0 : return GDT_UInt16;
130 92 : else if( H5Tequal( H5T_NATIVE_INT, TypeID ) )
131 92 : return GDT_Int32;
132 0 : else if( H5Tequal( H5T_NATIVE_UINT, TypeID ) )
133 0 : return GDT_UInt32;
134 0 : else if( H5Tequal( H5T_NATIVE_LONG, TypeID ) )
135 : {
136 : if( sizeof(long) == 4 )
137 : return GDT_Int32;
138 : else
139 0 : return GDT_Unknown;
140 : }
141 0 : else if( H5Tequal( H5T_NATIVE_ULONG, TypeID ) )
142 : {
143 : if( sizeof(unsigned long) == 4 )
144 : return GDT_UInt32;
145 : else
146 0 : return GDT_Unknown;
147 : }
148 0 : else if( H5Tequal( H5T_NATIVE_FLOAT, TypeID ) )
149 0 : return GDT_Float32;
150 0 : else if( H5Tequal( H5T_NATIVE_DOUBLE, TypeID ) )
151 0 : return GDT_Float64;
152 0 : else if( H5Tequal( H5T_NATIVE_LLONG, TypeID ) )
153 0 : return GDT_Unknown;
154 0 : else if( H5Tequal( H5T_NATIVE_ULLONG, TypeID ) )
155 0 : return GDT_Unknown;
156 0 : else if( H5Tequal( H5T_NATIVE_DOUBLE, TypeID ) )
157 0 : return GDT_Unknown;
158 :
159 0 : return GDT_Unknown;
160 : }
161 :
162 : /************************************************************************/
163 : /* GetDataTypeName() */
164 : /* */
165 : /* Return the human readable name of data type */
166 : /************************************************************************/
167 86 : const char *HDF5Dataset::GetDataTypeName(hid_t TypeID)
168 : {
169 86 : if( H5Tequal( H5T_NATIVE_CHAR, TypeID ) )
170 0 : return "8-bit character";
171 86 : else if( H5Tequal( H5T_NATIVE_UCHAR, TypeID ) )
172 2 : return "8-bit unsigned character";
173 84 : else if( H5Tequal( H5T_NATIVE_SHORT, TypeID ) )
174 0 : return "16-bit integer";
175 84 : else if( H5Tequal( H5T_NATIVE_USHORT, TypeID ) )
176 0 : return "16-bit unsigned integer";
177 84 : else if( H5Tequal( H5T_NATIVE_INT, TypeID ) )
178 84 : return "32-bit integer";
179 0 : else if( H5Tequal( H5T_NATIVE_UINT, TypeID ) )
180 0 : return "32-bit unsigned integer";
181 0 : else if( H5Tequal( H5T_NATIVE_LONG, TypeID ) )
182 0 : return "32/64-bit integer";
183 0 : else if( H5Tequal( H5T_NATIVE_ULONG, TypeID ) )
184 0 : return "32/64-bit unsigned integer";
185 0 : else if( H5Tequal( H5T_NATIVE_FLOAT, TypeID ) )
186 0 : return "32-bit floating-point";
187 0 : else if( H5Tequal( H5T_NATIVE_DOUBLE, TypeID ) )
188 0 : return "64-bit floating-point";
189 0 : else if( H5Tequal( H5T_NATIVE_LLONG, TypeID ) )
190 0 : return "64-bit integer";
191 0 : else if( H5Tequal( H5T_NATIVE_ULLONG, TypeID ) )
192 0 : return "64-bit unsigned integer";
193 0 : else if( H5Tequal( H5T_NATIVE_DOUBLE, TypeID ) )
194 0 : return "64-bit floating-point";
195 :
196 0 : return "Unknown";
197 : }
198 :
199 : /************************************************************************/
200 : /* Identify() */
201 : /************************************************************************/
202 :
203 22268 : int HDF5Dataset::Identify( GDALOpenInfo * poOpenInfo )
204 :
205 : {
206 : /* -------------------------------------------------------------------- */
207 : /* Is it an HDF5 file? */
208 : /* -------------------------------------------------------------------- */
209 : static const char achSignature[] = "\211HDF\r\n\032\n";
210 :
211 22268 : if( poOpenInfo->pabyHeader )
212 : {
213 1108 : if( memcmp(poOpenInfo->pabyHeader,achSignature,8) == 0 )
214 8 : return TRUE;
215 :
216 1100 : if( memcmp(poOpenInfo->pabyHeader,"<HDF_UserBlock>",15) == 0)
217 : {
218 0 : if( H5Fis_hdf5(poOpenInfo->pszFilename) )
219 0 : return TRUE;
220 : }
221 : }
222 :
223 22260 : return FALSE;
224 : }
225 :
226 : /************************************************************************/
227 : /* Open() */
228 : /************************************************************************/
229 3360 : GDALDataset *HDF5Dataset::Open( GDALOpenInfo * poOpenInfo )
230 : {
231 : HDF5Dataset *poDS;
232 : CPLErr Err;
233 :
234 3360 : if( !Identify( poOpenInfo ) )
235 3352 : return NULL;
236 :
237 : /* -------------------------------------------------------------------- */
238 : /* Create datasource. */
239 : /* -------------------------------------------------------------------- */
240 8 : poDS = new HDF5Dataset();
241 :
242 8 : poDS->SetDescription( poOpenInfo->pszFilename );
243 :
244 : /* -------------------------------------------------------------------- */
245 : /* Try opening the dataset. */
246 : /* -------------------------------------------------------------------- */
247 : poDS->hHDF5 = H5Fopen( poOpenInfo->pszFilename,
248 : H5F_ACC_RDONLY,
249 8 : H5P_DEFAULT );
250 8 : if( poDS->hHDF5 < 0 ) {
251 0 : delete poDS;
252 0 : return NULL;
253 : }
254 :
255 8 : poDS->hGroupID = H5Gopen( poDS->hHDF5, "/" );
256 8 : if( poDS->hGroupID < 0 ) {
257 0 : poDS->bIsHDFEOS=false;
258 0 : delete poDS;
259 0 : return NULL;
260 : }
261 :
262 8 : poDS->bIsHDFEOS=true;
263 8 : Err = poDS->ReadGlobalAttributes( true );
264 :
265 8 : poDS->SetMetadata( poDS->papszMetadata );
266 :
267 8 : if ( CSLCount( poDS->papszSubDatasets ) / 2 >= 1 )
268 8 : poDS->SetMetadata( poDS->papszSubDatasets, "SUBDATASETS" );
269 :
270 : // Make sure we don't try to do any pam stuff with this dataset.
271 8 : poDS->nPamFlags |= GPF_NOSAVE;
272 :
273 : /* -------------------------------------------------------------------- */
274 : /* If we have single subdataset only, open it immediately */
275 : /* -------------------------------------------------------------------- */
276 8 : int nSubDatasets = CSLCount( poDS->papszSubDatasets ) / 2;
277 8 : if( nSubDatasets == 1 )
278 : {
279 : CPLString osDSName = CSLFetchNameValue( poDS->papszSubDatasets,
280 2 : "SUBDATASET_1_NAME" );
281 2 : delete poDS;
282 2 : return (GDALDataset *) GDALOpen( osDSName, poOpenInfo->eAccess );
283 : }
284 : else
285 : {
286 : /* -------------------------------------------------------------------- */
287 : /* Confirm the requested access is supported. */
288 : /* -------------------------------------------------------------------- */
289 6 : if( poOpenInfo->eAccess == GA_Update )
290 : {
291 0 : delete poDS;
292 : CPLError( CE_Failure, CPLE_NotSupported,
293 : "The HDF5 driver does not support update access to existing"
294 0 : " datasets.\n" );
295 0 : return NULL;
296 : }
297 : }
298 6 : return( poDS );
299 : }
300 :
301 : /************************************************************************/
302 : /* DestroyH5Objects() */
303 : /* */
304 : /* Erase all objects */
305 : /************************************************************************/
306 212 : void HDF5Dataset::DestroyH5Objects( HDF5GroupObjects *poH5Object )
307 : {
308 : unsigned i;
309 :
310 : /* -------------------------------------------------------------------- */
311 : /* Visit all objects */
312 : /* -------------------------------------------------------------------- */
313 :
314 396 : for( i=0; i < poH5Object->nbObjs; i++ )
315 184 : if( poH5Object->poHchild+i != NULL )
316 184 : DestroyH5Objects( poH5Object->poHchild+i );
317 :
318 212 : if( poH5Object->poHparent ==NULL )
319 28 : return;
320 :
321 : /* -------------------------------------------------------------------- */
322 : /* Erase some data */
323 : /* -------------------------------------------------------------------- */
324 184 : CPLFree( poH5Object->paDims );
325 184 : poH5Object->paDims = NULL;
326 :
327 184 : CPLFree( poH5Object->pszPath );
328 184 : poH5Object->pszPath = NULL;
329 :
330 184 : CPLFree( poH5Object->pszName );
331 184 : poH5Object->pszName = NULL;
332 :
333 184 : CPLFree( poH5Object->pszUnderscorePath );
334 184 : poH5Object->pszUnderscorePath = NULL;
335 : /* -------------------------------------------------------------------- */
336 : /* All Children are visited and can be deleted. */
337 : /* -------------------------------------------------------------------- */
338 184 : if( ( i==poH5Object->nbObjs ) && ( poH5Object->nbObjs!=0 ) ) {
339 52 : CPLFree( poH5Object->poHchild );
340 52 : poH5Object->poHchild = NULL;
341 : }
342 :
343 : }
344 :
345 : /************************************************************************/
346 : /* CreatePath() */
347 : /* */
348 : /* Find Dataset path for HDopen */
349 : /************************************************************************/
350 514 : char* CreatePath( HDF5GroupObjects *poH5Object )
351 : {
352 : char pszPath[8192];
353 : char pszUnderscoreSpaceInName[8192];
354 : char *popszPath;
355 : int i;
356 : char **papszPath;
357 :
358 : /* -------------------------------------------------------------------- */
359 : /* Recurse to the root path */
360 : /* -------------------------------------------------------------------- */
361 514 : pszPath[0]='\0';
362 514 : if( poH5Object->poHparent !=NULL ) {
363 330 : popszPath=CreatePath( poH5Object->poHparent );
364 330 : strcpy( pszPath,popszPath );
365 : }
366 :
367 : /* -------------------------------------------------------------------- */
368 : /* add name to the path */
369 : /* -------------------------------------------------------------------- */
370 514 : if( !EQUAL( poH5Object->pszName,"/" ) ){
371 330 : strcat( pszPath,"/" );
372 330 : strcat( pszPath,poH5Object->pszName );
373 : }
374 :
375 : /* -------------------------------------------------------------------- */
376 : /* fill up path for each object */
377 : /* -------------------------------------------------------------------- */
378 514 : if( poH5Object->pszPath == NULL ) {
379 :
380 212 : if( strlen( poH5Object->pszName ) == 1 ) {
381 28 : strcat(pszPath, poH5Object->pszName );
382 28 : strcpy(pszUnderscoreSpaceInName, poH5Object->pszName);
383 : }
384 : else {
385 : /* -------------------------------------------------------------------- */
386 : /* Change space for underscore */
387 : /* -------------------------------------------------------------------- */
388 : papszPath = CSLTokenizeString2( pszPath,
389 184 : " ", CSLT_HONOURSTRINGS );
390 :
391 184 : strcpy(pszUnderscoreSpaceInName,papszPath[0]);
392 360 : for( i=1; i < CSLCount( papszPath ); i++ ) {
393 176 : strcat( pszUnderscoreSpaceInName, "_" );
394 176 : strcat( pszUnderscoreSpaceInName, papszPath[ i ] );
395 : }
396 184 : CSLDestroy(papszPath);
397 :
398 : }
399 : poH5Object->pszUnderscorePath =
400 212 : CPLStrdup( pszUnderscoreSpaceInName );
401 212 : poH5Object->pszPath = CPLStrdup( pszPath );
402 : }
403 :
404 514 : return( poH5Object->pszPath );
405 : }
406 :
407 : /************************************************************************/
408 : /* HDF5GroupCheckDuplicate() */
409 : /* */
410 : /* Returns TRUE if an ancestor has the same objno[] as passed */
411 : /* in - used to avoid looping in files with "links up" #(3218). */
412 : /************************************************************************/
413 :
414 64 : static int HDF5GroupCheckDuplicate( HDF5GroupObjects *poHparent,
415 : unsigned long *objno )
416 :
417 : {
418 230 : while( poHparent != NULL )
419 : {
420 102 : if( poHparent->objno[0] == objno[0]
421 0 : && poHparent->objno[1] == objno[1] )
422 0 : return TRUE;
423 :
424 102 : poHparent = poHparent->poHparent;
425 : }
426 :
427 64 : return FALSE;
428 : }
429 :
430 : /************************************************************************/
431 : /* HDF5CreateGroupObjs() */
432 : /* */
433 : /* Create HDF5 hierarchy into a linked list */
434 : /************************************************************************/
435 184 : herr_t HDF5CreateGroupObjs(hid_t hHDF5, const char *pszObjName,
436 : void *poHObjParent)
437 : {
438 : herr_t ret; /* error return status */
439 : hid_t hGroupID; /* identifier of group */
440 : hid_t hDatasetID; /* identifier of dataset */
441 184 : hsize_t nbObjs=0; /* number of objects in a group */
442 184 : int nbAttrs=0; /* number of attributes in object */
443 : unsigned idx;
444 : int n_dims;
445 : H5G_stat_t oStatbuf;
446 184 : hsize_t *dims=NULL;
447 184 : hsize_t *maxdims=NULL;
448 : hid_t datatype;
449 : hid_t dataspace;
450 : hid_t native;
451 : herr_t status;
452 :
453 : HDF5GroupObjects *poHchild;
454 : HDF5GroupObjects *poHparent;
455 :
456 184 : poHparent = ( HDF5GroupObjects * ) poHObjParent;
457 184 : poHchild=poHparent->poHchild;
458 :
459 184 : if( H5Gget_objinfo( hHDF5, pszObjName, FALSE, &oStatbuf ) < 0 )
460 0 : return -1;
461 :
462 :
463 : /* -------------------------------------------------------------------- */
464 : /* Look for next child */
465 : /* -------------------------------------------------------------------- */
466 430 : for( idx=0; idx < poHparent->nbObjs; idx++ ) {
467 430 : if( poHchild->pszName == NULL ) break;
468 246 : poHchild++;
469 : }
470 :
471 184 : if( idx == poHparent->nbObjs )
472 0 : return -1; // all children parsed
473 :
474 : /* -------------------------------------------------------------------- */
475 : /* Save child information */
476 : /* -------------------------------------------------------------------- */
477 184 : poHchild->pszName = CPLStrdup( pszObjName );
478 :
479 184 : poHchild->nType = oStatbuf.type;
480 184 : poHchild->nIndex = idx;
481 184 : poHchild->poHparent = poHparent;
482 184 : poHchild->nRank = 0;
483 184 : poHchild->paDims = 0;
484 184 : poHchild->HDatatype = 0;
485 184 : poHchild->objno[0] = oStatbuf.objno[0];
486 184 : poHchild->objno[1] = oStatbuf.objno[1];
487 184 : if( poHchild->pszPath == NULL ) {
488 184 : poHchild->pszPath = CreatePath( poHchild );
489 : }
490 184 : if( poHparent->pszPath == NULL ) {
491 0 : poHparent->pszPath = CreatePath( poHparent );
492 : }
493 :
494 :
495 184 : switch ( oStatbuf.type )
496 : {
497 : case H5G_LINK:
498 0 : poHchild->nbAttrs = 0;
499 0 : poHchild->nbObjs = 0;
500 0 : poHchild->poHchild = NULL;
501 0 : poHchild->nRank = 0;
502 0 : poHchild->paDims = 0;
503 0 : poHchild->HDatatype = 0;
504 0 : break;
505 :
506 : case H5G_GROUP:
507 64 : if( ( hGroupID = H5Gopen( hHDF5, pszObjName ) ) == -1 ) {
508 : printf( "Error: unable to access \"%s\" group.\n",
509 0 : pszObjName );
510 0 : return -1;
511 : }
512 64 : nbAttrs = H5Aget_num_attrs( hGroupID );
513 64 : ret = H5Gget_num_objs( hGroupID, &nbObjs );
514 64 : poHchild->nbAttrs= nbAttrs;
515 64 : poHchild->nbObjs = (int) nbObjs;
516 64 : poHchild->nRank = 0;
517 64 : poHchild->paDims = 0;
518 64 : poHchild->HDatatype = 0;
519 :
520 64 : if( nbObjs > 0 ) {
521 : poHchild->poHchild =( HDF5GroupObjects * )
522 52 : CPLCalloc( (int)nbObjs, sizeof( HDF5GroupObjects ) );
523 : memset( poHchild->poHchild, 0,
524 52 : (size_t) (sizeof( HDF5GroupObjects ) * nbObjs) );
525 : }
526 : else
527 12 : poHchild->poHchild = NULL;
528 :
529 64 : if( !HDF5GroupCheckDuplicate( poHparent, oStatbuf.objno ) )
530 : H5Giterate( hHDF5, pszObjName, NULL,
531 64 : HDF5CreateGroupObjs, (void*) poHchild );
532 : else
533 : CPLDebug( "HDF5", "avoiding link looping on node '%s'.",
534 0 : pszObjName );
535 :
536 64 : H5Gclose( hGroupID );
537 64 : break;
538 :
539 : case H5G_DATASET:
540 :
541 120 : if( ( hDatasetID = H5Dopen( hHDF5, pszObjName ) ) == -1 ) {
542 : printf( "Error: unable to access \"%s\" dataset.\n",
543 0 : pszObjName );
544 0 : return -1;
545 : }
546 120 : nbAttrs = H5Aget_num_attrs( hDatasetID );
547 120 : datatype = H5Dget_type( hDatasetID );
548 120 : dataspace = H5Dget_space( hDatasetID );
549 120 : n_dims = H5Sget_simple_extent_ndims( dataspace );
550 120 : native = H5Tget_native_type( datatype, H5T_DIR_ASCEND );
551 :
552 120 : if( n_dims > 0 ) {
553 118 : dims = (hsize_t *) CPLCalloc( n_dims,sizeof( hsize_t ) );
554 118 : maxdims = (hsize_t *) CPLCalloc( n_dims,sizeof( hsize_t ) );
555 : }
556 120 : status = H5Sget_simple_extent_dims( dataspace, dims, maxdims );
557 120 : if( maxdims != NULL )
558 118 : CPLFree( maxdims );
559 :
560 120 : if( n_dims > 0 ) {
561 118 : poHchild->nRank = n_dims; // rank of the array
562 118 : poHchild->paDims = dims; // dimmension of the array.
563 118 : poHchild->HDatatype = datatype; // HDF5 datatype
564 : }
565 : else {
566 2 : poHchild->nRank = -1;
567 2 : poHchild->paDims = NULL;
568 2 : poHchild->HDatatype = 0;
569 : }
570 120 : poHchild->nbAttrs = nbAttrs;
571 120 : poHchild->nbObjs = 0;
572 120 : poHchild->poHchild = NULL;
573 120 : poHchild->native = native;
574 120 : ret = H5Dclose( hDatasetID );
575 120 : break;
576 :
577 : case H5G_TYPE:
578 0 : poHchild->nbAttrs = 0;
579 0 : poHchild->nbObjs = 0;
580 0 : poHchild->poHchild = NULL;
581 0 : poHchild->nRank = 0;
582 0 : poHchild->paDims = 0;
583 0 : poHchild->HDatatype = 0;
584 : break;
585 :
586 : default:
587 : break;
588 : }
589 :
590 184 : return 0;
591 : }
592 :
593 :
594 : /************************************************************************/
595 : /* HDF5AttrIterate() */
596 : /************************************************************************/
597 :
598 678 : herr_t HDF5AttrIterate( hid_t hH5ObjID,
599 : const char *pszAttrName,
600 : void *pDS )
601 : {
602 : hid_t hAttrID;
603 : hid_t hAttrTypeID;
604 : hid_t hAttrNativeType;
605 : hid_t hAttrSpace;
606 :
607 678 : char *szData = NULL;
608 : hsize_t nSize[64];
609 : unsigned int nAttrElmts;
610 : hsize_t nAttrSize;
611 : hsize_t i;
612 678 : void *buf = NULL;
613 : unsigned int nAttrDims;
614 :
615 : char **papszTokens;
616 :
617 : HDF5Dataset *poDS;
618 678 : CPLString osKey;
619 678 : char *szValue = NULL;
620 :
621 678 : poDS = (HDF5Dataset *) pDS;
622 :
623 : // Convert "/" into "_" for the path component
624 678 : const char* pszPath = poDS->poH5CurrentObject->pszUnderscorePath;
625 678 : if(pszPath != NULL && strlen(pszPath) > 0)
626 : {
627 678 : papszTokens = CSLTokenizeString2( pszPath, "/", CSLT_HONOURSTRINGS );
628 :
629 1396 : for( int i = 0; papszTokens != NULL && papszTokens[i] != NULL; ++i )
630 : {
631 718 : if( i != 0)
632 276 : osKey += '_';
633 718 : osKey += papszTokens[i];
634 : }
635 678 : CSLDestroy( papszTokens );
636 : }
637 :
638 : // Convert whitespaces into "_" for the attribute name component
639 : papszTokens = CSLTokenizeString2( pszAttrName, " ",
640 678 : CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES );
641 1984 : for( int i = 0; papszTokens != NULL && papszTokens[i] != NULL; ++i )
642 : {
643 1306 : if(!osKey.empty())
644 1070 : osKey += '_';
645 1306 : osKey += papszTokens[i];
646 : }
647 678 : CSLDestroy( papszTokens );
648 :
649 678 : hAttrID = H5Aopen_name( hH5ObjID, pszAttrName );
650 678 : hAttrTypeID = H5Aget_type( hAttrID );
651 678 : hAttrNativeType = H5Tget_native_type( hAttrTypeID, H5T_DIR_DEFAULT );
652 678 : hAttrSpace = H5Aget_space( hAttrID );
653 678 : nAttrDims = H5Sget_simple_extent_dims( hAttrSpace, nSize, NULL );
654 :
655 678 : nAttrElmts = 1;
656 1108 : for( i=0; i < nAttrDims; i++ ) {
657 430 : nAttrElmts *= (int) nSize[i];
658 : }
659 :
660 678 : if( H5Tget_class( hAttrNativeType ) == H5T_STRING )
661 : {
662 262 : if ( H5Tis_variable_str(hAttrNativeType) )
663 : {
664 : char** papszStrings;
665 24 : papszStrings = (char**) CPLMalloc( nAttrElmts * sizeof(char*) );
666 :
667 : // Read the values
668 24 : H5Aread( hAttrID, hAttrNativeType, papszStrings );
669 :
670 : // Concatenate all values as one string (separated by a space)
671 24 : CPLString osVal = papszStrings[0];
672 76 : for( i=1; i < nAttrElmts; i++ ) {
673 52 : osVal += " ";
674 52 : osVal += papszStrings[i];
675 : }
676 :
677 24 : szValue = (char*) CPLMalloc(osVal.length() + 1);
678 24 : strcpy( szValue, osVal.c_str() );
679 :
680 : H5Dvlen_reclaim( hAttrNativeType, hAttrSpace, H5P_DEFAULT,
681 24 : papszStrings );
682 24 : CPLFree( papszStrings );
683 : }
684 : else
685 : {
686 238 : nAttrSize = H5Aget_storage_size( hAttrID );
687 238 : szValue = (char*) CPLMalloc((size_t) (nAttrSize+1));
688 238 : H5Aread( hAttrID, hAttrNativeType, szValue );
689 238 : szValue[nAttrSize] = '\0';
690 : }
691 : }
692 : else {
693 416 : if( nAttrElmts > 0 ) {
694 : buf = (void *) CPLMalloc( nAttrElmts*
695 416 : H5Tget_size( hAttrNativeType ));
696 416 : szData = (char*) CPLMalloc( 8192 );
697 416 : szValue = (char*) CPLMalloc( MAX_METADATA_LEN );
698 416 : szData[0] = '\0';
699 416 : szValue[0] ='\0';
700 416 : H5Aread( hAttrID, hAttrNativeType, buf );
701 : }
702 416 : if( H5Tequal( H5T_NATIVE_CHAR, hAttrNativeType ) ){
703 0 : for( i=0; i < nAttrElmts; i++ ) {
704 0 : sprintf( szData, "%c ", ((char *) buf)[i]);
705 0 : if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >=
706 : MAX_METADATA_LEN )
707 : CPLError( CE_Warning, CPLE_OutOfMemory,
708 0 : "Header data too long. Truncated\n");
709 : }
710 : }
711 416 : else if( H5Tequal( H5T_NATIVE_UCHAR, hAttrNativeType ) ) {
712 0 : for( i=0; i < nAttrElmts; i++ ) {
713 0 : sprintf( szData, "%c", ((char *) buf)[i] );
714 0 : if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >=
715 : MAX_METADATA_LEN )
716 : CPLError( CE_Warning, CPLE_OutOfMemory,
717 0 : "Header data too long. Truncated\n");
718 : }
719 : }
720 416 : else if( H5Tequal( H5T_NATIVE_SHORT, hAttrNativeType ) ) {
721 100 : for( i=0; i < nAttrElmts; i++ ) {
722 50 : sprintf( szData, "%d ", ((short *) buf)[i] );
723 50 : if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >=
724 : MAX_METADATA_LEN )
725 : CPLError( CE_Warning, CPLE_OutOfMemory,
726 0 : "Header data too long. Truncated\n");
727 : }
728 : }
729 366 : else if( H5Tequal( H5T_NATIVE_USHORT, hAttrNativeType ) ) {
730 40 : for( i=0; i < nAttrElmts; i++ ) {
731 20 : sprintf( szData, "%ud ", ((unsigned short *) buf)[i] );
732 20 : if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >=
733 : MAX_METADATA_LEN )
734 : CPLError( CE_Warning, CPLE_OutOfMemory,
735 0 : "Header data too long. Truncated\n");
736 : }
737 : }
738 346 : else if( H5Tequal( H5T_NATIVE_INT, hAttrNativeType ) ) {
739 248 : for( i=0; i < nAttrElmts; i++ ) {
740 124 : sprintf( szData, "%d ", ((int *) buf)[i] );
741 124 : if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >=
742 : MAX_METADATA_LEN )
743 : CPLError( CE_Warning, CPLE_OutOfMemory,
744 0 : "Header data too long. Truncated\n");
745 : }
746 : }
747 222 : else if( H5Tequal( H5T_NATIVE_UINT, hAttrNativeType ) ) {
748 168 : for( i=0; i < nAttrElmts; i++ ) {
749 84 : sprintf( szData, "%ud ", ((unsigned int *) buf)[i] );
750 84 : if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >=
751 : MAX_METADATA_LEN )
752 : CPLError( CE_Warning, CPLE_OutOfMemory,
753 0 : "Header data too long. Truncated\n");
754 : }
755 : }
756 138 : else if( H5Tequal( H5T_NATIVE_LONG, hAttrNativeType ) ) {
757 0 : for( i=0; i < nAttrElmts; i++ ) {
758 0 : sprintf( szData, "%ld ", ((long *)buf)[i] );
759 0 : if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >=
760 : MAX_METADATA_LEN )
761 : CPLError( CE_Warning, CPLE_OutOfMemory,
762 0 : "Header data too long. Truncated\n");
763 : }
764 : }
765 138 : else if( H5Tequal( H5T_NATIVE_ULONG, hAttrNativeType ) ) {
766 0 : for( i=0; i < nAttrElmts; i++ ) {
767 0 : sprintf( szData, "%ld ", ((unsigned long *)buf)[i] );
768 0 : if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >=
769 : MAX_METADATA_LEN )
770 : CPLError( CE_Warning, CPLE_OutOfMemory,
771 0 : "Header data too long. Truncated\n");
772 : }
773 : }
774 138 : else if( H5Tequal( H5T_NATIVE_FLOAT, hAttrNativeType ) ) {
775 240 : for( i=0; i < nAttrElmts; i++ ) {
776 120 : sprintf( szData, "%.8g ", ((float *)buf)[i] );
777 120 : if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >=
778 : MAX_METADATA_LEN )
779 : CPLError( CE_Warning, CPLE_OutOfMemory,
780 0 : "Header data too long. Truncated\n");
781 : }
782 : }
783 18 : else if( H5Tequal( H5T_NATIVE_DOUBLE, hAttrNativeType ) ) {
784 32 : for( i=0; i < nAttrElmts; i++ ) {
785 16 : sprintf( szData, "%.15g ", ((double *)buf)[i] );
786 16 : if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >=
787 : MAX_METADATA_LEN )
788 : CPLError( CE_Warning, CPLE_OutOfMemory,
789 0 : "Header data too long. Truncated\n");
790 : }
791 : }
792 416 : CPLFree( buf );
793 :
794 : }
795 678 : H5Sclose(hAttrSpace);
796 678 : H5Tclose(hAttrNativeType);
797 678 : H5Tclose(hAttrTypeID);
798 678 : H5Aclose( hAttrID );
799 678 : poDS->papszMetadata = CSLSetNameValue( poDS->papszMetadata, osKey, szValue);
800 :
801 678 : CPLFree( szData );
802 678 : CPLFree( szValue );
803 :
804 678 : return 0;
805 : }
806 :
807 : /************************************************************************/
808 : /* CreateMetadata() */
809 : /************************************************************************/
810 198 : CPLErr HDF5Dataset::CreateMetadata( HDF5GroupObjects *poH5Object, int nType)
811 : {
812 : hid_t hGroupID; /* identifier of group */
813 : hid_t hDatasetID;
814 : int nbAttrs;
815 : herr_t ret;
816 :
817 : HDF5Dataset *poDS;
818 :
819 198 : if( !poH5Object->pszPath )
820 0 : return CE_None;
821 :
822 198 : poDS = this;
823 :
824 198 : poH5CurrentObject = poH5Object;
825 198 : nbAttrs = poH5Object->nbAttrs;
826 :
827 198 : if( poH5Object->pszPath == NULL || EQUAL(poH5Object->pszPath, "" ) )
828 0 : return CE_None;
829 :
830 198 : switch( nType ) {
831 :
832 : case H5G_GROUP:
833 :
834 92 : hGroupID = H5Gopen( hHDF5, poH5Object->pszPath );
835 92 : if( nbAttrs > 0 ) {
836 : ret = H5Aiterate( hGroupID, NULL,
837 26 : HDF5AttrIterate, (void *)poDS );
838 26 : ret = H5Gclose( hGroupID );
839 : }
840 :
841 92 : break;
842 :
843 : case H5G_DATASET:
844 :
845 106 : hDatasetID = H5Dopen(hHDF5, poH5Object->pszPath );
846 :
847 106 : if( nbAttrs > 0 ) {
848 : ret = H5Aiterate( hDatasetID, NULL,
849 90 : HDF5AttrIterate, (void *)poDS );
850 90 : ret = H5Dclose( hDatasetID );
851 : }
852 : break;
853 :
854 : default:
855 : break;
856 : }
857 :
858 198 : return CE_None;
859 : }
860 :
861 :
862 : /************************************************************************/
863 : /* HDF5FindDatasetObjectsbyPath() */
864 : /* Find object by name */
865 : /************************************************************************/
866 90 : HDF5GroupObjects* HDF5Dataset::HDF5FindDatasetObjectsbyPath
867 : ( HDF5GroupObjects *poH5Objects, const char* pszDatasetPath )
868 : {
869 : unsigned i;
870 : HDF5Dataset *poDS;
871 : HDF5GroupObjects *poObjectsFound;
872 90 : poDS=this;
873 :
874 90 : if( poH5Objects->nType == H5G_DATASET &&
875 : EQUAL( poH5Objects->pszUnderscorePath,pszDatasetPath ) ) {
876 :
877 : /* printf("found it! %ld\n",(long) poH5Objects);*/
878 20 : return( poH5Objects );
879 : }
880 :
881 70 : if( poH5Objects->nbObjs >0 )
882 82 : for( i=0; i <poH5Objects->nbObjs; i++ ) {
883 : poObjectsFound=
884 : poDS->HDF5FindDatasetObjectsbyPath( poH5Objects->poHchild+i,
885 70 : pszDatasetPath );
886 : /* -------------------------------------------------------------------- */
887 : /* Is this our dataset?? */
888 : /* -------------------------------------------------------------------- */
889 70 : if( poObjectsFound != NULL ) return( poObjectsFound );
890 : }
891 : /* -------------------------------------------------------------------- */
892 : /* Dataset has not been found! */
893 : /* -------------------------------------------------------------------- */
894 32 : return( NULL );
895 :
896 : }
897 :
898 :
899 : /************************************************************************/
900 : /* HDF5FindDatasetObjects() */
901 : /* Find object by name */
902 : /************************************************************************/
903 28 : HDF5GroupObjects* HDF5Dataset::HDF5FindDatasetObjects
904 : ( HDF5GroupObjects *poH5Objects, const char* pszDatasetName )
905 : {
906 : unsigned i;
907 : HDF5Dataset *poDS;
908 : HDF5GroupObjects *poObjectsFound;
909 28 : poDS=this;
910 :
911 28 : if( poH5Objects->nType == H5G_DATASET &&
912 : EQUAL( poH5Objects->pszName,pszDatasetName ) ) {
913 :
914 : /* printf("found it! %ld\n",(long) poH5Objects);*/
915 0 : return( poH5Objects );
916 : }
917 :
918 28 : if( poH5Objects->nbObjs >0 )
919 42 : for( i=0; i <poH5Objects->nbObjs; i++ ) {
920 : poObjectsFound=
921 : poDS->HDF5FindDatasetObjects( poH5Objects->poHchild+i,
922 24 : pszDatasetName );
923 : /* -------------------------------------------------------------------- */
924 : /* Is this our dataset?? */
925 : /* -------------------------------------------------------------------- */
926 24 : if( poObjectsFound != NULL ) return( poObjectsFound );
927 :
928 : }
929 : /* -------------------------------------------------------------------- */
930 : /* Dataset has not been found! */
931 : /* -------------------------------------------------------------------- */
932 28 : return( NULL );
933 :
934 : }
935 :
936 :
937 : /************************************************************************/
938 : /* HDF5ListGroupObjects() */
939 : /* */
940 : /* List all objects in HDF5 */
941 : /************************************************************************/
942 212 : CPLErr HDF5Dataset::HDF5ListGroupObjects( HDF5GroupObjects *poRootGroup,
943 : int bSUBDATASET )
944 : {
945 : char szTemp[8192];
946 : char szDim[8192];
947 : HDF5Dataset *poDS;
948 212 : poDS=this;
949 :
950 212 : if( poRootGroup->nbObjs >0 )
951 264 : for( hsize_t i=0; i < poRootGroup->nbObjs; i++ ) {
952 184 : poDS->HDF5ListGroupObjects( poRootGroup->poHchild+i, bSUBDATASET );
953 : }
954 :
955 :
956 212 : if( poRootGroup->nType == H5G_GROUP ) {
957 92 : CreateMetadata( poRootGroup, H5G_GROUP );
958 : }
959 :
960 : /* -------------------------------------------------------------------- */
961 : /* Create Sub dataset list */
962 : /* -------------------------------------------------------------------- */
963 212 : if( (poRootGroup->nType == H5G_DATASET ) && bSUBDATASET
964 : && poDS->GetDataType( poRootGroup->native ) == GDT_Unknown )
965 : {
966 : CPLDebug( "HDF5", "Skipping unsupported %s of type %s",
967 : poRootGroup->pszUnderscorePath,
968 0 : poDS->GetDataTypeName( poRootGroup->native ) );
969 : }
970 212 : else if( (poRootGroup->nType == H5G_DATASET ) && bSUBDATASET )
971 : {
972 86 : CreateMetadata( poRootGroup, H5G_DATASET );
973 :
974 86 : szDim[0]='\0';
975 86 : switch( poRootGroup->nRank ) {
976 : case 3:
977 : sprintf( szTemp,"%dx%dx%d",
978 0 : (int)poRootGroup->paDims[0],
979 0 : (int)poRootGroup->paDims[1],
980 0 : (int)poRootGroup->paDims[2] );
981 0 : break;
982 :
983 : case 2:
984 : sprintf( szTemp,"%dx%d",
985 86 : (int)poRootGroup->paDims[0],
986 172 : (int)poRootGroup->paDims[1] );
987 86 : break;
988 :
989 : default:
990 0 : return CE_None;
991 :
992 : }
993 86 : strcat( szDim,szTemp );
994 :
995 86 : sprintf( szTemp, "SUBDATASET_%d_NAME", ++(poDS->nSubDataCount) );
996 :
997 : poDS->papszSubDatasets =
998 : CSLSetNameValue( poDS->papszSubDatasets, szTemp,
999 : CPLSPrintf( "HDF5:\"%s\":%s",
1000 86 : poDS->GetDescription(),
1001 172 : poRootGroup->pszUnderscorePath ) );
1002 :
1003 86 : sprintf( szTemp, "SUBDATASET_%d_DESC", poDS->nSubDataCount );
1004 :
1005 : poDS->papszSubDatasets =
1006 : CSLSetNameValue( poDS->papszSubDatasets, szTemp,
1007 : CPLSPrintf( "[%s] %s (%s)",
1008 : szDim,
1009 : poRootGroup->pszUnderscorePath,
1010 : poDS->GetDataTypeName
1011 86 : ( poRootGroup->native ) ) );
1012 :
1013 : }
1014 :
1015 212 : return CE_None;
1016 : }
1017 :
1018 :
1019 : /************************************************************************/
1020 : /* ReadGlobalAttributes() */
1021 : /************************************************************************/
1022 28 : CPLErr HDF5Dataset::ReadGlobalAttributes(int bSUBDATASET)
1023 : {
1024 :
1025 : HDF5GroupObjects *poRootGroup;
1026 :
1027 28 : poRootGroup = (HDF5GroupObjects*) CPLCalloc(sizeof(HDF5GroupObjects), 1);
1028 :
1029 28 : poH5RootGroup=poRootGroup;
1030 28 : poRootGroup->pszName = CPLStrdup( "/" );
1031 28 : poRootGroup->nType = H5G_GROUP;
1032 28 : poRootGroup->poHparent = NULL;
1033 28 : poRootGroup->pszPath = NULL;
1034 28 : poRootGroup->pszUnderscorePath = NULL;
1035 :
1036 28 : if( hHDF5 < 0 ) {
1037 0 : printf( "hHDF5 <0!!\n" );
1038 0 : return CE_None;
1039 : }
1040 :
1041 : H5G_stat_t oStatbuf;
1042 28 : if( H5Gget_objinfo( hHDF5, "/", FALSE, &oStatbuf ) < 0 )
1043 0 : return CE_Failure;
1044 28 : poRootGroup->objno[0] = oStatbuf.objno[0];
1045 28 : poRootGroup->objno[1] = oStatbuf.objno[1];
1046 :
1047 28 : hGroupID = H5Gopen( hHDF5, "/" );
1048 28 : if( hGroupID < 0 ){
1049 0 : printf( "hGroupID <0!!\n" );
1050 0 : return CE_None;
1051 : }
1052 :
1053 28 : poRootGroup->nbAttrs = H5Aget_num_attrs( hGroupID );
1054 :
1055 28 : H5Gget_num_objs( hGroupID, &( poRootGroup->nbObjs ) );
1056 :
1057 28 : if( poRootGroup->nbObjs > 0 ) {
1058 : poRootGroup->poHchild = ( HDF5GroupObjects * )
1059 : CPLCalloc( poRootGroup->nbObjs,
1060 28 : sizeof( HDF5GroupObjects ) );
1061 : H5Giterate( hGroupID, "/", NULL,
1062 28 : HDF5CreateGroupObjs, (void *)poRootGroup );
1063 : }
1064 0 : else poRootGroup->poHchild = NULL;
1065 :
1066 28 : HDF5ListGroupObjects( poRootGroup, bSUBDATASET );
1067 28 : return CE_None;
1068 : }
|