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