LCOV - code coverage report
Current view: directory - frmts/hdf4 - hdf4dataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 419 313 74.7 %
Date: 2011-12-18 Functions: 19 17 89.5 %

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

Generated by: LCOV version 1.7