GDALDataset *HDF5ImageDataset::Open( GDALOpenInfo * poOpenInfo )
{
    if(!STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF5:") )
        return NULL;

/* -------------------------------------------------------------------- */
/*      Confirm the requested access is supported.                      */
/* -------------------------------------------------------------------- */
    if( poOpenInfo->eAccess == GA_Update )
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "The HDF5ImageDataset driver does not support update access "
                  " to existing datasets.\n" );
        return NULL;
    }

    HDF5ImageDataset *poDS = new HDF5ImageDataset();

    /* -------------------------------------------------------------------- */
    /*      Create a corresponding GDALDataset.                             */
    /* -------------------------------------------------------------------- */
    /* printf("poOpenInfo->pszFilename %s\n",poOpenInfo->pszFilename); */
    char **papszName =
        CSLTokenizeString2(  poOpenInfo->pszFilename,
                             ":", CSLT_HONOURSTRINGS|CSLT_PRESERVEESCAPES );

    if( !((CSLCount(papszName) == 3) || (CSLCount(papszName) == 4)) )
    {
        CSLDestroy(papszName);
        delete poDS;
        return NULL;
    }

    poDS->SetDescription( poOpenInfo->pszFilename );

    /* -------------------------------------------------------------------- */
    /*    Check for drive name in windows HDF5:"D:\...                      */
    /* -------------------------------------------------------------------- */
    CPLString osSubdatasetName;

    CPLString osFilename(papszName[1]);

    if( strlen(papszName[1]) == 1 && papszName[3] != NULL )
    {
        osFilename += ":";
        osFilename += papszName[2];
        osSubdatasetName = papszName[3];
    }
    else
        osSubdatasetName = papszName[2];

    poDS->SetSubdatasetName( osSubdatasetName );

    CSLDestroy(papszName);
    papszName = NULL;

    if( !H5Fis_hdf5(osFilename) ) {
        delete poDS;
        return NULL;
    }

    poDS->SetPhysicalFilename( osFilename );

    /* -------------------------------------------------------------------- */
    /*      Try opening the dataset.                                        */
    /* -------------------------------------------------------------------- */
    poDS->hHDF5 = H5Fopen(osFilename,
                          H5F_ACC_RDONLY,
                          H5P_DEFAULT );

    if( poDS->hHDF5 < 0 )
    {
        delete poDS;
        return NULL;
    }

    poDS->hGroupID = H5Gopen( poDS->hHDF5, "/" );
    if( poDS->hGroupID < 0 )
    {
        poDS->bIsHDFEOS=false;
        delete poDS;
        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      THIS IS AN HDF5 FILE                                            */
/* -------------------------------------------------------------------- */
    poDS->bIsHDFEOS=TRUE;
    poDS->ReadGlobalAttributes( FALSE );

/* -------------------------------------------------------------------- */
/*      Create HDF5 Data Hierarchy in a link list                       */
/* -------------------------------------------------------------------- */
    poDS->poH5Objects =
        poDS->HDF5FindDatasetObjectsbyPath( poDS->poH5RootGroup,
                                            osSubdatasetName );

    if( poDS->poH5Objects == NULL ) {
        delete poDS;
        return NULL;
    }
/* -------------------------------------------------------------------- */
/*      Retrieve HDF5 data information                                  */
/* -------------------------------------------------------------------- */
    poDS->dataset_id   = H5Dopen( poDS->hHDF5,poDS->poH5Objects->pszPath );
    poDS->dataspace_id = H5Dget_space( poDS->dataset_id );
    poDS->ndims        = H5Sget_simple_extent_ndims( poDS->dataspace_id );
    if( poDS->ndims < 0 )
    {
        delete poDS;
        return NULL;
    }
    poDS->dims         = (hsize_t*)CPLCalloc( poDS->ndims, sizeof(hsize_t) );
    poDS->maxdims      = (hsize_t*)CPLCalloc( poDS->ndims, sizeof(hsize_t) );
    poDS->dimensions   = H5Sget_simple_extent_dims( poDS->dataspace_id,
                                                    poDS->dims,
                                                    poDS->maxdims );
    poDS->datatype = H5Dget_type( poDS->dataset_id );
    poDS->class_   = H5Tget_class( poDS->datatype );
    poDS->size     = H5Tget_size( poDS->datatype );
    poDS->address = H5Dget_offset( poDS->dataset_id );
    poDS->native  = H5Tget_native_type( poDS->datatype, H5T_DIR_ASCEND );

    // CSK code in IdentifyProductType() and CreateProjections()
    // uses dataset metadata.
    poDS->SetMetadata( poDS->papszMetadata );

    // Check if the hdf5 is a well known product type
    poDS->IdentifyProductType();

    poDS->nRasterYSize=static_cast<int>(poDS->dims[poDS->GetYIndex()]); // nRows
    poDS->nRasterXSize=static_cast<int>(poDS->dims[poDS->GetXIndex()]); // nCols
    if( poDS->IsComplexCSKL1A() )
    {
        poDS->nBands=(int) poDS->dims[2]; // nBands
    }
    else if( poDS->ndims == 3 )
    {
        poDS->nBands=(int) poDS->dims[0];
    }
    else
    {
        poDS->nBands=1;
    }

    for( int i = 1; i <= poDS->nBands; i++ ) {
        HDF5ImageRasterBand * const poBand =
            new HDF5ImageRasterBand( poDS, i,
                            poDS->GetDataType( poDS->native ) );

        poDS->SetBand( i, poBand );
        if( poBand->bNoDataSet )
            poBand->SetNoDataValue( 255 );
    }

    poDS->CreateProjections( );

/* -------------------------------------------------------------------- */
/*      Setup/check for pam .aux.xml.                                   */
/* -------------------------------------------------------------------- */
    poDS->TryLoadXML();

/* -------------------------------------------------------------------- */
/*      Setup overviews.                                                */
/* -------------------------------------------------------------------- */
    poDS->oOvManager.Initialize( poDS, ":::VIRTUAL:::" );

    return poDS;
}
CPLErr HDF5ImageRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                                        void * pImage )
{
    HDF5ImageDataset *poGDS = reinterpret_cast<HDF5ImageDataset * >(poDS);

    if( poGDS->eAccess == GA_Update ) {
        memset( pImage, 0,
            nBlockXSize * nBlockYSize *
            GDALGetDataTypeSize( eDataType )/8 );
        return CE_None;
    }

    hsize_t count[3] = {0, 0, 0};
    H5OFFSET_TYPE offset[3] = {0, 0, 0};
    hsize_t col_dims[3] = {0, 0, 0};
    hsize_t rank = 2;

    if( poGDS->IsComplexCSKL1A() )
    {
        rank = 3;
        offset[2]   = nBand-1;
        count[2]    = 1;
        col_dims[2] = 1;
    }
    else if( poGDS->ndims == 3 )
    {
        rank = 3;
        offset[0]   = nBand-1;
        count[0]    = 1;
        col_dims[0] = 1;
    }
    // Defaults to rank = 2;

    offset[poGDS->GetYIndex()] = nBlockYOff*static_cast<hsize_t>(nBlockYSize);
    offset[poGDS->GetXIndex()] = nBlockXOff*static_cast<hsize_t>(nBlockXSize);
    count[poGDS->GetYIndex()]  = nBlockYSize;
    count[poGDS->GetXIndex()]  = nBlockXSize;

    const int nSizeOfData = static_cast<int>(H5Tget_size( poGDS->native ));
    memset( pImage,0,nBlockXSize*nBlockYSize*nSizeOfData );

    /*  blocksize may not be a multiple of imagesize */
    count[poGDS->GetYIndex()]  = MIN( size_t(nBlockYSize),
                                    poDS->GetRasterYSize() -
                                    offset[poGDS->GetYIndex()]);
    count[poGDS->GetXIndex()]  = MIN( size_t(nBlockXSize),
                                    poDS->GetRasterXSize()-
                                    offset[poGDS->GetXIndex()]);

/* -------------------------------------------------------------------- */
/*      Select block from file space                                    */
/* -------------------------------------------------------------------- */
    herr_t status =  H5Sselect_hyperslab( poGDS->dataspace_id,
                                          H5S_SELECT_SET,
                                          offset, NULL,
                                          count, NULL );
    if( status < 0 )
        return CE_Failure;

/* -------------------------------------------------------------------- */
/*      Create memory space to receive the data                         */
/* -------------------------------------------------------------------- */
    col_dims[poGDS->GetYIndex()]=nBlockYSize;
    col_dims[poGDS->GetXIndex()]=nBlockXSize;

    const hid_t memspace =
        H5Screate_simple( static_cast<int>(rank), col_dims, NULL );
    H5OFFSET_TYPE mem_offset[3] = {0, 0, 0};
    status =  H5Sselect_hyperslab(memspace,
                                  H5S_SELECT_SET,
                                  mem_offset, NULL,
                                  count, NULL);
    if( status < 0 )
        return CE_Failure;

    status = H5Dread ( poGDS->dataset_id,
                       poGDS->native,
                       memspace,
                       poGDS->dataspace_id,
                       H5P_DEFAULT,
                       pImage );

    H5Sclose( memspace );

    if( status < 0 )
    {
        CPLError( CE_Failure, CPLE_AppDefined,
                  "H5Dread() failed for block." );
        return CE_Failure;
    }

    return CE_None;
}