Index: frmts/netcdf/netcdfdataset.cpp =================================================================== --- frmts/netcdf/netcdfdataset.cpp (revision 23937) +++ frmts/netcdf/netcdfdataset.cpp (working copy) @@ -32,6 +32,7 @@ CPL_CVSID("$Id$"); #include //for NCDFWriteProjAttribs() +#include /* Internal function declarations */ @@ -3799,6 +3800,9 @@ CPLString osSubdatasetName; int bTreatAsSubdataset; + char szVarName[NC_MAX_NAME]; + CPLString osBandNumbers; + std::vector oBandNumbers; /* -------------------------------------------------------------------- */ /* Does this appear to be a netcdf file? */ @@ -3817,53 +3821,108 @@ netCDFDataset *poDS; poDS = new netCDFDataset(); - poDS->SetDescription( poOpenInfo->pszFilename ); - /* -------------------------------------------------------------------- */ /* Check if filename start with NETCDF: tag */ /* -------------------------------------------------------------------- */ if( EQUALN( poOpenInfo->pszFilename,"NETCDF:",7) ) { - char **papszName = + char **papszFields = CSLTokenizeString2( poOpenInfo->pszFilename, ":", CSLT_HONOURSTRINGS|CSLT_PRESERVEESCAPES ); - + int nFieldCount = CSLCount(papszFields); /* -------------------------------------------------------------------- */ /* Check for drive name in windows NETCDF:"D:\... */ /* -------------------------------------------------------------------- */ - if ( CSLCount(papszName) == 4 && - strlen(papszName[1]) == 1 && - (papszName[2][0] == '/' || papszName[2][0] == '\\') ) + if ( ( nFieldCount == 4 || nFieldCount == 5 ) && + strlen(papszFields[1]) == 1 && + (papszFields[2][0] == '/' || papszFields[2][0] == '\\') ) { - poDS->osFilename = papszName[1]; + poDS->osFilename = papszFields[1]; poDS->osFilename += ':'; - poDS->osFilename += papszName[2]; - osSubdatasetName = papszName[3]; + poDS->osFilename += papszFields[2]; + osSubdatasetName = papszFields[3]; bTreatAsSubdataset = TRUE; - CSLDestroy( papszName ); + if( nFieldCount == 5 ) + osBandNumbers = papszFields[4]; + CSLDestroy( papszFields ); } - else if( CSLCount(papszName) == 3 ) + else if( nFieldCount == 3 || nFieldCount == 4 ) { - poDS->osFilename = papszName[1]; - osSubdatasetName = papszName[2]; + poDS->osFilename = papszFields[1]; + osSubdatasetName = papszFields[2]; bTreatAsSubdataset = TRUE; - CSLDestroy( papszName ); + if( nFieldCount == 4 ) + osBandNumbers = papszFields[3]; + CSLDestroy( papszFields ); } - else if( CSLCount(papszName) == 2 ) + else if( nFieldCount == 2 ) { - poDS->osFilename = papszName[1]; - osSubdatasetName = ""; + poDS->osFilename = papszFields[1]; bTreatAsSubdataset = FALSE; - CSLDestroy( papszName ); + CSLDestroy( papszFields ); } else { - CSLDestroy( papszName ); + CSLDestroy( papszFields ); delete poDS; CPLError( CE_Failure, CPLE_AppDefined, - "Failed to parse NETCDF: prefix string into expected 2, 3 or 4 fields." ); + "Failed to parse NETCDF: prefix string into expected 2, 3 or 4 fields.\n" + "e.g. NETCDF: | NETCDF:: | NETCDF:file.nc: | \n" + " NETCDF::: (=i,j-k" ); return NULL; } + + /* parse band numbers like <1,2,5-6> */ + if ( osBandNumbers.size() > 0 ) { + char **papszTokens = NULL; + char **papszTokens2 = NULL; + int nTemp1=-1, nTemp2=-1; + papszTokens = CSLTokenizeString2( osBandNumbers.c_str(), ",", CSLT_STRIPLEADSPACES | + CSLT_STRIPENDSPACES ); + for ( int i = 0; papszTokens && papszTokens[i]; i++ ) { + papszTokens2 = CSLTokenizeString2( papszTokens[i], "-", CSLT_STRIPLEADSPACES | + CSLT_STRIPENDSPACES ); + if ( CSLCount(papszTokens2) == 1 ) { + nTemp1 = atoi(papszTokens2[0]); + if ( CPLGetValueType(papszTokens2[0])!=CPL_VALUE_INTEGER || + nTemp1<1 ) { + CPLError( CE_Warning, CPLE_AppDefined, + "[%s] is not a positive integer",papszTokens2[0] ); + } + else + oBandNumbers.push_back(nTemp1); + } + else if ( CSLCount(papszTokens2) == 2 ) { + if ( CPLGetValueType(papszTokens2[0])==CPL_VALUE_INTEGER ) + nTemp1=atoi(papszTokens2[0]); + if ( CPLGetValueType(papszTokens2[1])==CPL_VALUE_INTEGER ) + nTemp2=atoi(papszTokens2[1]); + if ( (nTemp1 < 1) || (nTemp2 < 1) || (nTemp1 > nTemp2) ) { + CPLError( CE_Warning, CPLE_AppDefined, + "[%s] is not a supported integer sequence",papszTokens[i] ); + } + else { + for ( int j=nTemp1; j<=nTemp2; j++ ) + oBandNumbers.push_back(j); + } + } + else + CPLError( CE_Warning, CPLE_AppDefined, + "[%s] is not a supported integer sequence",papszTokens[i] ); + CSLDestroy( papszTokens2 ); + } + std::sort(oBandNumbers.begin(), oBandNumbers.end()); + if ( oBandNumbers.empty() ) { + delete poDS; + CPLError( CE_Failure, CPLE_AppDefined, + "Did not parse any valid values from [%s]", + osBandNumbers.c_str() ); + CSLDestroy( papszTokens ); + return NULL; + } + CSLDestroy( papszTokens ); + } + /* Identify Format from real file, with bCheckExt=FALSE */ GDALOpenInfo* poOpenInfo2 = new GDALOpenInfo(poDS->osFilename.c_str(), GA_ReadOnly ); poDS->nFormat = IdentifyFormat( poOpenInfo2, FALSE ); @@ -3881,6 +3940,10 @@ poDS->nFormat = nTmpFormat; } + /* disable PAM if requested a subset of bands, because any stats will be invalid */ + if ( ! oBandNumbers.empty() ) + poDS->nPamFlags |= GPF_DISABLED; + /* -------------------------------------------------------------------- */ /* Try opening the dataset. */ /* -------------------------------------------------------------------- */ @@ -3942,7 +4005,23 @@ /* -------------------------------------------------------------------- */ if( bTreatAsSubdataset ) { - status = nc_inq_varid( cdfid, osSubdatasetName, &var); + /* detect integer value, convert to actual variable value */ + if ( CPLGetValueType(osSubdatasetName.c_str())==CPL_VALUE_INTEGER ) { + var = atoi( osSubdatasetName.c_str() ); + status = nc_inq_varname( cdfid, var, szVarName ); + if( status == NC_NOERR ) { + CPLDebug( "GDAL_netCDF", + "parsed variable number %d corresponding to variable name %s", + var, szVarName ); + osSubdatasetName = szVarName; + status = NC_NOERR; + } + } + /* get varid from name */ + else { + status = nc_inq_varid( cdfid, osSubdatasetName, &var); + } + if( status != NC_NOERR ) { CPLError( CE_Warning, CPLE_AppDefined, "%s is a netCDF file, but %s is not a variable.", @@ -4025,8 +4104,6 @@ /* -------------------------------------------------------------------- */ if( !bTreatAsSubdataset ) // nCount must be 1! { - char szVarName[NC_MAX_NAME]; - nc_inq_varname( cdfid, nVarID, szVarName); osSubdatasetName = szVarName; } @@ -4152,26 +4229,34 @@ } i=0; + for ( unsigned int lev = 0; lev < nTotLevCount ; lev++ ) { - netCDFRasterBand *poBand = - new netCDFRasterBand(poDS, var, nDim, lev, - panBandZLev, panBandDimPos, - paDimIds, i+1 ); - poDS->SetBand( i+1, poBand ); - i++; + if ( oBandNumbers.empty() || + std::find (oBandNumbers.begin(), oBandNumbers.end(), lev+1) != + oBandNumbers.end() ) { + netCDFRasterBand *poBand = + new netCDFRasterBand(poDS, var, nDim, lev, + panBandZLev, panBandDimPos, + paDimIds, i+1 ); + poDS->SetBand( i+1, poBand ); + i++; + } } + poDS->nBands = i; + CPLFree( paDimIds ); CPLFree( panBandDimPos ); CPLFree( panBandZLev ); - poDS->nBands = i; // Handle angular geographic coordinates here /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ + poDS->SetDescription( poOpenInfo->pszFilename ); + if( bTreatAsSubdataset ) { poDS->SetPhysicalFilename( poDS->osFilename ); @@ -5604,3 +5689,4 @@ return dfNoData; } +