1 : /******************************************************************************
2 : * $Id: hdf5dataset.cpp 19431 2010-04-17 01:12:34Z warmerdam $
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 19431 2010-04-17 01:12:34Z warmerdam $");
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 409 : void GDALRegister_HDF5()
58 :
59 : {
60 : GDALDriver *poDriver;
61 409 : if( GDALGetDriverByName("HDF5") == NULL )
62 : {
63 392 : poDriver = new GDALDriver();
64 392 : poDriver->SetDescription("HDF5");
65 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
66 392 : "Hierarchical Data Format Release 5");
67 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
68 392 : "frmt_hdf5.html");
69 392 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "hdf5");
70 392 : poDriver->pfnOpen = HDF5Dataset::Open;
71 392 : poDriver->pfnIdentify = HDF5Dataset::Identify;
72 392 : GetGDALDriverManager()->RegisterDriver(poDriver);
73 : }
74 409 : }
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 10 : 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 : CPLFree( poH5RootGroup );
110 : }
111 10 : }
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 : return GDT_Int32;
136 : else
137 0 : return GDT_Unknown;
138 : }
139 0 : else if( H5Tequal( H5T_NATIVE_ULONG, TypeID ) )
140 : {
141 : if( sizeof(unsigned long) == 4 )
142 : return GDT_UInt32;
143 : else
144 0 : 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 9582 : 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 9582 : if( poOpenInfo->pabyHeader == NULL
210 : || memcmp(poOpenInfo->pabyHeader,achSignature,8) != 0 )
211 9581 : return FALSE;
212 :
213 1 : return TRUE;
214 : }
215 :
216 : /************************************************************************/
217 : /* Open() */
218 : /************************************************************************/
219 1337 : GDALDataset *HDF5Dataset::Open( GDALOpenInfo * poOpenInfo )
220 : {
221 : HDF5Dataset *poDS;
222 : CPLErr Err;
223 :
224 1337 : if( !Identify( poOpenInfo ) )
225 1336 : 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 : CPLFree( poH5Object->paDims );
316 42 : poH5Object->paDims = NULL;
317 :
318 42 : CPLFree( poH5Object->pszPath );
319 42 : poH5Object->pszPath = NULL;
320 :
321 42 : CPLFree( poH5Object->pszName );
322 42 : poH5Object->pszName = NULL;
323 :
324 42 : CPLFree( poH5Object->pszUnderscorePath );
325 42 : poH5Object->pszUnderscorePath = NULL;
326 : /* -------------------------------------------------------------------- */
327 : /* All Children are visited and can be deleted. */
328 : /* -------------------------------------------------------------------- */
329 42 : if( ( i==poH5Object->nbObjs ) && ( poH5Object->nbObjs!=0 ) ) {
330 18 : CPLFree( poH5Object->poHchild );
331 18 : poH5Object->poHchild = NULL;
332 : }
333 :
334 : }
335 :
336 : /************************************************************************/
337 : /* CreatePath() */
338 : /* */
339 : /* Find Dataset path for HDopen */
340 : /************************************************************************/
341 125 : char* CreatePath( HDF5GroupObjects *poH5Object )
342 : {
343 : char pszPath[8192];
344 : char pszUnderscoreSpaceInName[8192];
345 : char *popszPath;
346 : int i;
347 : char **papszPath;
348 :
349 : /* -------------------------------------------------------------------- */
350 : /* Recurse to the root path */
351 : /* -------------------------------------------------------------------- */
352 125 : pszPath[0]='\0';
353 125 : if( poH5Object->poHparent !=NULL ) {
354 83 : popszPath=CreatePath( poH5Object->poHparent );
355 83 : strcpy( pszPath,popszPath );
356 : }
357 :
358 : /* -------------------------------------------------------------------- */
359 : /* add name to the path */
360 : /* -------------------------------------------------------------------- */
361 125 : if( !EQUAL( poH5Object->pszName,"/" ) ){
362 83 : strcat( pszPath,"/" );
363 83 : strcat( pszPath,poH5Object->pszName );
364 : }
365 :
366 : /* -------------------------------------------------------------------- */
367 : /* fill up path for each object */
368 : /* -------------------------------------------------------------------- */
369 125 : if( poH5Object->pszPath == NULL ) {
370 :
371 52 : if( strlen( poH5Object->pszName ) == 1 ) {
372 10 : strcat(pszPath, poH5Object->pszName );
373 10 : strcpy(pszUnderscoreSpaceInName, poH5Object->pszName);
374 : }
375 : else {
376 : /* -------------------------------------------------------------------- */
377 : /* Change space for underscore */
378 : /* -------------------------------------------------------------------- */
379 : papszPath = CSLTokenizeString2( pszPath,
380 42 : " ", CSLT_HONOURSTRINGS );
381 :
382 42 : strcpy(pszUnderscoreSpaceInName,papszPath[0]);
383 50 : for( i=1; i < CSLCount( papszPath ); i++ ) {
384 8 : strcat( pszUnderscoreSpaceInName, "_" );
385 8 : strcat( pszUnderscoreSpaceInName, papszPath[ i ] );
386 : }
387 42 : CSLDestroy(papszPath);
388 :
389 : }
390 : poH5Object->pszUnderscorePath =
391 52 : CPLStrdup( pszUnderscoreSpaceInName );
392 52 : poH5Object->pszPath = CPLStrdup( pszPath );
393 : }
394 :
395 125 : return( poH5Object->pszPath );
396 : }
397 :
398 : /************************************************************************/
399 : /* HDF5GroupCheckDuplicate() */
400 : /* */
401 : /* Returns TRUE if an ancestor has the same objno[] as passed */
402 : /* in - used to avoid looping in files with "links up" #(3218). */
403 : /************************************************************************/
404 :
405 : static int HDF5GroupCheckDuplicate( HDF5GroupObjects *poHparent,
406 24 : unsigned long *objno )
407 :
408 : {
409 91 : while( poHparent != NULL )
410 : {
411 43 : if( poHparent->objno[0] == objno[0]
412 : && poHparent->objno[1] == objno[1] )
413 0 : return TRUE;
414 :
415 43 : poHparent = poHparent->poHparent;
416 : }
417 :
418 24 : return FALSE;
419 : }
420 :
421 : /************************************************************************/
422 : /* HDF5CreateGroupObjs() */
423 : /* */
424 : /* Create HDF5 hierarchy into a linked list */
425 : /************************************************************************/
426 : herr_t HDF5CreateGroupObjs(hid_t hHDF5, const char *pszObjName,
427 42 : void *poHObjParent)
428 : {
429 : herr_t ret; /* error return status */
430 : hid_t hGroupID; /* identifier of group */
431 : hid_t hDatasetID; /* identifier of dataset */
432 42 : hsize_t nbObjs=0; /* number of objects in a group */
433 42 : int nbAttrs=0; /* number of attributes in object */
434 : int idx;
435 : int n_dims;
436 : H5G_stat_t oStatbuf;
437 42 : hsize_t *dims=NULL;
438 42 : hsize_t *maxdims=NULL;
439 : hid_t datatype;
440 : hid_t dataspace;
441 : hid_t native;
442 : herr_t status;
443 :
444 : char *CreatePath( HDF5GroupObjects *poH5Object );
445 :
446 : HDF5GroupObjects *poHchild;
447 : HDF5GroupObjects *poHparent;
448 :
449 42 : poHparent = ( HDF5GroupObjects * ) poHObjParent;
450 42 : poHchild=poHparent->poHchild;
451 :
452 42 : if( H5Gget_objinfo( hHDF5, pszObjName, FALSE, &oStatbuf ) < 0 )
453 0 : return -1;
454 :
455 :
456 : /* -------------------------------------------------------------------- */
457 : /* Look for next child */
458 : /* -------------------------------------------------------------------- */
459 61 : for( idx=0; idx < poHparent->nbObjs; idx++ ) {
460 61 : if( poHchild->pszName == NULL ) break;
461 19 : poHchild++;
462 : }
463 :
464 42 : if( idx == poHparent->nbObjs )
465 0 : return -1; // all children parsed
466 :
467 : /* -------------------------------------------------------------------- */
468 : /* Save child information */
469 : /* -------------------------------------------------------------------- */
470 42 : poHchild->pszName = CPLStrdup( pszObjName );
471 :
472 42 : poHchild->nType = oStatbuf.type;
473 42 : poHchild->nIndex = idx;
474 42 : poHchild->poHparent = poHparent;
475 42 : poHchild->nRank = 0;
476 42 : poHchild->paDims = 0;
477 42 : poHchild->HDatatype = 0;
478 42 : poHchild->objno[0] = oStatbuf.objno[0];
479 42 : poHchild->objno[1] = oStatbuf.objno[1];
480 42 : if( poHchild->pszPath == NULL ) {
481 42 : poHchild->pszPath = CreatePath( poHchild );
482 : }
483 42 : if( poHparent->pszPath == NULL ) {
484 0 : poHparent->pszPath = CreatePath( poHparent );
485 : }
486 :
487 :
488 42 : switch ( oStatbuf.type )
489 : {
490 : case H5G_LINK:
491 0 : poHchild->nbAttrs = 0;
492 0 : poHchild->nbObjs = 0;
493 0 : poHchild->poHchild = NULL;
494 0 : poHchild->nRank = 0;
495 0 : poHchild->paDims = 0;
496 0 : poHchild->HDatatype = 0;
497 0 : break;
498 :
499 : case H5G_GROUP:
500 24 : if( ( hGroupID = H5Gopen( hHDF5, pszObjName ) ) == -1 ) {
501 : printf( "Error: unable to access \"%s\" group.\n",
502 0 : pszObjName );
503 0 : return -1;
504 : }
505 24 : nbAttrs = H5Aget_num_attrs( hGroupID );
506 24 : ret = H5Gget_num_objs( hGroupID, &nbObjs );
507 24 : poHchild->nbAttrs= nbAttrs;
508 24 : poHchild->nbObjs = nbObjs;
509 24 : poHchild->nRank = 0;
510 24 : poHchild->paDims = 0;
511 24 : poHchild->HDatatype = 0;
512 :
513 24 : if( nbObjs > 0 ) {
514 : poHchild->poHchild =( HDF5GroupObjects * )
515 18 : CPLCalloc( nbObjs, sizeof( HDF5GroupObjects ) );
516 : memset( poHchild->poHchild,0,
517 18 : sizeof( HDF5GroupObjects ) * nbObjs );
518 : }
519 : else
520 6 : poHchild->poHchild = NULL;
521 :
522 24 : if( !HDF5GroupCheckDuplicate( poHparent, oStatbuf.objno ) )
523 : H5Giterate( hHDF5, pszObjName, NULL,
524 24 : HDF5CreateGroupObjs, (void*) poHchild );
525 : else
526 : CPLDebug( "HDF5", "avoiding link looping on node '%s'.",
527 0 : pszObjName );
528 24 : H5Gclose( hGroupID );
529 24 : break;
530 :
531 : case H5G_DATASET:
532 :
533 18 : if( ( hDatasetID = H5Dopen( hHDF5, pszObjName ) ) == -1 ) {
534 : printf( "Error: unable to access \"%s\" dataset.\n",
535 0 : pszObjName );
536 0 : return -1;
537 : }
538 18 : nbAttrs = H5Aget_num_attrs( hDatasetID );
539 18 : datatype = H5Dget_type( hDatasetID );
540 18 : dataspace = H5Dget_space( hDatasetID );
541 18 : n_dims = H5Sget_simple_extent_ndims( dataspace );
542 18 : native = H5Tget_native_type( datatype, H5T_DIR_ASCEND );
543 :
544 18 : if( n_dims > 0 ) {
545 17 : dims = (hsize_t *) CPLCalloc( n_dims,sizeof( hsize_t ) );
546 17 : maxdims = (hsize_t *) CPLCalloc( n_dims,sizeof( hsize_t ) );
547 : }
548 18 : status = H5Sget_simple_extent_dims( dataspace, dims, maxdims );
549 18 : if( maxdims != NULL )
550 17 : CPLFree( maxdims );
551 :
552 18 : if( n_dims > 0 ) {
553 17 : poHchild->nRank = n_dims; // rank of the array
554 17 : poHchild->paDims = dims; // dimmension of the array.
555 17 : poHchild->HDatatype = datatype; // HDF5 datatype
556 : }
557 : else {
558 1 : poHchild->nRank = -1;
559 1 : poHchild->paDims = NULL;
560 1 : poHchild->HDatatype = 0;
561 : }
562 18 : poHchild->nbAttrs = nbAttrs;
563 18 : poHchild->nbObjs = 0;
564 18 : poHchild->poHchild = NULL;
565 18 : poHchild->native = native;
566 18 : ret = H5Dclose( hDatasetID );
567 18 : break;
568 :
569 : case H5G_TYPE:
570 0 : poHchild->nbAttrs = 0;
571 0 : poHchild->nbObjs = 0;
572 0 : poHchild->poHchild = NULL;
573 0 : poHchild->nRank = 0;
574 0 : poHchild->paDims = 0;
575 0 : poHchild->HDatatype = 0;
576 : break;
577 :
578 : default:
579 : break;
580 : }
581 :
582 42 : return 0;
583 : }
584 :
585 :
586 : /************************************************************************/
587 : /* HDF5AttrIterate() */
588 : /************************************************************************/
589 :
590 : herr_t HDF5AttrIterate( hid_t hH5ObjID,
591 : const char *AttrName,
592 17 : void *pDS )
593 : {
594 : hid_t hAttrID;
595 : hid_t hAttrTypeID;
596 : hid_t hAttrNativeType;
597 : hid_t hAttrSpace;
598 :
599 : char szData[8192];
600 : hsize_t nSize[64];
601 : unsigned int nAttrElmts;
602 : hsize_t nAttrSize;
603 : hsize_t i;
604 17 : void *buf = NULL;
605 : unsigned int nAttrDims;
606 :
607 :
608 : HDF5Dataset *poDS;
609 : char szTemp[8192];
610 : char szValue[8192];
611 :
612 17 : poDS = (HDF5Dataset *) pDS;
613 : sprintf( szTemp, "%s:%s", poDS->poH5CurrentObject->pszName,
614 17 : AttrName );
615 :
616 17 : hAttrID = H5Aopen_name( hH5ObjID, AttrName );
617 17 : hAttrTypeID = H5Aget_type( hAttrID );
618 17 : hAttrNativeType = H5Tget_native_type( hAttrTypeID, H5T_DIR_DEFAULT );
619 17 : hAttrSpace = H5Aget_space( hAttrID );
620 17 : nAttrDims = H5Sget_simple_extent_dims( hAttrSpace, nSize, NULL );
621 :
622 :
623 17 : szValue[0] ='\0';
624 :
625 17 : if( H5Tget_class( hAttrNativeType ) == H5T_STRING ) {
626 13 : nAttrSize = H5Tget_size( hAttrTypeID );
627 13 : H5Aread( hAttrID, hAttrNativeType, szData );
628 13 : szData[nAttrSize]='\0';
629 13 : sprintf( szValue, "%s", szData );
630 :
631 : }
632 : else {
633 4 : nAttrElmts = 1;
634 6 : for( i=0; i < nAttrDims; i++ ) {
635 2 : nAttrElmts *= nSize[i];
636 : }
637 4 : if( nAttrElmts > 0 ){
638 : buf = (void *) CPLMalloc( nAttrElmts*
639 4 : H5Tget_size( hAttrNativeType ));
640 4 : H5Aread( hAttrID, hAttrNativeType, buf );
641 : }
642 4 : if( H5Tequal( H5T_NATIVE_CHAR, hAttrNativeType ) ){
643 0 : for( i=0; i < nAttrElmts; i++ ) {
644 0 : sprintf( szData, "%c ", ((char *) buf)[i]);
645 0 : strcat(szValue,szData);
646 : }
647 : }
648 4 : else if( H5Tequal( H5T_NATIVE_UCHAR, hAttrNativeType ) ) {
649 0 : for( i=0; i < nAttrElmts; i++ ) {
650 0 : sprintf( szData, "%c", ((char *) buf)[i] );
651 0 : strcat(szValue,szData);
652 : }
653 : }
654 4 : else if( H5Tequal( H5T_NATIVE_SHORT, hAttrNativeType ) ) {
655 2 : for( i=0; i < nAttrElmts; i++ ) {
656 1 : sprintf( szData, "%d ", ((short *) buf)[i] );
657 1 : strcat(szValue,szData);
658 : }
659 : }
660 3 : else if( H5Tequal( H5T_NATIVE_USHORT, hAttrNativeType ) ) {
661 4 : for( i=0; i < nAttrElmts; i++ ) {
662 2 : sprintf( szData, "%ud ", ((unsigned short *) buf)[i] );
663 2 : strcat(szValue,szData);
664 : }
665 : }
666 1 : else if( H5Tequal( H5T_NATIVE_INT, hAttrNativeType ) ) {
667 0 : for( i=0; i < nAttrElmts; i++ ) {
668 0 : sprintf( szData, "%d ", ((int *) buf)[i] );
669 0 : strcat(szValue,szData);
670 : }
671 : }
672 1 : else if( H5Tequal( H5T_NATIVE_UINT, hAttrNativeType ) ) {
673 0 : for( i=0; i < nAttrElmts; i++ ) {
674 0 : sprintf( szData, "%ud ", ((unsigned int *) buf)[i] );
675 0 : strcat(szValue,szData);
676 : }
677 : }
678 1 : else if( H5Tequal( H5T_NATIVE_LONG, hAttrNativeType ) ) {
679 0 : for( i=0; i < nAttrElmts; i++ ) {
680 0 : sprintf( szData, "%ld ", ((long *)buf)[i] );
681 0 : strcat(szValue,szData);
682 : }
683 : }
684 1 : else if( H5Tequal( H5T_NATIVE_ULONG, hAttrNativeType ) ) {
685 0 : for( i=0; i < nAttrElmts; i++ ) {
686 0 : sprintf( szData, "%ld ", ((unsigned long *)buf)[i] );
687 0 : strcat(szValue,szData);
688 : }
689 : }
690 1 : else if( H5Tequal( H5T_NATIVE_FLOAT, hAttrNativeType ) ) {
691 0 : for( i=0; i < nAttrElmts; i++ ) {
692 0 : sprintf( szData, "%f ", ((float *)buf)[i] );
693 0 : strcat(szValue,szData);
694 : }
695 : }
696 1 : else if( H5Tequal( H5T_NATIVE_DOUBLE, hAttrNativeType ) ) {
697 0 : for( i=0; i < nAttrElmts; i++ ) {
698 0 : sprintf( szData, "%g ", ((double *)buf)[i] );
699 0 : strcat(szValue,szData);
700 : }
701 : }
702 4 : CPLFree( buf );
703 :
704 : }
705 17 : H5Aclose( hAttrID );
706 : //printf( "%s = %s\n",szTemp, szValue );
707 : poDS->papszMetadata =
708 : CSLSetNameValue( poDS->papszMetadata, szTemp,
709 17 : CPLSPrintf( "%s", szValue ) );
710 :
711 17 : return 0;
712 : }
713 :
714 : /************************************************************************/
715 : /* CreateMetadata() */
716 : /************************************************************************/
717 43 : CPLErr HDF5Dataset::CreateMetadata( HDF5GroupObjects *poH5Object, int nType)
718 : {
719 : hid_t hGroupID; /* identifier of group */
720 : hid_t hDatasetID;
721 : int nbAttrs;
722 : herr_t ret;
723 :
724 : HDF5Dataset *poDS;
725 :
726 43 : if( !poH5Object->pszPath )
727 0 : return CE_None;
728 :
729 43 : poDS = this;
730 :
731 43 : poH5CurrentObject = poH5Object;
732 43 : nbAttrs = poH5Object->nbAttrs;
733 :
734 43 : if( poH5Object->pszPath == NULL || 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 : HDF5GroupObjects* HDF5Dataset::HDF5FindDatasetObjectsbyPath
774 43 : ( 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 : HDF5GroupObjects* HDF5Dataset::HDF5FindDatasetObjects
810 14 : ( HDF5GroupObjects *poH5Objects, char* pszDatasetName )
811 : {
812 : int i;
813 : HDF5Dataset *poDS;
814 : HDF5GroupObjects *poObjectsFound;
815 14 : poDS=this;
816 :
817 14 : 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 14 : if( poH5Objects->nbObjs >0 )
824 21 : for( i=0; i <poH5Objects->nbObjs; i++ ) {
825 : poObjectsFound=
826 : poDS->HDF5FindDatasetObjects( poH5Objects->poHchild+i,
827 12 : pszDatasetName );
828 : /* -------------------------------------------------------------------- */
829 : /* Is this our dataset?? */
830 : /* -------------------------------------------------------------------- */
831 12 : if( poObjectsFound != NULL ) return( poObjectsFound );
832 :
833 : }
834 : /* -------------------------------------------------------------------- */
835 : /* Dataset has not been found! */
836 : /* -------------------------------------------------------------------- */
837 14 : return( NULL );
838 :
839 : }
840 :
841 :
842 : /************************************************************************/
843 : /* HDF5ListGroupObjects() */
844 : /* */
845 : /* List all objects in HDF5 */
846 : /************************************************************************/
847 : CPLErr HDF5Dataset::HDF5ListGroupObjects( HDF5GroupObjects *poRootGroup,
848 52 : 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 : (int)poRootGroup->paDims[0],
883 : (int)poRootGroup->paDims[1],
884 0 : (int)poRootGroup->paDims[2] );
885 0 : break;
886 :
887 : case 2:
888 : sprintf( szTemp,"%dx%d",
889 : (int)poRootGroup->paDims[0],
890 2 : (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 : poDS->GetDescription(),
904 2 : 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 = (HDF5GroupObjects*) CPLCalloc(sizeof(HDF5GroupObjects), 1);
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 10 : poRootGroup->pszUnderscorePath = NULL;
938 :
939 10 : if( hHDF5 < 0 ) {
940 0 : printf( "hHDF5 <0!!\n" );
941 0 : return CE_None;
942 : }
943 :
944 : H5G_stat_t oStatbuf;
945 10 : if( H5Gget_objinfo( hHDF5, "/", FALSE, &oStatbuf ) < 0 )
946 0 : return CE_Failure;
947 10 : poRootGroup->objno[0] = oStatbuf.objno[0];
948 10 : poRootGroup->objno[1] = oStatbuf.objno[1];
949 :
950 10 : hGroupID = H5Gopen( hHDF5, "/" );
951 10 : if( hGroupID < 0 ){
952 0 : printf( "hGroupID <0!!\n" );
953 0 : return CE_None;
954 : }
955 :
956 10 : poRootGroup->nbAttrs = H5Aget_num_attrs( hGroupID );
957 :
958 10 : H5Gget_num_objs( hGroupID, (hsize_t *) &( poRootGroup->nbObjs ) );
959 :
960 10 : if( poRootGroup->nbObjs > 0 ) {
961 : poRootGroup->poHchild = ( HDF5GroupObjects * )
962 : CPLCalloc( poRootGroup->nbObjs,
963 10 : sizeof( HDF5GroupObjects ) );
964 : H5Giterate( hGroupID, "/", NULL,
965 10 : HDF5CreateGroupObjs, (void *)poRootGroup );
966 : }
967 0 : else poRootGroup->poHchild = NULL;
968 :
969 10 : HDF5ListGroupObjects( poRootGroup, bSUBDATASET );
970 10 : return CE_None;
971 : }
|