LCOV - code coverage report
Current view: directory - frmts/hdf4 - hdf4dataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 457 326 71.3 %
Date: 2013-03-30 Functions: 20 18 90.0 %

       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                 : 

Generated by: LCOV version 1.7