GDALDataset *NDFDataset::Open( GDALOpenInfo * poOpenInfo ) { /* -------------------------------------------------------------------- */ /* The user must select the header file (ie. .H1). */ /* -------------------------------------------------------------------- */ if( poOpenInfo->nHeaderBytes < 50 ) return NULL; if( !EQUALN((const char *)poOpenInfo->pabyHeader,"NDF_REVISION=2",14) && !EQUALN((const char *)poOpenInfo->pabyHeader,"NDF_REVISION=0",14) ) return NULL; /* -------------------------------------------------------------------- */ /* Read and process the header into a local name/value */ /* stringlist. We just take off the trailing semicolon. The */ /* keyword is already seperated from the value by an equal */ /* sign. */ /* -------------------------------------------------------------------- */ VSILFILE* fp = VSIFOpenL(poOpenInfo->pszFilename, "rb"); if (fp == NULL) return NULL; const char *pszLine; const int nHeaderMax = 1000; int nHeaderLines = 0; char **papszHeader = (char **) CPLMalloc(sizeof(char *) * (nHeaderMax+1)); while( nHeaderLines < nHeaderMax && (pszLine = CPLReadLineL( fp )) != NULL && !EQUAL(pszLine,"END_OF_HDR;") ) { char *pszFixed; if( strstr(pszLine,"=") == NULL ) break; pszFixed = CPLStrdup( pszLine ); if( pszFixed[strlen(pszFixed)-1] == ';' ) pszFixed[strlen(pszFixed)-1] = '\0'; papszHeader[nHeaderLines++] = pszFixed; papszHeader[nHeaderLines] = NULL; } VSIFCloseL(fp); fp = NULL; if( CSLFetchNameValue( papszHeader, "PIXELS_PER_LINE" ) == NULL || CSLFetchNameValue( papszHeader, "LINES_PER_DATA_FILE" ) == NULL || CSLFetchNameValue( papszHeader, "BITS_PER_PIXEL" ) == NULL || CSLFetchNameValue( papszHeader, "PIXEL_FORMAT" ) == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Dataset appears to be NDF but is missing a required field."); CSLDestroy( papszHeader ); return NULL; } if( !EQUAL(CSLFetchNameValue( papszHeader, "PIXEL_FORMAT"), "BYTE" ) || !EQUAL(CSLFetchNameValue( papszHeader, "BITS_PER_PIXEL"),"8") ) { CPLError( CE_Failure, CPLE_AppDefined, "Currently NDF driver supports only 8bit BYTE format." ); CSLDestroy( papszHeader ); return NULL; } /* -------------------------------------------------------------------- */ /* Confirm the requested access is supported. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->eAccess == GA_Update ) { CSLDestroy( papszHeader ); CPLError( CE_Failure, CPLE_NotSupported, "The NDF driver does not support update access to existing" " datasets.\n" ); return NULL; } /* -------------------------------------------------------------------- */ /* Create a corresponding GDALDataset. */ /* -------------------------------------------------------------------- */ NDFDataset *poDS; poDS = new NDFDataset(); poDS->papszHeader = papszHeader; poDS->nRasterXSize = atoi(poDS->Get("PIXELS_PER_LINE","")); poDS->nRasterYSize = atoi(poDS->Get("LINES_PER_DATA_FILE","")); /* -------------------------------------------------------------------- */ /* Create a raw raster band for each file. */ /* -------------------------------------------------------------------- */ int iBand; const char* pszBand = CSLFetchNameValue(papszHeader, "NUMBER_OF_BANDS_IN_VOLUME"); if (pszBand == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot find band count"); delete poDS; return NULL; } int nBands = atoi(pszBand); if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) || !GDALCheckBandCount(nBands, FALSE)) { delete poDS; return NULL; } for( iBand = 0; iBand < nBands; iBand++ ) { char szKey[100]; CPLString osFilename; sprintf( szKey, "BAND%d_FILENAME", iBand+1 ); osFilename = poDS->Get(szKey,""); // NDF1 file do not include the band filenames. if( osFilename.size() == 0 ) { char szBandExtension[15]; sprintf( szBandExtension, "I%d", iBand+1 ); osFilename = CPLResetExtension( poOpenInfo->pszFilename, szBandExtension ); } else { CPLString osBasePath = CPLGetPath(poOpenInfo->pszFilename); osFilename = CPLFormFilename( osBasePath, osFilename, NULL); } VSILFILE *fpRaw = VSIFOpenL( osFilename, "rb" ); if( fpRaw == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Failed to open band file: %s", osFilename.c_str() ); delete poDS; return NULL; } poDS->papszExtraFiles = CSLAddString( poDS->papszExtraFiles, osFilename ); RawRasterBand *poBand = new RawRasterBand( poDS, iBand+1, fpRaw, 0, 1, poDS->nRasterXSize, GDT_Byte, TRUE, TRUE ); sprintf( szKey, "BAND%d_NAME", iBand+1 ); poBand->SetDescription( poDS->Get(szKey, "") ); sprintf( szKey, "BAND%d_WAVELENGTHS", iBand+1 ); poBand->SetMetadataItem( "WAVELENGTHS", poDS->Get(szKey,"") ); sprintf( szKey, "BAND%d_RADIOMETRIC_GAINS/BIAS", iBand+1 ); poBand->SetMetadataItem( "RADIOMETRIC_GAINS_BIAS", poDS->Get(szKey,"") ); poDS->SetBand( iBand+1, poBand ); } /* -------------------------------------------------------------------- */ /* Fetch and parse USGS projection parameters. */ /* -------------------------------------------------------------------- */ double adfUSGSParms[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; char **papszParmTokens = CSLTokenizeStringComplex( poDS->Get( "USGS_PROJECTION_NUMBER", "" ), ",", FALSE, TRUE ); if( CSLCount( papszParmTokens ) >= 15 ) { int i; for( i = 0; i < 15; i++ ) adfUSGSParms[i] = CPLAtof(papszParmTokens[i]); } CSLDestroy(papszParmTokens); papszParmTokens = NULL; /* -------------------------------------------------------------------- */ /* Minimal georef support ... should add full USGS style */ /* support at some point. */ /* -------------------------------------------------------------------- */ OGRSpatialReference oSRS; int nUSGSProjection = atoi(poDS->Get( "USGS_PROJECTION_NUMBER", "" )); int nZone = atoi(poDS->Get("USGS_MAP_ZONE","0")); oSRS.importFromUSGS( nUSGSProjection, nZone, adfUSGSParms, 12 ); CPLString osDatum = poDS->Get( "HORIZONTAL_DATUM", "" ); if( EQUAL(osDatum,"WGS84") || EQUAL(osDatum,"NAD83") || EQUAL(osDatum,"NAD27") ) { oSRS.SetWellKnownGeogCS( osDatum ); } else if( EQUALN(osDatum,"NAD27",5) ) { oSRS.SetWellKnownGeogCS( "NAD27" ); } else { CPLError( CE_Warning, CPLE_AppDefined, "Unrecognised datum name in NLAPS/NDF file:%s, assuming WGS84.", osDatum.c_str() ); oSRS.SetWellKnownGeogCS( "WGS84" ); } if( oSRS.GetRoot() != NULL ) { CPLFree( poDS->pszProjection ); poDS->pszProjection = NULL; oSRS.exportToWkt( &(poDS->pszProjection) ); } /* -------------------------------------------------------------------- */ /* Get geotransform. */ /* -------------------------------------------------------------------- */ char **papszUL = CSLTokenizeString2( poDS->Get("UPPER_LEFT_CORNER",""), ",", 0 ); char **papszUR = CSLTokenizeString2( poDS->Get("UPPER_RIGHT_CORNER",""), ",", 0 ); char **papszLL = CSLTokenizeString2( poDS->Get("LOWER_LEFT_CORNER",""), ",", 0 ); if( CSLCount(papszUL) == 4 && CSLCount(papszUR) == 4 && CSLCount(papszLL) == 4 ) { poDS->adfGeoTransform[0] = CPLAtof(papszUL[2]); poDS->adfGeoTransform[1] = (CPLAtof(papszUR[2]) - CPLAtof(papszUL[2])) / (poDS->nRasterXSize-1); poDS->adfGeoTransform[2] = (CPLAtof(papszUR[3]) - CPLAtof(papszUL[3])) / (poDS->nRasterXSize-1); poDS->adfGeoTransform[3] = CPLAtof(papszUL[3]); poDS->adfGeoTransform[4] = (CPLAtof(papszLL[2]) - CPLAtof(papszUL[2])) / (poDS->nRasterYSize-1); poDS->adfGeoTransform[5] = (CPLAtof(papszLL[3]) - CPLAtof(papszUL[3])) / (poDS->nRasterYSize-1); // Move origin up-left half a pixel. poDS->adfGeoTransform[0] -= poDS->adfGeoTransform[1] * 0.5; poDS->adfGeoTransform[0] -= poDS->adfGeoTransform[4] * 0.5; poDS->adfGeoTransform[3] -= poDS->adfGeoTransform[2] * 0.5; poDS->adfGeoTransform[3] -= poDS->adfGeoTransform[5] * 0.5; } CSLDestroy( papszUL ); CSLDestroy( papszLL ); CSLDestroy( papszUR ); /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ poDS->SetDescription( poOpenInfo->pszFilename ); poDS->TryLoadXML(); /* -------------------------------------------------------------------- */ /* Check for overviews. */ /* -------------------------------------------------------------------- */ poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); return( poDS ); }
GDALDataset *CTable2Dataset::Open( GDALOpenInfo * poOpenInfo ) { if( !Identify( poOpenInfo ) ) return NULL; /* -------------------------------------------------------------------- */ /* Create a corresponding GDALDataset. */ /* -------------------------------------------------------------------- */ CTable2Dataset *poDS = new CTable2Dataset(); poDS->eAccess = poOpenInfo->eAccess; /* -------------------------------------------------------------------- */ /* Open the file. */ /* -------------------------------------------------------------------- */ CPLString osFilename = poOpenInfo->pszFilename; if( poOpenInfo->eAccess == GA_ReadOnly ) poDS->fpImage = VSIFOpenL( osFilename, "rb" ); else poDS->fpImage = VSIFOpenL( osFilename, "rb+" ); if( poDS->fpImage == NULL ) { delete poDS; return NULL; } /* -------------------------------------------------------------------- */ /* Read the file header. */ /* -------------------------------------------------------------------- */ CPL_IGNORE_RET_VAL(VSIFSeekL( poDS->fpImage, 0, SEEK_SET )); char achHeader[160] = { '\0' }; CPL_IGNORE_RET_VAL(VSIFReadL( achHeader, 1, 160, poDS->fpImage )); achHeader[16+79] = '\0'; CPLString osDescription = reinterpret_cast<const char *>( achHeader + 16 ); osDescription.Trim(); poDS->SetMetadataItem( "DESCRIPTION", osDescription ); /* -------------------------------------------------------------------- */ /* Convert from LSB to local machine byte order. */ /* -------------------------------------------------------------------- */ CPL_LSBPTR64( achHeader + 96 ); CPL_LSBPTR64( achHeader + 104 ); CPL_LSBPTR64( achHeader + 112 ); CPL_LSBPTR64( achHeader + 120 ); CPL_LSBPTR32( achHeader + 128 ); CPL_LSBPTR32( achHeader + 132 ); /* -------------------------------------------------------------------- */ /* Extract size, and geotransform. */ /* -------------------------------------------------------------------- */ int nRasterXSize, nRasterYSize; memcpy( &nRasterXSize, achHeader + 128, 4 ); memcpy( &nRasterYSize, achHeader + 132, 4 ); if (!GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize)) { delete poDS; return NULL; } poDS->nRasterXSize = nRasterXSize; poDS->nRasterYSize = nRasterYSize; double adfValues[4]; memcpy( adfValues, achHeader + 96, sizeof(double)*4 ); for( int i = 0; i < 4; i++ ) adfValues[i] *= 180/M_PI; // Radians to degrees. poDS->adfGeoTransform[0] = adfValues[0] - adfValues[2]*0.5; poDS->adfGeoTransform[1] = adfValues[2]; poDS->adfGeoTransform[2] = 0.0; poDS->adfGeoTransform[3] = adfValues[1] + adfValues[3]*(nRasterYSize-0.5); poDS->adfGeoTransform[4] = 0.0; poDS->adfGeoTransform[5] = -adfValues[3]; /* -------------------------------------------------------------------- */ /* Setup the bands. */ /* -------------------------------------------------------------------- */ RawRasterBand *poBand = new RawRasterBand( poDS, 1, poDS->fpImage, 160 + 4 + nRasterXSize * (nRasterYSize-1) * 2 * 4, 8, -8 * nRasterXSize, GDT_Float32, CPL_IS_LSB, TRUE, FALSE ); poBand->SetDescription( "Latitude Offset (radians)" ); poDS->SetBand( 1, poBand ); poBand = new RawRasterBand( poDS, 2, poDS->fpImage, 160 + nRasterXSize * (nRasterYSize-1) * 2 * 4, 8, -8 * nRasterXSize, GDT_Float32, CPL_IS_LSB, TRUE, FALSE ); poBand->SetDescription( "Longitude Offset (radians)" ); poDS->SetBand( 2, poBand ); /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ poDS->SetDescription( poOpenInfo->pszFilename ); poDS->TryLoadXML(); /* -------------------------------------------------------------------- */ /* Check for overviews. */ /* -------------------------------------------------------------------- */ poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); return poDS; }