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