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