1 : /******************************************************************************
2 : * $Id: hdf4dataset.cpp 17664 2009-09-21 21:16:45Z rouault $
3 : *
4 : * Project: Hierarchical Data Format Release 4 (HDF4)
5 : * Purpose: HDF4 Datasets. Open HDF4 file, fetch metadata and list of
6 : * subdatasets.
7 : * This driver initially based on code supplied by Markus Neteler
8 : * Author: Andrey Kiselev, dron@ak4719.spb.edu
9 : *
10 : ******************************************************************************
11 : * Copyright (c) 2002, Andrey Kiselev <dron@ak4719.spb.edu>
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 : #include "hdf.h"
33 : #include "mfhdf.h"
34 :
35 : #include "HdfEosDef.h"
36 :
37 : #include "gdal_priv.h"
38 : #include "cpl_string.h"
39 : #include "hdf4compat.h"
40 : #include "hdf4dataset.h"
41 :
42 : CPL_CVSID("$Id: hdf4dataset.cpp 17664 2009-09-21 21:16:45Z rouault $");
43 :
44 : CPL_C_START
45 : void GDALRegister_HDF4(void);
46 : CPL_C_END
47 :
48 : extern const char *pszGDALSignature;
49 :
50 : /************************************************************************/
51 : /* ==================================================================== */
52 : /* HDF4Dataset */
53 : /* ==================================================================== */
54 : /************************************************************************/
55 :
56 : /************************************************************************/
57 : /* HDF4Dataset() */
58 : /************************************************************************/
59 :
60 582 : HDF4Dataset::HDF4Dataset()
61 :
62 : {
63 582 : fp = NULL;
64 582 : hSD = 0;
65 582 : hGR = 0;
66 582 : papszGlobalMetadata = NULL;
67 582 : papszSubDatasets = NULL;
68 582 : bIsHDFEOS = 0;
69 582 : }
70 :
71 : /************************************************************************/
72 : /* ~HDF4Dataset() */
73 : /************************************************************************/
74 :
75 806 : HDF4Dataset::~HDF4Dataset()
76 :
77 : {
78 582 : if ( hSD )
79 358 : SDend( hSD );
80 582 : if ( hGR )
81 0 : GRend( hGR );
82 582 : if ( papszSubDatasets )
83 224 : CSLDestroy( papszSubDatasets );
84 582 : if ( papszGlobalMetadata )
85 448 : CSLDestroy( papszGlobalMetadata );
86 582 : if( fp != NULL )
87 224 : VSIFClose( fp );
88 806 : }
89 :
90 : /************************************************************************/
91 : /* GetMetadata() */
92 : /************************************************************************/
93 :
94 197 : char **HDF4Dataset::GetMetadata( const char *pszDomain )
95 :
96 : {
97 197 : if( pszDomain != NULL && EQUALN( pszDomain, "SUBDATASETS", 11 ) )
98 0 : return papszSubDatasets;
99 : else
100 197 : return GDALDataset::GetMetadata( pszDomain );
101 : }
102 :
103 : /************************************************************************/
104 : /* SPrintArray() */
105 : /* Prints numerical arrays in string buffer. */
106 : /* This function takes pfaDataArray as a pointer to printed array, */
107 : /* nValues as a number of values to print and pszDelimiter as a */
108 : /* field delimiting strings. */
109 : /* Pointer to filled buffer will be returned. */
110 : /************************************************************************/
111 :
112 224 : char *SPrintArray( GDALDataType eDataType, const void *paDataArray,
113 : int nValues, const char *pszDelimiter )
114 : {
115 : char *pszString, *pszField;
116 : int i, iFieldSize, iStringSize;
117 :
118 224 : iFieldSize = 32 + strlen( pszDelimiter );
119 224 : pszField = (char *)CPLMalloc( iFieldSize + 1 );
120 224 : iStringSize = nValues * iFieldSize + 1;
121 224 : pszString = (char *)CPLMalloc( iStringSize );
122 224 : memset( pszString, 0, iStringSize );
123 791 : for ( i = 0; i < nValues; i++ )
124 : {
125 567 : switch ( eDataType )
126 : {
127 : case GDT_Byte:
128 0 : sprintf( pszField, "%d%s", ((GByte *)paDataArray)[i],
129 0 : (i < nValues - 1)?pszDelimiter:"" );
130 0 : break;
131 : case GDT_UInt16:
132 0 : sprintf( pszField, "%u%s", ((GUInt16 *)paDataArray)[i],
133 0 : (i < nValues - 1)?pszDelimiter:"" );
134 0 : break;
135 : case GDT_Int16:
136 : default:
137 0 : sprintf( pszField, "%d%s", ((GInt16 *)paDataArray)[i],
138 0 : (i < nValues - 1)?pszDelimiter:"" );
139 0 : break;
140 : case GDT_UInt32:
141 : sprintf( pszField, "%u%s", ((GUInt32 *)paDataArray)[i],
142 567 : (i < nValues - 1)?pszDelimiter:"" );
143 567 : break;
144 : case GDT_Int32:
145 : sprintf( pszField, "%d%s", ((GInt32 *)paDataArray)[i],
146 0 : (i < nValues - 1)?pszDelimiter:"" );
147 0 : break;
148 : case GDT_Float32:
149 0 : sprintf( pszField, "%.7g%s", ((float *)paDataArray)[i],
150 0 : (i < nValues - 1)?pszDelimiter:"" );
151 0 : break;
152 : case GDT_Float64:
153 : sprintf( pszField, "%.15g%s", ((double *)paDataArray)[i],
154 0 : (i < nValues - 1)?pszDelimiter:"" );
155 : break;
156 : }
157 567 : strcat( pszString, pszField );
158 : }
159 :
160 224 : CPLFree( pszField );
161 224 : return pszString;
162 : }
163 :
164 : /************************************************************************/
165 : /* Translate HDF4 data type into GDAL data type */
166 : /************************************************************************/
167 256 : GDALDataType HDF4Dataset::GetDataType( int32 iNumType )
168 : {
169 256 : switch (iNumType)
170 : {
171 : case DFNT_CHAR8: // The same as DFNT_CHAR
172 : case DFNT_UCHAR8: // The same as DFNT_UCHAR
173 : case DFNT_INT8:
174 : case DFNT_UINT8:
175 64 : return GDT_Byte;
176 : case DFNT_INT16:
177 32 : return GDT_Int16;
178 : case DFNT_UINT16:
179 32 : return GDT_UInt16;
180 : case DFNT_INT32:
181 32 : return GDT_Int32;
182 : case DFNT_UINT32:
183 32 : return GDT_UInt32;
184 : case DFNT_INT64:
185 0 : return GDT_Unknown;
186 : case DFNT_UINT64:
187 0 : return GDT_Unknown;
188 : case DFNT_FLOAT32:
189 32 : return GDT_Float32;
190 : case DFNT_FLOAT64:
191 32 : return GDT_Float64;
192 : default:
193 0 : return GDT_Unknown;
194 : }
195 : }
196 :
197 : /************************************************************************/
198 : /* Return the human readable name of data type */
199 : /************************************************************************/
200 :
201 224 : const char *HDF4Dataset::GetDataTypeName( int32 iNumType )
202 : {
203 224 : switch (iNumType)
204 : {
205 : case DFNT_CHAR8: // The same as DFNT_CHAR
206 0 : return "8-bit character";
207 : case DFNT_UCHAR8: // The same as DFNT_UCHAR
208 0 : return "8-bit unsigned character";
209 : case DFNT_INT8:
210 0 : return "8-bit integer";
211 : case DFNT_UINT8:
212 56 : return "8-bit unsigned integer";
213 : case DFNT_INT16:
214 28 : return "16-bit integer";
215 : case DFNT_UINT16:
216 28 : return "16-bit unsigned integer";
217 : case DFNT_INT32:
218 28 : return "32-bit integer";
219 : case DFNT_UINT32:
220 28 : return "32-bit unsigned integer";
221 : case DFNT_INT64:
222 0 : return "64-bit integer";
223 : case DFNT_UINT64:
224 0 : return "64-bit unsigned integer";
225 : case DFNT_FLOAT32:
226 28 : return "32-bit floating-point";
227 : case DFNT_FLOAT64:
228 28 : return "64-bit floating-point";
229 : default:
230 0 : return "unknown type";
231 : }
232 : }
233 :
234 : /************************************************************************/
235 : /* Return the size of data type in bytes */
236 : /************************************************************************/
237 :
238 1312 : int HDF4Dataset::GetDataTypeSize( int32 iNumType )
239 : {
240 1312 : switch (iNumType)
241 : {
242 : case DFNT_CHAR8: // The same as DFNT_CHAR
243 : case DFNT_UCHAR8: // The same as DFNT_UCHAR
244 : case DFNT_INT8:
245 : case DFNT_UINT8:
246 1312 : return 1;
247 : case DFNT_INT16:
248 : case DFNT_UINT16:
249 0 : return 2;
250 : case DFNT_INT32:
251 : case DFNT_UINT32:
252 : case DFNT_FLOAT32:
253 0 : return 4;
254 : case DFNT_INT64:
255 : case DFNT_UINT64:
256 : case DFNT_FLOAT64:
257 0 : return 8;
258 : default:
259 0 : return 0;
260 : }
261 : }
262 :
263 : /************************************************************************/
264 : /* Convert value stored in the input buffer to double value. */
265 : /************************************************************************/
266 :
267 0 : double HDF4Dataset::AnyTypeToDouble( int32 iNumType, void *pData )
268 : {
269 0 : switch ( iNumType )
270 : {
271 : case DFNT_INT8:
272 0 : return (double)*(char *)pData;
273 : case DFNT_UINT8:
274 0 : return (double)*(unsigned char *)pData;
275 : case DFNT_INT16:
276 0 : return (double)*(short *)pData;
277 : case DFNT_UINT16:
278 0 : return (double)*(unsigned short *)pData;
279 : case DFNT_INT32:
280 0 : return (double)*(long *)pData;
281 : case DFNT_UINT32:
282 0 : return (double)*(unsigned long *)pData;
283 : case DFNT_INT64:
284 0 : return (double)*(char *)pData;
285 : case DFNT_UINT64:
286 0 : return (double)*(GIntBig *)pData;
287 : case DFNT_FLOAT32:
288 0 : return (double)*(float *)pData;
289 : case DFNT_FLOAT64:
290 0 : return (double)*(double *)pData;
291 : default:
292 0 : return 0.0;
293 : }
294 : }
295 :
296 : /************************************************************************/
297 : /* Tokenize HDF-EOS attributes. */
298 : /************************************************************************/
299 :
300 0 : char **HDF4Dataset::HDF4EOSTokenizeAttrs( const char * pszString )
301 :
302 : {
303 0 : const char *pszDelimiters = " \t\n\r";
304 0 : char **papszRetList = NULL;
305 : char *pszToken;
306 : int nTokenMax, nTokenLen;
307 :
308 0 : pszToken = (char *) CPLCalloc( 10, 1 );
309 0 : nTokenMax = 10;
310 :
311 0 : while( pszString != NULL && *pszString != '\0' )
312 : {
313 0 : int bInString = FALSE, bInBracket = FALSE;
314 :
315 0 : nTokenLen = 0;
316 :
317 : // Try to find the next delimeter, marking end of token
318 0 : for( ; *pszString != '\0'; pszString++ )
319 : {
320 :
321 : // End if this is a delimeter skip it and break.
322 0 : if ( !bInBracket && !bInString
323 : && strchr(pszDelimiters, *pszString) != NULL )
324 : {
325 0 : pszString++;
326 0 : break;
327 : }
328 :
329 : // Sometimes in bracketed tokens we may found a sort of
330 : // paragraph formatting. We will remove unneeded spaces and new
331 : // lines.
332 0 : if ( bInBracket )
333 0 : if ( strchr("\r\n", *pszString) != NULL
334 : || ( *pszString == ' '
335 : && strchr(" \r\n", *(pszString - 1)) != NULL ) )
336 0 : continue;
337 :
338 0 : if ( *pszString == '"' )
339 : {
340 0 : if ( bInString )
341 : {
342 0 : bInString = FALSE;
343 0 : continue;
344 : }
345 : else
346 : {
347 0 : bInString = TRUE;
348 0 : continue;
349 : }
350 : }
351 0 : else if ( *pszString == '(' )
352 : {
353 0 : bInBracket = TRUE;
354 0 : continue;
355 : }
356 0 : else if ( *pszString == ')' )
357 : {
358 0 : bInBracket = FALSE;
359 0 : continue;
360 : }
361 :
362 0 : if( nTokenLen >= nTokenMax - 2 )
363 : {
364 0 : nTokenMax = nTokenMax * 2 + 10;
365 0 : pszToken = (char *) CPLRealloc( pszToken, nTokenMax );
366 : }
367 :
368 0 : pszToken[nTokenLen] = *pszString;
369 0 : nTokenLen++;
370 : }
371 :
372 0 : pszToken[nTokenLen] = '\0';
373 :
374 0 : if( pszToken[0] != '\0' )
375 : {
376 0 : papszRetList = CSLAddString( papszRetList, pszToken );
377 : }
378 :
379 : // If the last token is an empty token, then we have to catch
380 : // it now, otherwise we won't reenter the loop and it will be lost.
381 0 : if ( *pszString == '\0' && strchr(pszDelimiters, *(pszString-1)) )
382 : {
383 0 : papszRetList = CSLAddString( papszRetList, "" );
384 : }
385 : }
386 :
387 0 : if( papszRetList == NULL )
388 0 : papszRetList = (char **) CPLCalloc( sizeof(char *), 1 );
389 :
390 0 : CPLFree( pszToken );
391 :
392 0 : return papszRetList;
393 : }
394 :
395 : /************************************************************************/
396 : /* Find object name and its value in HDF-EOS attributes. */
397 : /* Function returns pointer to the string in list next behind */
398 : /* recognized object. */
399 : /************************************************************************/
400 :
401 0 : char **HDF4Dataset::HDF4EOSGetObject( char **papszAttrList, char **ppszAttrName,
402 : char **ppszAttrValue )
403 : {
404 : int iCount, i, j;
405 0 : *ppszAttrName = NULL;
406 0 : *ppszAttrValue = NULL;
407 :
408 0 : iCount = CSLCount( papszAttrList );
409 0 : for ( i = 0; i < iCount - 2; i++ )
410 : {
411 0 : if ( EQUAL( papszAttrList[i], "OBJECT" ) )
412 : {
413 0 : i += 2;
414 0 : for ( j = 1; i + j < iCount - 2; j++ )
415 : {
416 0 : if ( EQUAL( papszAttrList[i + j], "END_OBJECT" ) ||
417 0 : EQUAL( papszAttrList[i + j], "OBJECT" ) )
418 0 : return &papszAttrList[i + j];
419 0 : else if ( EQUAL( papszAttrList[i + j], "VALUE" ) )
420 : {
421 0 : *ppszAttrName = papszAttrList[i];
422 0 : *ppszAttrValue = papszAttrList[i + j + 2];
423 :
424 0 : return &papszAttrList[i + j + 2];
425 : }
426 : }
427 : }
428 : }
429 :
430 0 : return NULL;
431 : }
432 :
433 : /************************************************************************/
434 : /* Translate HDF4-EOS attributes in GDAL metadata items */
435 : /************************************************************************/
436 :
437 0 : char** HDF4Dataset::TranslateHDF4EOSAttributes( int32 iHandle,
438 : int32 iAttribute, int32 nValues, char **papszMetadata )
439 : {
440 : char *pszData;
441 :
442 0 : pszData = (char *)CPLMalloc( (nValues + 1) * sizeof(char) );
443 0 : pszData[nValues] = '\0';
444 0 : SDreadattr( iHandle, iAttribute, pszData );
445 : // HDF4-EOS attributes has followed structure:
446 : //
447 : // GROUP = <name>
448 : // GROUPTYPE = <name>
449 : //
450 : // GROUP = <name>
451 : //
452 : // OBJECT = <name>
453 : // CLASS = <string>
454 : // NUM_VAL = <number>
455 : // VALUE = <string> or <number>
456 : // END_OBJECT = <name>
457 : //
458 : // .......
459 : // .......
460 : // .......
461 : //
462 : // END_GROUP = <name>
463 : //
464 : // .......
465 : // .......
466 : // .......
467 : //
468 : // END_GROUP = <name>
469 : // END
470 : //
471 : // Used data types:
472 : // <name> --- unquoted character strings
473 : // <string> --- quoted character strings
474 : // <number> --- numerical value
475 : // If NUM_VAL != 1 then values combined in lists:
476 : // (<string>,<string>,...)
477 : // or
478 : // (<number>,<number>,...)
479 : //
480 : // Records within objects may follows in any order, objects may contains
481 : // other objects (and lacks VALUE record), groups contains other groups
482 : // and objects. Names of groups and objects are not unique and may repeat.
483 : // Objects may contains other types of records.
484 : //
485 : // We are interested in OBJECTS structures only.
486 :
487 : char *pszAttrName, *pszAttrValue;
488 0 : char *pszAddAttrName = NULL;
489 : char **papszAttrList, **papszAttrs;
490 :
491 0 : papszAttrList = HDF4EOSTokenizeAttrs( pszData );
492 0 : papszAttrs = papszAttrList;
493 0 : while ( papszAttrs )
494 : {
495 : papszAttrs =
496 0 : HDF4EOSGetObject( papszAttrs, &pszAttrName, &pszAttrValue );
497 0 : if ( pszAttrName && pszAttrValue )
498 : {
499 : // Now we should recognize special type of HDF EOS metastructures:
500 : // ADDITIONALATTRIBUTENAME = <name>
501 : // PARAMETERVALUE = <value>
502 0 : if ( EQUAL( pszAttrName, "ADDITIONALATTRIBUTENAME" ) )
503 0 : pszAddAttrName = pszAttrValue;
504 0 : else if ( pszAddAttrName && EQUAL( pszAttrName, "PARAMETERVALUE" ) )
505 : {
506 : papszMetadata =
507 0 : CSLAddNameValue( papszMetadata, pszAddAttrName, pszAttrValue );
508 0 : pszAddAttrName = NULL;
509 : }
510 : else
511 : {
512 : papszMetadata =
513 0 : CSLAddNameValue( papszMetadata, pszAttrName, pszAttrValue );
514 : }
515 : }
516 : }
517 :
518 0 : CSLDestroy( papszAttrList );
519 0 : CPLFree( pszData );
520 :
521 0 : return papszMetadata;
522 : }
523 :
524 : /************************************************************************/
525 : /* Translate HDF4 attributes in GDAL metadata items */
526 : /************************************************************************/
527 :
528 1312 : char** HDF4Dataset::TranslateHDF4Attributes( int32 iHandle,
529 : int32 iAttribute, char *pszAttrName, int32 iNumType, int32 nValues,
530 : char **papszMetadata )
531 : {
532 1312 : void *pData = NULL;
533 1312 : char *pszTemp = NULL;
534 :
535 : /* -------------------------------------------------------------------- */
536 : /* Allocate a buffer to hold the attribute data. */
537 : /* -------------------------------------------------------------------- */
538 2624 : if ( iNumType == DFNT_CHAR8 || iNumType == DFNT_UCHAR8 )
539 1312 : pData = CPLMalloc( (nValues + 1) * GetDataTypeSize(iNumType) );
540 : else
541 0 : pData = CPLMalloc( nValues * GetDataTypeSize(iNumType) );
542 :
543 : /* -------------------------------------------------------------------- */
544 : /* Read the attribute data. */
545 : /* -------------------------------------------------------------------- */
546 1312 : SDreadattr( iHandle, iAttribute, pData );
547 2624 : if ( iNumType == DFNT_CHAR8 || iNumType == DFNT_UCHAR8 )
548 : {
549 1312 : ((char *)pData)[nValues] = '\0';
550 : papszMetadata = CSLAddNameValue( papszMetadata, pszAttrName,
551 1312 : (const char *) pData );
552 : }
553 : else
554 : {
555 0 : pszTemp = SPrintArray( GetDataType(iNumType), pData, nValues, ", " );
556 0 : papszMetadata = CSLAddNameValue( papszMetadata, pszAttrName, pszTemp );
557 0 : if ( pszTemp )
558 0 : CPLFree( pszTemp );
559 : }
560 :
561 1312 : if ( pData )
562 1312 : CPLFree( pData );
563 :
564 1312 : return papszMetadata;
565 : }
566 :
567 : /************************************************************************/
568 : /* ReadGlobalAttributes() */
569 : /************************************************************************/
570 :
571 448 : CPLErr HDF4Dataset::ReadGlobalAttributes( int32 iHandler )
572 : {
573 : int32 iAttribute, nValues, iNumType, nDatasets, nAttributes;
574 : char szAttrName[H4_MAX_NC_NAME];
575 :
576 : /* -------------------------------------------------------------------- */
577 : /* Obtain number of SDSs and global attributes in input file. */
578 : /* -------------------------------------------------------------------- */
579 448 : if ( SDfileinfo( iHandler, &nDatasets, &nAttributes ) != 0 )
580 0 : return CE_Failure;
581 :
582 : // Loop through the all attributes
583 1760 : for ( iAttribute = 0; iAttribute < nAttributes; iAttribute++ )
584 : {
585 : // Get information about the attribute. Note that the first
586 : // parameter is an SD interface identifier.
587 1312 : SDattrinfo( iHandler, iAttribute, szAttrName, &iNumType, &nValues );
588 :
589 1312 : if ( EQUALN( szAttrName, "coremetadata.", 13 ) ||
590 : EQUALN( szAttrName, "archivemetadata.", 16 ) ||
591 : EQUALN( szAttrName, "productmetadata.", 16 ) ||
592 : EQUALN( szAttrName, "badpixelinformation", 19 ) ||
593 : EQUALN( szAttrName, "product_summary", 15 ) ||
594 : EQUALN( szAttrName, "dem_specific", 12 ) ||
595 : EQUALN( szAttrName, "bts_specific", 12 ) ||
596 : EQUALN( szAttrName, "etse_specific", 13 ) ||
597 : EQUALN( szAttrName, "dst_specific", 12 ) ||
598 : EQUALN( szAttrName, "acv_specific", 12 ) ||
599 : EQUALN( szAttrName, "act_specific", 12 ) ||
600 : EQUALN( szAttrName, "etst_specific", 13 ) ||
601 : EQUALN( szAttrName, "level_1_carryover", 17 ) )
602 : {
603 0 : bIsHDFEOS = 1;
604 : papszGlobalMetadata = TranslateHDF4EOSAttributes( iHandler,
605 0 : iAttribute, nValues, papszGlobalMetadata );
606 : }
607 :
608 : // Skip "StructMetadata.N" records. We will fetch information
609 : // from them using HDF-EOS API
610 1312 : else if ( EQUALN( szAttrName, "structmetadata.", 15 ) )
611 : {
612 0 : bIsHDFEOS = 1;
613 0 : continue;
614 : }
615 :
616 : else
617 : {
618 : papszGlobalMetadata = TranslateHDF4Attributes( iHandler,
619 1312 : iAttribute, szAttrName, iNumType, nValues, papszGlobalMetadata );
620 : }
621 : }
622 :
623 448 : return CE_None;
624 : }
625 :
626 : /************************************************************************/
627 : /* Identify() */
628 : /************************************************************************/
629 :
630 9479 : int HDF4Dataset::Identify( GDALOpenInfo * poOpenInfo )
631 :
632 : {
633 9479 : if( poOpenInfo->nHeaderBytes < 4 )
634 8615 : return FALSE;
635 :
636 864 : if( memcmp(poOpenInfo->pabyHeader,"\016\003\023\001",4) != 0 )
637 640 : return FALSE;
638 :
639 224 : return TRUE;
640 : }
641 :
642 : /************************************************************************/
643 : /* Open() */
644 : /************************************************************************/
645 :
646 1750 : GDALDataset *HDF4Dataset::Open( GDALOpenInfo * poOpenInfo )
647 :
648 : {
649 : int32 i;
650 :
651 1750 : if( !Identify( poOpenInfo ) )
652 1526 : return NULL;
653 :
654 : /* -------------------------------------------------------------------- */
655 : /* Try opening the dataset. */
656 : /* -------------------------------------------------------------------- */
657 : int32 hHDF4;
658 :
659 224 : hHDF4 = Hopen(poOpenInfo->pszFilename, DFACC_READ, 0);
660 :
661 224 : if( hHDF4 <= 0 )
662 0 : return( NULL );
663 :
664 224 : Hclose( hHDF4 );
665 :
666 : /* -------------------------------------------------------------------- */
667 : /* Create a corresponding GDALDataset. */
668 : /* -------------------------------------------------------------------- */
669 : HDF4Dataset *poDS;
670 :
671 224 : poDS = new HDF4Dataset();
672 :
673 224 : poDS->fp = poOpenInfo->fp;
674 224 : poOpenInfo->fp = NULL;
675 :
676 : /* -------------------------------------------------------------------- */
677 : /* Open HDF SDS Interface. */
678 : /* -------------------------------------------------------------------- */
679 224 : poDS->hSD = SDstart( poOpenInfo->pszFilename, DFACC_READ );
680 :
681 224 : if ( poDS->hSD == -1 )
682 : {
683 0 : delete poDS;
684 0 : return NULL;
685 : }
686 :
687 : /* -------------------------------------------------------------------- */
688 : /* Now read Global Attributes. */
689 : /* -------------------------------------------------------------------- */
690 224 : if ( poDS->ReadGlobalAttributes( poDS->hSD ) != CE_None )
691 : {
692 0 : delete poDS;
693 0 : return NULL;
694 : }
695 :
696 224 : poDS->SetMetadata( poDS->papszGlobalMetadata, "" );
697 :
698 : /* -------------------------------------------------------------------- */
699 : /* Determine type of file we read. */
700 : /* -------------------------------------------------------------------- */
701 : const char *pszValue;
702 :
703 224 : if ( (pszValue = CSLFetchNameValue(poDS->papszGlobalMetadata,
704 : "Signature"))
705 : && EQUAL( pszValue, pszGDALSignature ) )
706 : {
707 224 : poDS->iSubdatasetType = H4ST_GDAL;
708 224 : poDS->pszSubdatasetType = "GDAL_HDF4";
709 : }
710 :
711 0 : else if ( (pszValue = CSLFetchNameValue(poDS->papszGlobalMetadata, "Title"))
712 : && EQUAL( pszValue, "SeaWiFS Level-1A Data" ) )
713 : {
714 0 : poDS->iSubdatasetType = H4ST_SEAWIFS_L1A;
715 0 : poDS->pszSubdatasetType = "SEAWIFS_L1A";
716 : }
717 :
718 0 : else if ( (pszValue = CSLFetchNameValue(poDS->papszGlobalMetadata, "Title"))
719 : && EQUAL( pszValue, "SeaWiFS Level-2 Data" ) )
720 : {
721 0 : poDS->iSubdatasetType = H4ST_SEAWIFS_L2;
722 0 : poDS->pszSubdatasetType = "SEAWIFS_L2";
723 : }
724 :
725 0 : else if ( (pszValue = CSLFetchNameValue(poDS->papszGlobalMetadata, "Title"))
726 : && EQUAL( pszValue, "SeaWiFS Level-3 Standard Mapped Image" ) )
727 : {
728 0 : poDS->iSubdatasetType = H4ST_SEAWIFS_L3;
729 0 : poDS->pszSubdatasetType = "SEAWIFS_L3";
730 : }
731 :
732 0 : else if ( (pszValue = CSLFetchNameValue(poDS->papszGlobalMetadata,
733 : "L1 File Generated By"))
734 : && EQUALN( pszValue, "HYP version ", 12 ) )
735 : {
736 0 : poDS->iSubdatasetType = H4ST_HYPERION_L1;
737 0 : poDS->pszSubdatasetType = "HYPERION_L1";
738 : }
739 :
740 : else
741 : {
742 0 : poDS->iSubdatasetType = H4ST_UNKNOWN;
743 0 : poDS->pszSubdatasetType = "UNKNOWN";
744 : }
745 :
746 : /* -------------------------------------------------------------------- */
747 : /* If we have HDF-EOS dataset, process it here. */
748 : /* -------------------------------------------------------------------- */
749 : char szName[VSNAMELENMAX + 1], szTemp[8192];
750 : char *pszString;
751 : const char *pszName;
752 : int nCount;
753 : int32 aiDimSizes[H4_MAX_VAR_DIMS];
754 : int32 iRank, iNumType, nAttrs;
755 :
756 : // Sometimes "HDFEOSVersion" attribute is not defined and we will
757 : // determine HDF-EOS datasets using other records
758 : // (see ReadGlobalAttributes() method).
759 224 : if ( poDS->bIsHDFEOS
760 : || CSLFetchNameValue(poDS->papszGlobalMetadata, "HDFEOSVersion") )
761 : {
762 : int32 nSubDatasets, nStrBufSize;
763 :
764 : /* -------------------------------------------------------------------- */
765 : /* Process swath layers. */
766 : /* -------------------------------------------------------------------- */
767 0 : hHDF4 = SWopen( poOpenInfo->pszFilename, DFACC_READ );
768 0 : nSubDatasets = SWinqswath(poOpenInfo->pszFilename, NULL, &nStrBufSize);
769 : #if DEBUG
770 : CPLDebug( "HDF4", "Number of HDF-EOS swaths: %d", (int)nSubDatasets );
771 : #endif
772 0 : if ( nSubDatasets > 0 && nStrBufSize > 0 )
773 : {
774 : char *pszSwathList;
775 : char **papszSwaths;
776 :
777 0 : pszSwathList = (char *)CPLMalloc( nStrBufSize + 1 );
778 0 : SWinqswath( poOpenInfo->pszFilename, pszSwathList, &nStrBufSize );
779 0 : pszSwathList[nStrBufSize] = '\0';
780 :
781 : #if DEBUG
782 : CPLDebug( "HDF4", "List of HDF-EOS swaths: %s", pszSwathList );
783 : #endif
784 :
785 : papszSwaths =
786 0 : CSLTokenizeString2( pszSwathList, ",", CSLT_HONOURSTRINGS );
787 0 : CPLFree( pszSwathList );
788 :
789 0 : if ( nSubDatasets != CSLCount(papszSwaths) )
790 : {
791 0 : CSLDestroy( papszSwaths );
792 0 : delete poDS;
793 0 : CPLDebug( "HDF4", "Can not parse list of HDF-EOS grids." );
794 0 : return NULL;
795 : }
796 :
797 0 : for ( i = 0; i < nSubDatasets; i++)
798 : {
799 : char *pszFieldList;
800 : char **papszFields;
801 : int32 *paiRank, *paiNumType;
802 : int32 hSW, nFields, j;
803 :
804 0 : hSW = SWattach( hHDF4, papszSwaths[i] );
805 :
806 0 : nFields = SWnentries( hSW, HDFE_NENTDFLD, &nStrBufSize );
807 0 : pszFieldList = (char *)CPLMalloc( nStrBufSize + 1 );
808 0 : paiRank = (int32 *)CPLMalloc( nFields * sizeof(int32) );
809 0 : paiNumType = (int32 *)CPLMalloc( nFields * sizeof(int32) );
810 :
811 0 : SWinqdatafields( hSW, pszFieldList, paiRank, paiNumType );
812 :
813 : #if DEBUG
814 : {
815 : char *pszTmp =
816 : SPrintArray( GDT_UInt32, paiRank, nFields, "," );
817 :
818 : CPLDebug( "HDF4", "Number of data fields in swath %d: %d",
819 : (int) i, (int) nFields );
820 : CPLDebug( "HDF4", "List of data fields in swath %d: %s",
821 : (int) i, pszFieldList );
822 : CPLDebug( "HDF4", "Data fields ranks: %s", pszTmp );
823 :
824 : CPLFree( pszTmp );
825 : }
826 : #endif
827 :
828 : papszFields = CSLTokenizeString2( pszFieldList, ",",
829 0 : CSLT_HONOURSTRINGS );
830 :
831 0 : for ( j = 0; j < nFields; j++ )
832 : {
833 0 : SWfieldinfo( hSW, papszFields[j], &iRank, aiDimSizes,
834 0 : &iNumType, NULL );
835 :
836 0 : if ( iRank < 2 )
837 0 : continue;
838 :
839 : // Add field to the list of GDAL subdatasets
840 0 : nCount = CSLCount( poDS->papszSubDatasets ) / 2;
841 0 : sprintf( szTemp, "SUBDATASET_%d_NAME", nCount + 1 );
842 : // We will use the field index as an identificator.
843 : poDS->papszSubDatasets =
844 : CSLSetNameValue( poDS->papszSubDatasets, szTemp,
845 : CPLSPrintf("HDF4_EOS:EOS_SWATH:\"%s\":%s:%s",
846 : poOpenInfo->pszFilename,
847 0 : papszSwaths[i], papszFields[j]) );
848 :
849 0 : sprintf( szTemp, "SUBDATASET_%d_DESC", nCount + 1 );
850 : pszString = SPrintArray( GDT_UInt32, aiDimSizes,
851 0 : iRank, "x" );
852 : poDS->papszSubDatasets =
853 : CSLSetNameValue( poDS->papszSubDatasets, szTemp,
854 : CPLSPrintf( "[%s] %s %s (%s)", pszString,
855 : papszFields[j],
856 : papszSwaths[i],
857 0 : poDS->GetDataTypeName(iNumType) ) );
858 0 : CPLFree( pszString );
859 : }
860 :
861 0 : CSLDestroy( papszFields );
862 0 : CPLFree( paiNumType );
863 0 : CPLFree( paiRank );
864 0 : CPLFree( pszFieldList );
865 0 : SWdetach( hSW );
866 : }
867 :
868 0 : CSLDestroy( papszSwaths );
869 : }
870 0 : SWclose( hHDF4 );
871 :
872 : /* -------------------------------------------------------------------- */
873 : /* Process grid layers. */
874 : /* -------------------------------------------------------------------- */
875 0 : hHDF4 = GDopen( poOpenInfo->pszFilename, DFACC_READ );
876 0 : nSubDatasets = GDinqgrid( poOpenInfo->pszFilename, NULL, &nStrBufSize );
877 : #if DEBUG
878 : CPLDebug( "HDF4", "Number of HDF-EOS grids: %d", (int)nSubDatasets );
879 : #endif
880 0 : if ( nSubDatasets > 0 && nStrBufSize > 0 )
881 : {
882 : char *pszGridList;
883 : char **papszGrids;
884 :
885 0 : pszGridList = (char *)CPLMalloc( nStrBufSize + 1 );
886 0 : GDinqgrid( poOpenInfo->pszFilename, pszGridList, &nStrBufSize );
887 :
888 : #if DEBUG
889 : CPLDebug( "HDF4", "List of HDF-EOS grids: %s", pszGridList );
890 : #endif
891 :
892 : papszGrids =
893 0 : CSLTokenizeString2( pszGridList, ",", CSLT_HONOURSTRINGS );
894 0 : CPLFree( pszGridList );
895 :
896 0 : if ( nSubDatasets != CSLCount(papszGrids) )
897 : {
898 0 : CSLDestroy( papszGrids );
899 0 : delete poDS;
900 0 : CPLDebug( "HDF4", "Can not parse list of HDF-EOS grids." );
901 0 : return NULL;
902 : }
903 :
904 0 : for ( i = 0; i < nSubDatasets; i++)
905 : {
906 : char *pszFieldList;
907 : char **papszFields;
908 : int32 *paiRank, *paiNumType;
909 : int32 hGD, nFields, j;
910 :
911 0 : hGD = GDattach( hHDF4, papszGrids[i] );
912 :
913 0 : nFields = GDnentries( hGD, HDFE_NENTDFLD, &nStrBufSize );
914 0 : pszFieldList = (char *)CPLMalloc( nStrBufSize + 1 );
915 0 : paiRank = (int32 *)CPLMalloc( nFields * sizeof(int32) );
916 0 : paiNumType = (int32 *)CPLMalloc( nFields * sizeof(int32) );
917 :
918 0 : GDinqfields( hGD, pszFieldList, paiRank, paiNumType );
919 :
920 : #if DEBUG
921 : {
922 : char* pszTmp =
923 : SPrintArray( GDT_UInt32, paiRank, nFields, "," );
924 : CPLDebug( "HDF4", "Number of fields in grid %d: %d",
925 : (int) i, (int) nFields );
926 : CPLDebug( "HDF4", "List of fields in grid %d: %s",
927 : (int) i, pszFieldList );
928 : CPLDebug( "HDF4", "Fields ranks: %s",
929 : pszTmp );
930 : CPLFree( pszTmp );
931 : }
932 : #endif
933 :
934 : papszFields = CSLTokenizeString2( pszFieldList, ",",
935 0 : CSLT_HONOURSTRINGS );
936 :
937 0 : for ( j = 0; j < nFields; j++ )
938 : {
939 : GDfieldinfo( hGD, papszFields[j], &iRank, aiDimSizes,
940 0 : &iNumType, NULL );
941 :
942 0 : if ( iRank < 2 )
943 0 : continue;
944 :
945 : // Add field to the list of GDAL subdatasets
946 0 : nCount = CSLCount( poDS->papszSubDatasets ) / 2;
947 0 : sprintf( szTemp, "SUBDATASET_%d_NAME", nCount + 1 );
948 : // We will use the field index as an identificator.
949 : poDS->papszSubDatasets =
950 : CSLSetNameValue(poDS->papszSubDatasets, szTemp,
951 : CPLSPrintf( "HDF4_EOS:EOS_GRID:\"%s\":%s:%s",
952 : poOpenInfo->pszFilename,
953 0 : papszGrids[i], papszFields[j]));
954 :
955 0 : sprintf( szTemp, "SUBDATASET_%d_DESC", nCount + 1 );
956 : pszString = SPrintArray( GDT_UInt32, aiDimSizes,
957 0 : iRank, "x" );
958 : poDS->papszSubDatasets =
959 : CSLSetNameValue( poDS->papszSubDatasets, szTemp,
960 : CPLSPrintf("[%s] %s %s (%s)", pszString,
961 : papszFields[j],
962 : papszGrids[i],
963 0 : poDS->GetDataTypeName(iNumType)) );
964 0 : CPLFree( pszString );
965 : }
966 :
967 0 : CSLDestroy( papszFields );
968 0 : CPLFree( paiNumType );
969 0 : CPLFree( paiRank );
970 0 : CPLFree( pszFieldList );
971 0 : GDdetach( hGD );
972 : }
973 :
974 0 : CSLDestroy( papszGrids );
975 0 : GDclose( hHDF4 );
976 : }
977 0 : GDclose( hHDF4 );
978 : }
979 :
980 : else
981 : {
982 :
983 : /* -------------------------------------------------------------------- */
984 : /* Make a list of subdatasets from SDSs contained in input HDF file. */
985 : /* -------------------------------------------------------------------- */
986 : int32 nDatasets;
987 :
988 224 : if ( SDfileinfo( poDS->hSD, &nDatasets, &nAttrs ) != 0 )
989 0 : return NULL;
990 :
991 448 : for ( i = 0; i < nDatasets; i++ )
992 : {
993 : int32 iSDS;
994 :
995 224 : iSDS = SDselect( poDS->hSD, i );
996 224 : if ( SDgetinfo( iSDS, szName, &iRank, aiDimSizes, &iNumType, &nAttrs) != 0 )
997 0 : return NULL;
998 :
999 224 : if ( iRank == 1 ) // Skip 1D datsets
1000 0 : continue;
1001 :
1002 : // Do sort of known datasets. We will display only image bands
1003 224 : if ( (poDS->iSubdatasetType == H4ST_SEAWIFS_L1A ) &&
1004 : !EQUALN( szName, "l1a_data", 8 ) )
1005 0 : continue;
1006 : else
1007 224 : pszName = szName;
1008 :
1009 : // Add datasets with multiple dimensions to the list of GDAL subdatasets
1010 224 : nCount = CSLCount( poDS->papszSubDatasets ) / 2;
1011 224 : sprintf( szTemp, "SUBDATASET_%d_NAME", nCount + 1 );
1012 : // We will use SDS index as an identificator, because SDS names
1013 : // are not unique. Filename also needed for further file opening
1014 : poDS->papszSubDatasets = CSLSetNameValue(poDS->papszSubDatasets, szTemp,
1015 : CPLSPrintf( "HDF4_SDS:%s:\"%s\":%ld", poDS->pszSubdatasetType,
1016 224 : poOpenInfo->pszFilename, (long)i) );
1017 224 : sprintf( szTemp, "SUBDATASET_%d_DESC", nCount + 1 );
1018 224 : pszString = SPrintArray( GDT_UInt32, aiDimSizes, iRank, "x" );
1019 : poDS->papszSubDatasets = CSLSetNameValue(poDS->papszSubDatasets, szTemp,
1020 : CPLSPrintf( "[%s] %s (%s)", pszString,
1021 224 : pszName, poDS->GetDataTypeName(iNumType)) );
1022 224 : CPLFree( pszString );
1023 :
1024 224 : SDendaccess( iSDS );
1025 : }
1026 :
1027 224 : SDend( poDS->hSD );
1028 224 : poDS->hSD = 0;
1029 : }
1030 :
1031 : /* -------------------------------------------------------------------- */
1032 : /* Build a list of raster images. Note, that HDF-EOS dataset may */
1033 : /* contain a raster image as well. */
1034 : /* -------------------------------------------------------------------- */
1035 224 : hHDF4 = Hopen(poOpenInfo->pszFilename, DFACC_READ, 0);
1036 224 : poDS->hGR = GRstart( hHDF4 );
1037 :
1038 224 : if ( poDS->hGR != -1 )
1039 : {
1040 224 : if ( GRfileinfo( poDS->hGR, &poDS->nImages, &nAttrs ) == -1 )
1041 0 : return NULL;
1042 :
1043 224 : for ( i = 0; i < poDS->nImages; i++ )
1044 : {
1045 : int32 iInterlaceMode;
1046 0 : int32 iGR = GRselect( poDS->hGR, i );
1047 :
1048 : // iRank in GR interface has another meaning. It represents number
1049 : // of samples per pixel. aiDimSizes has only two dimensions.
1050 0 : if ( GRgetiminfo( iGR, szName, &iRank, &iNumType, &iInterlaceMode,
1051 : aiDimSizes, &nAttrs ) != 0 )
1052 0 : return NULL;
1053 0 : nCount = CSLCount( poDS->papszSubDatasets ) / 2;
1054 0 : sprintf( szTemp, "SUBDATASET_%d_NAME", nCount + 1 );
1055 : poDS->papszSubDatasets = CSLSetNameValue(poDS->papszSubDatasets,
1056 : szTemp,CPLSPrintf( "HDF4_GR:UNKNOWN:\"%s\":%ld",
1057 0 : poOpenInfo->pszFilename, (long)i));
1058 0 : sprintf( szTemp, "SUBDATASET_%d_DESC", nCount + 1 );
1059 0 : pszString = SPrintArray( GDT_UInt32, aiDimSizes, 2, "x" );
1060 : poDS->papszSubDatasets = CSLSetNameValue(poDS->papszSubDatasets,
1061 : szTemp, CPLSPrintf( "[%sx%ld] %s (%s)", pszString, (long)iRank,
1062 0 : szName, poDS->GetDataTypeName(iNumType)) );
1063 0 : CPLFree( pszString );
1064 :
1065 0 : GRendaccess( iGR );
1066 : }
1067 :
1068 224 : GRend( poDS->hGR );
1069 224 : poDS->hGR = 0;
1070 : }
1071 :
1072 224 : Hclose( hHDF4 );
1073 :
1074 224 : poDS->nRasterXSize = poDS->nRasterYSize = 512; // XXX: bogus values
1075 :
1076 : // Make sure we don't try to do any pam stuff with this dataset.
1077 224 : poDS->nPamFlags |= GPF_NOSAVE;
1078 :
1079 : /* -------------------------------------------------------------------- */
1080 : /* If we have single subdataset only, open it immediately */
1081 : /* -------------------------------------------------------------------- */
1082 224 : if ( CSLCount( poDS->papszSubDatasets ) / 2 == 1 )
1083 : {
1084 : char *pszSDSName;
1085 : pszSDSName = CPLStrdup( CSLFetchNameValue( poDS->papszSubDatasets,
1086 224 : "SUBDATASET_1_NAME" ));
1087 224 : delete poDS;
1088 224 : poDS = (HDF4Dataset *) GDALOpen( pszSDSName, poOpenInfo->eAccess );
1089 224 : CPLFree( pszSDSName );
1090 : }
1091 : else
1092 : {
1093 : /* -------------------------------------------------------------------- */
1094 : /* Confirm the requested access is supported. */
1095 : /* -------------------------------------------------------------------- */
1096 0 : if( poOpenInfo->eAccess == GA_Update )
1097 : {
1098 0 : delete poDS;
1099 : CPLError( CE_Failure, CPLE_NotSupported,
1100 : "The HDF4 driver does not support update access to existing"
1101 0 : " datasets.\n" );
1102 0 : return NULL;
1103 : }
1104 :
1105 : }
1106 :
1107 224 : return( poDS );
1108 : }
1109 :
1110 : /************************************************************************/
1111 : /* GDALRegister_HDF4() */
1112 : /************************************************************************/
1113 :
1114 338 : void GDALRegister_HDF4()
1115 :
1116 : {
1117 : GDALDriver *poDriver;
1118 :
1119 338 : if (! GDAL_CHECK_VERSION("HDF4 driver"))
1120 0 : return;
1121 :
1122 338 : if( GDALGetDriverByName( "HDF4" ) == NULL )
1123 : {
1124 336 : poDriver = new GDALDriver();
1125 :
1126 336 : poDriver->SetDescription( "HDF4" );
1127 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1128 336 : "Hierarchical Data Format Release 4" );
1129 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1130 336 : "frmt_hdf4.html" );
1131 :
1132 336 : poDriver->pfnOpen = HDF4Dataset::Open;
1133 336 : poDriver->pfnIdentify = HDF4Dataset::Identify;
1134 :
1135 336 : GetGDALDriverManager()->RegisterDriver( poDriver );
1136 : }
1137 : }
1138 :
|