EVOLUTION-MANAGER
Edit File: sar_ceosdataset.cpp
/****************************************************************************** * * Project: ASI CEOS Translator * Purpose: GDALDataset driver for CEOS translator. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 2000, Atlantis Scientific Inc. * Copyright (c) 2009-2013, Even Rouault <even dot rouault at mines-paris dot org> * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "ceos.h" #include "cpl_string.h" #include "gdal_frmts.h" #include "gdal_priv.h" #include "rawdataset.h" #include "ogr_srs_api.h" CPL_CVSID("$Id: sar_ceosdataset.cpp 37040 2016-12-30 15:31:43Z rouault $"); static GInt16 CastToGInt16(float val) { if ( val < -32768.0 ) val = -32768.0; if ( val > 32767 ) val = 32767.0; return static_cast<GInt16>(val); } static const char * const CeosExtension[][6] = { { "vol", "led", "img", "trl", "nul", "ext" }, { "vol", "lea", "img", "trl", "nul", "ext" }, { "vol", "led", "img", "tra", "nul", "ext" }, { "vol", "lea", "img", "tra", "nul", "ext" }, { "vdf", "slf", "sdf", "stf", "nvd", "ext" }, { "vdf", "ldr", "img", "tra", "nul", "ext2" }, /* Jers from Japan- not sure if this is generalized as much as it could be */ { "VOLD", "Sarl_01", "Imop_%02d", "Sart_01", "NULL", "base" }, /* Radarsat: basename, not extension */ { "vdf_dat", "lea_%02d", "dat_%02d", "tra_%02d", "nul_vdf", "base" }, /* Ers-1: basename, not extension */ { "vdf_dat", "lea_%02d", "dat_%02d", "tra_%02d", "nul_dat", "base" }, /* Ers-2 from Telaviv */ { "volume", "leader", "image", "trailer", "nul_dat", "whole" }, /* Ers-1 from D-PAF */ { "VDF", "LF", "SLC", "", "", "ext" }, /* Radarsat-1 per #2051 */ { "vol", "sarl", "sard", "sart", "nvol", "ext" }, /* end marker */ { NULL, NULL, NULL, NULL, NULL, NULL } }; static int ProcessData( VSILFILE *fp, int fileid, CeosSARVolume_t *sar, int max_records, vsi_l_offset max_bytes ); static CeosTypeCode_t QuadToTC( int a, int b, int c, int d ) { CeosTypeCode_t abcd; abcd.UCharCode.Subtype1 = (unsigned char) a; abcd.UCharCode.Type = (unsigned char) b; abcd.UCharCode.Subtype2 = (unsigned char) c; abcd.UCharCode.Subtype3 = (unsigned char) d; return abcd; } #define LEADER_DATASET_SUMMARY_TC QuadToTC( 18, 10, 18, 20 ) #define LEADER_DATASET_SUMMARY_ERS2_TC QuadToTC( 10, 10, 31, 20 ) #define LEADER_RADIOMETRIC_COMPENSATION_TC QuadToTC( 18, 51, 18, 20 ) #define VOLUME_DESCRIPTOR_RECORD_TC QuadToTC( 192, 192, 18, 18 ) #define IMAGE_HEADER_RECORD_TC QuadToTC( 63, 192, 18, 18 ) #define LEADER_RADIOMETRIC_DATA_RECORD_TC QuadToTC( 18, 50, 18, 20 ) #define LEADER_MAP_PROJ_RECORD_TC QuadToTC( 10, 20, 31, 20 ) // TODO: recond? /* JERS from Japan has MAP_PROJ recond with different identifiers */ /* see CEOS-SAR-CCT Iss/Rev: 2/0 February 10, 1989 */ #define LEADER_MAP_PROJ_RECORD_JERS_TC QuadToTC( 18, 20, 18, 20 ) /* For ERS calibration and incidence angle information */ #define ERS_GENERAL_FACILITY_DATA_TC QuadToTC( 10, 200, 31, 50 ) #define ERS_GENERAL_FACILITY_DATA_ALT_TC QuadToTC( 10, 216, 31, 50 ) #define RSAT_PROC_PARAM_TC QuadToTC( 18, 120, 18, 20 ) /************************************************************************/ /* ==================================================================== */ /* SAR_CEOSDataset */ /* ==================================================================== */ /************************************************************************/ class SAR_CEOSRasterBand; class CCPRasterBand; class PALSARRasterBand; class SAR_CEOSDataset : public GDALPamDataset { friend class SAR_CEOSRasterBand; friend class CCPRasterBand; friend class PALSARRasterBand; CeosSARVolume_t sVolume; VSILFILE *fpImage; char **papszTempMD; int nGCPCount; GDAL_GCP *pasGCPList; void ScanForGCPs(); void ScanForMetadata(); int ScanForMapProjection(); public: SAR_CEOSDataset(); virtual ~SAR_CEOSDataset(); virtual int GetGCPCount() override; virtual const char *GetGCPProjection() override; virtual const GDAL_GCP *GetGCPs() override; virtual char **GetMetadataDomainList() override; virtual char **GetMetadata( const char * pszDomain ) override; static GDALDataset *Open( GDALOpenInfo * ); }; /************************************************************************/ /* ==================================================================== */ /* CCPRasterBand */ /* ==================================================================== */ /************************************************************************/ class CCPRasterBand : public GDALPamRasterBand { friend class SAR_CEOSDataset; public: CCPRasterBand( SAR_CEOSDataset *, int, GDALDataType ); virtual CPLErr IReadBlock( int, int, void * ) override; }; /************************************************************************/ /* ==================================================================== */ /* PALSARRasterBand */ /* ==================================================================== */ /************************************************************************/ class PALSARRasterBand : public GDALPamRasterBand { friend class SAR_CEOSDataset; public: PALSARRasterBand( SAR_CEOSDataset *, int ); virtual CPLErr IReadBlock( int, int, void * ) override; }; /************************************************************************/ /* ==================================================================== */ /* SAR_CEOSRasterBand */ /* ==================================================================== */ /************************************************************************/ class SAR_CEOSRasterBand : public GDALPamRasterBand { friend class SAR_CEOSDataset; public: SAR_CEOSRasterBand( SAR_CEOSDataset *, int, GDALDataType ); virtual CPLErr IReadBlock( int, int, void * ) override; }; /************************************************************************/ /* SAR_CEOSRasterBand() */ /************************************************************************/ SAR_CEOSRasterBand::SAR_CEOSRasterBand( SAR_CEOSDataset *poGDSIn, int nBandIn, GDALDataType eType ) { poDS = poGDSIn; nBand = nBandIn; eDataType = eType; nBlockXSize = poGDSIn->nRasterXSize; nBlockYSize = 1; } /************************************************************************/ /* IReadBlock() */ /************************************************************************/ CPLErr SAR_CEOSRasterBand::IReadBlock( int /* nBlockXOff */, int nBlockYOff, void * pImage ) { SAR_CEOSDataset *poGDS = (SAR_CEOSDataset *) poDS; struct CeosSARImageDesc *ImageDesc = &(poGDS->sVolume.ImageDesc); int offset; CalcCeosSARImageFilePosition( &(poGDS->sVolume), nBand, nBlockYOff + 1, NULL, &offset ); offset += ImageDesc->ImageDataStart; /* -------------------------------------------------------------------- */ /* Load all the pixel data associated with this scanline. */ /* Ensure we handle multiple record scanlines properly. */ /* -------------------------------------------------------------------- */ int nPixelsRead = 0; GByte *pabyRecord = (GByte *) CPLMalloc( ImageDesc->BytesPerPixel * nBlockXSize ); for( int iRecord = 0; iRecord < ImageDesc->RecordsPerLine; iRecord++ ) { int nPixelsToRead; if( nPixelsRead + ImageDesc->PixelsPerRecord > nBlockXSize ) nPixelsToRead = nBlockXSize - nPixelsRead; else nPixelsToRead = ImageDesc->PixelsPerRecord; CPL_IGNORE_RET_VAL(VSIFSeekL( poGDS->fpImage, offset, SEEK_SET )); CPL_IGNORE_RET_VAL(VSIFReadL( pabyRecord + nPixelsRead * ImageDesc->BytesPerPixel, 1, nPixelsToRead * ImageDesc->BytesPerPixel, poGDS->fpImage )); nPixelsRead += nPixelsToRead; offset += ImageDesc->BytesPerRecord; } /* -------------------------------------------------------------------- */ /* Copy the desired band out based on the size of the type, and */ /* the interleaving mode. */ /* -------------------------------------------------------------------- */ const int nBytesPerSample = GDALGetDataTypeSize( eDataType ) / 8; if( ImageDesc->ChannelInterleaving == CEOS_IL_PIXEL ) { GDALCopyWords( pabyRecord + (nBand-1) * nBytesPerSample, eDataType, ImageDesc->BytesPerPixel, pImage, eDataType, nBytesPerSample, nBlockXSize ); } else if( ImageDesc->ChannelInterleaving == CEOS_IL_LINE ) { GDALCopyWords( pabyRecord + (nBand-1) * nBytesPerSample * nBlockXSize, eDataType, nBytesPerSample, pImage, eDataType, nBytesPerSample, nBlockXSize ); } else if( ImageDesc->ChannelInterleaving == CEOS_IL_BAND ) { memcpy( pImage, pabyRecord, nBytesPerSample * nBlockXSize ); } #ifdef CPL_LSB GDALSwapWords( pImage, nBytesPerSample, nBlockXSize, nBytesPerSample ); #endif CPLFree( pabyRecord ); return CE_None; } /************************************************************************/ /* ==================================================================== */ /* CCPRasterBand */ /* ==================================================================== */ /************************************************************************/ /************************************************************************/ /* CCPRasterBand() */ /************************************************************************/ CCPRasterBand::CCPRasterBand( SAR_CEOSDataset *poGDSIn, int nBandIn, GDALDataType eType ) { poDS = poGDSIn; nBand = nBandIn; eDataType = eType; nBlockXSize = poGDSIn->nRasterXSize; nBlockYSize = 1; if( nBand == 1 ) SetMetadataItem( "POLARIMETRIC_INTERP", "HH" ); else if( nBand == 2 ) SetMetadataItem( "POLARIMETRIC_INTERP", "HV" ); else if( nBand == 3 ) SetMetadataItem( "POLARIMETRIC_INTERP", "VH" ); else if( nBand == 4 ) SetMetadataItem( "POLARIMETRIC_INTERP", "VV" ); } /************************************************************************/ /* IReadBlock() */ /************************************************************************/ /* From: http://southport.jpl.nasa.gov/software/dcomp/dcomp.html ysca = sqrt{ [ (Byte(2) / 254 ) + 1.5] 2Byte(1) } Re(SHH) = byte(3) ysca/127 Im(SHH) = byte(4) ysca/127 Re(SHV) = byte(5) ysca/127 Im(SHV) = byte(6) ysca/127 Re(SVH) = byte(7) ysca/127 Im(SVH) = byte(8) ysca/127 Re(SVV) = byte(9) ysca/127 Im(SVV) = byte(10) ysca/127 */ CPLErr CCPRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff, void * pImage ) { SAR_CEOSDataset *poGDS = (SAR_CEOSDataset *) poDS; struct CeosSARImageDesc *ImageDesc = &(poGDS->sVolume.ImageDesc); int offset = ImageDesc->FileDescriptorLength + ImageDesc->BytesPerRecord * nBlockYOff + ImageDesc->ImageDataStart; /* -------------------------------------------------------------------- */ /* Load all the pixel data associated with this scanline. */ /* -------------------------------------------------------------------- */ const int nBytesToRead = ImageDesc->BytesPerPixel * nBlockXSize; GByte *pabyRecord = (GByte *) CPLMalloc( nBytesToRead ); if( VSIFSeekL( poGDS->fpImage, offset, SEEK_SET ) != 0 || (int) VSIFReadL( pabyRecord, 1, nBytesToRead, poGDS->fpImage ) != nBytesToRead ) { CPLError( CE_Failure, CPLE_FileIO, "Error reading %d bytes of CEOS record data at offset %d.\n" "Reading file %s failed.", nBytesToRead, offset, poGDS->GetDescription() ); CPLFree( pabyRecord ); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Initialize our power table if this is our first time through. */ /* -------------------------------------------------------------------- */ static float afPowTable[256]; static bool bPowTableInitialized = false; if( !bPowTableInitialized ) { bPowTableInitialized = true; for( int i = 0; i < 256; i++ ) { afPowTable[i] = (float)pow( 2.0, i-128 ); } } /* -------------------------------------------------------------------- */ /* Copy the desired band out based on the size of the type, and */ /* the interleaving mode. */ /* -------------------------------------------------------------------- */ for( int iX = 0; iX < nBlockXSize; iX++ ) { unsigned char *pabyGroup = pabyRecord + iX * ImageDesc->BytesPerPixel; signed char *Byte = (signed char*)pabyGroup-1; /* A ones based alias */ double dfReSHH, dfImSHH, dfReSHV, dfImSHV, dfReSVH, dfImSVH, dfReSVV, dfImSVV; const double dfScale = sqrt( (Byte[2] / 254.0 + 1.5) * afPowTable[Byte[1] + 128] ); if( nBand == 1 ) { dfReSHH = Byte[3] * dfScale / 127.0; dfImSHH = Byte[4] * dfScale / 127.0; ((float *) pImage)[iX*2 ] = (float)dfReSHH; ((float *) pImage)[iX*2+1] = (float)dfImSHH; } else if( nBand == 2 ) { dfReSHV = Byte[5] * dfScale / 127.0; dfImSHV = Byte[6] * dfScale / 127.0; ((float *) pImage)[iX*2 ] = (float)dfReSHV; ((float *) pImage)[iX*2+1] = (float)dfImSHV; } else if( nBand == 3 ) { dfReSVH = Byte[7] * dfScale / 127.0; dfImSVH = Byte[8] * dfScale / 127.0; ((float *) pImage)[iX*2 ] = (float)dfReSVH; ((float *) pImage)[iX*2+1] = (float)dfImSVH; } else if( nBand == 4 ) { dfReSVV = Byte[9] * dfScale / 127.0; dfImSVV = Byte[10]* dfScale / 127.0; ((float *) pImage)[iX*2 ] = (float)dfReSVV; ((float *) pImage)[iX*2+1] = (float)dfImSVV; } } CPLFree( pabyRecord ); return CE_None; } /************************************************************************/ /* ==================================================================== */ /* PALSARRasterBand */ /* ==================================================================== */ /************************************************************************/ /************************************************************************/ /* PALSARRasterBand() */ /************************************************************************/ PALSARRasterBand::PALSARRasterBand( SAR_CEOSDataset *poGDSIn, int nBandIn ) { poDS = poGDSIn; nBand = nBandIn; eDataType = GDT_CInt16; nBlockXSize = poGDSIn->nRasterXSize; nBlockYSize = 1; if( nBand == 1 ) SetMetadataItem( "POLARIMETRIC_INTERP", "Covariance_11" ); else if( nBand == 2 ) SetMetadataItem( "POLARIMETRIC_INTERP", "Covariance_22" ); else if( nBand == 3 ) SetMetadataItem( "POLARIMETRIC_INTERP", "Covariance_33" ); else if( nBand == 4 ) SetMetadataItem( "POLARIMETRIC_INTERP", "Covariance_12" ); else if( nBand == 5 ) SetMetadataItem( "POLARIMETRIC_INTERP", "Covariance_13" ); else if( nBand == 6 ) SetMetadataItem( "POLARIMETRIC_INTERP", "Covariance_23" ); } /************************************************************************/ /* IReadBlock() */ /* */ /* Based on ERSDAC-VX-CEOS-004 */ /************************************************************************/ CPLErr PALSARRasterBand::IReadBlock( int /* nBlockXOff */, int nBlockYOff, void * pImage ) { SAR_CEOSDataset *poGDS = (SAR_CEOSDataset *) poDS; struct CeosSARImageDesc *ImageDesc = &(poGDS->sVolume.ImageDesc); int offset = ImageDesc->FileDescriptorLength + ImageDesc->BytesPerRecord * nBlockYOff + ImageDesc->ImageDataStart; /* -------------------------------------------------------------------- */ /* Load all the pixel data associated with this scanline. */ /* -------------------------------------------------------------------- */ const int nBytesToRead = ImageDesc->BytesPerPixel * nBlockXSize; GByte *pabyRecord = (GByte *) CPLMalloc( nBytesToRead ); if( VSIFSeekL( poGDS->fpImage, offset, SEEK_SET ) != 0 || (int) VSIFReadL( pabyRecord, 1, nBytesToRead, poGDS->fpImage ) != nBytesToRead ) { CPLError( CE_Failure, CPLE_FileIO, "Error reading %d bytes of CEOS record data at offset %d.\n" "Reading file %s failed.", nBytesToRead, offset, poGDS->GetDescription() ); CPLFree( pabyRecord ); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Copy the desired band out based on the size of the type, and */ /* the interleaving mode. */ /* -------------------------------------------------------------------- */ if( nBand == 1 || nBand == 2 || nBand == 3 ) { // we need to pre-initialize things to set the imaginary component to 0 memset( pImage, 0, nBlockXSize * 4 ); GDALCopyWords( pabyRecord + 4*(nBand - 1), GDT_Int16, 18, pImage, GDT_Int16, 4, nBlockXSize ); #ifdef CPL_LSB GDALSwapWords( pImage, 2, nBlockXSize, 4 ); #endif } else { GDALCopyWords( pabyRecord + 6 + 4*(nBand - 4), GDT_CInt16, 18, pImage, GDT_CInt16, 4, nBlockXSize ); #ifdef CPL_LSB GDALSwapWords( pImage, 2, nBlockXSize*2, 2 ); #endif } CPLFree( pabyRecord ); /* -------------------------------------------------------------------- */ /* Convert the values into covariance form as per: */ /* -------------------------------------------------------------------- */ /* ** 1) PALSAR- adjust so that it reads bands as a covariance matrix, and ** set polarimetric interpretation accordingly: ** ** Covariance_11=HH*conj(HH): already there ** Covariance_22=2*HV*conj(HV): need a factor of 2 ** Covariance_33=VV*conj(VV): already there ** Covariance_12=sqrt(2)*HH*conj(HV): need the sqrt(2) factor ** Covariance_13=HH*conj(VV): already there ** Covariance_23=sqrt(2)*HV*conj(VV): need to take the conjugate, then ** multiply by sqrt(2) ** */ if( nBand == 2 ) { GInt16 *panLine = (GInt16 *) pImage; for( int i = 0; i < nBlockXSize * 2; i++ ) { panLine[i] = (GInt16) CastToGInt16((float)2.0 * panLine[i]); } } else if( nBand == 4 ) { const double sqrt_2 = pow(2.0,0.5); GInt16 *panLine = (GInt16 *) pImage; for( int i = 0; i < nBlockXSize * 2; i++ ) { panLine[i] = (GInt16) CastToGInt16((float)floor(panLine[i] * sqrt_2 + 0.5)); } } else if( nBand == 6 ) { GInt16 *panLine = (GInt16 *) pImage; const double sqrt_2 = pow(2.0,0.5); // real portion - just multiple by sqrt(2) for( int i = 0; i < nBlockXSize * 2; i += 2 ) { panLine[i] = (GInt16) CastToGInt16((float)floor(panLine[i] * sqrt_2 + 0.5)); } // imaginary portion - conjugate and multiply for( int i = 1; i < nBlockXSize * 2; i += 2 ) { panLine[i] = (GInt16) CastToGInt16((float)floor(-panLine[i] * sqrt_2 + 0.5)); } } return CE_None; } /************************************************************************/ /* ==================================================================== */ /* SAR_CEOSDataset */ /* ==================================================================== */ /************************************************************************/ /************************************************************************/ /* SAR_CEOSDataset() */ /************************************************************************/ SAR_CEOSDataset::SAR_CEOSDataset() : fpImage(NULL), papszTempMD(NULL), nGCPCount(0), pasGCPList(NULL) { sVolume.Flavor = 0; sVolume.Sensor = 0; sVolume.ProductType = 0; sVolume.FileNamingConvention = 0; sVolume.VolumeDirectoryFile = 0; sVolume.SARLeaderFile = 0; sVolume.ImagryOptionsFile = 0; sVolume.SARTrailerFile = 0; sVolume.NullVolumeDirectoryFile = 0; sVolume.ImageDesc.ImageDescValid = 0; sVolume.ImageDesc.NumChannels = 0; sVolume.ImageDesc.ChannelInterleaving = 0; sVolume.ImageDesc.DataType = 0; sVolume.ImageDesc.BytesPerRecord = 0; sVolume.ImageDesc.Lines = 0; sVolume.ImageDesc.TopBorderPixels = 0; sVolume.ImageDesc.BottomBorderPixels = 0; sVolume.ImageDesc.PixelsPerLine = 0; sVolume.ImageDesc.LeftBorderPixels = 0; sVolume.ImageDesc.RightBorderPixels = 0; sVolume.ImageDesc.BytesPerPixel = 0; sVolume.ImageDesc.RecordsPerLine = 0; sVolume.ImageDesc.PixelsPerRecord = 0; sVolume.ImageDesc.ImageDataStart = 0; sVolume.ImageDesc.ImageSuffixData = 0; sVolume.ImageDesc.FileDescriptorLength = 0; sVolume.ImageDesc.PixelOrder = 0; sVolume.ImageDesc.LineOrder = 0; sVolume.ImageDesc.PixelDataBytesPerRecord = 0; sVolume.RecordList = NULL; } /************************************************************************/ /* ~SAR_CEOSDataset() */ /************************************************************************/ SAR_CEOSDataset::~SAR_CEOSDataset() { FlushCache(); CSLDestroy( papszTempMD ); if( fpImage != NULL ) CPL_IGNORE_RET_VAL(VSIFCloseL( fpImage )); if( nGCPCount > 0 ) { GDALDeinitGCPs( nGCPCount, pasGCPList ); CPLFree( pasGCPList ); } if( sVolume.RecordList ) { for(Link_t *Links = sVolume.RecordList; Links != NULL; Links = Links->next) { if(Links->object) { DeleteCeosRecord( (CeosRecord_t *) Links->object ); Links->object = NULL; } } DestroyList( sVolume.RecordList ); } FreeRecipes(); } /************************************************************************/ /* GetGCPCount() */ /************************************************************************/ int SAR_CEOSDataset::GetGCPCount() { return nGCPCount; } /************************************************************************/ /* GetGCPProjection() */ /************************************************************************/ const char *SAR_CEOSDataset::GetGCPProjection() { if( nGCPCount > 0 ) return SRS_WKT_WGS84; return ""; } /************************************************************************/ /* GetGCP() */ /************************************************************************/ const GDAL_GCP *SAR_CEOSDataset::GetGCPs() { return pasGCPList; } /************************************************************************/ /* GetMetadataDomainList() */ /************************************************************************/ char **SAR_CEOSDataset::GetMetadataDomainList() { return CSLAddString(GDALDataset::GetMetadataDomainList(), "ceos-FFF-n-n-n-n:r"); } /************************************************************************/ /* GetMetadata() */ /* */ /* We provide our own GetMetadata() so that we can override */ /* behavior for some very specialized domain names intended to */ /* give us access to raw record data. */ /* */ /* The domain must look like: */ /* ceos-FFF-n-n-n-n:r */ /* */ /* FFF - The file id - one of vol, lea, img, trl or nul. */ /* n-n-n-n - the record type code such as 18-10-18-20 for the */ /* dataset summary record in the leader file. */ /* :r - The zero based record number to fetch (optional) */ /* */ /* Note that only records that are pre-loaded will be */ /* accessible, and this normally means that most image records */ /* are not available. */ /************************************************************************/ char **SAR_CEOSDataset::GetMetadata( const char * pszDomain ) { if( pszDomain == NULL || !STARTS_WITH_CI(pszDomain, "ceos-") ) return GDALDataset::GetMetadata( pszDomain ); /* -------------------------------------------------------------------- */ /* Identify which file to fetch the file from. */ /* -------------------------------------------------------------------- */ int nFileId = -1; if( STARTS_WITH_CI(pszDomain, "ceos-vol") ) { nFileId = CEOS_VOLUME_DIR_FILE; } else if( STARTS_WITH_CI(pszDomain, "ceos-lea") ) { nFileId = CEOS_LEADER_FILE; } else if( STARTS_WITH_CI(pszDomain, "ceos-img") ) { nFileId = CEOS_IMAGRY_OPT_FILE; } else if( STARTS_WITH_CI(pszDomain, "ceos-trl") ) { nFileId = CEOS_TRAILER_FILE; } else if( STARTS_WITH_CI(pszDomain, "ceos-nul") ) { nFileId = CEOS_NULL_VOL_FILE; } else return NULL; pszDomain += 8; /* -------------------------------------------------------------------- */ /* Identify the record type. */ /* -------------------------------------------------------------------- */ int a, b, c, d, nRecordIndex = -1; if( sscanf( pszDomain, "-%d-%d-%d-%d:%d", &a, &b, &c, &d, &nRecordIndex ) != 5 && sscanf( pszDomain, "-%d-%d-%d-%d", &a, &b, &c, &d ) != 4 ) { return NULL; } CeosTypeCode_t sTypeCode = QuadToTC( a, b, c, d ); /* -------------------------------------------------------------------- */ /* Try to fetch the record. */ /* -------------------------------------------------------------------- */ CeosRecord_t *record = FindCeosRecord( sVolume.RecordList, sTypeCode, nFileId, -1, nRecordIndex ); if( record == NULL ) return NULL; /* -------------------------------------------------------------------- */ /* Massage the data into a safe textual format. The RawRecord */ /* just has zero bytes turned into spaces while the */ /* EscapedRecord has regular backslash escaping applied to zero */ /* chars, double quotes, and backslashes. */ /* just turn zero bytes into spaces. */ /* -------------------------------------------------------------------- */ CSLDestroy( papszTempMD ); // Escaped version char *pszSafeCopy = CPLEscapeString( (char *) record->Buffer, record->Length, CPLES_BackslashQuotable ); papszTempMD = CSLSetNameValue( NULL, "EscapedRecord", pszSafeCopy ); CPLFree( pszSafeCopy ); // Copy with '\0' replaced by spaces. pszSafeCopy = (char *) CPLCalloc(1,record->Length+1); memcpy( pszSafeCopy, record->Buffer, record->Length ); for( int i = 0; i < record->Length; i++ ) if( pszSafeCopy[i] == '\0' ) pszSafeCopy[i] = ' '; papszTempMD = CSLSetNameValue( papszTempMD, "RawRecord", pszSafeCopy ); CPLFree( pszSafeCopy ); return papszTempMD; } /************************************************************************/ /* ScanForMetadata() */ /************************************************************************/ void SAR_CEOSDataset::ScanForMetadata() { /* -------------------------------------------------------------------- */ /* Get the volume id (with the sensor name) */ /* -------------------------------------------------------------------- */ CeosRecord_t *record = FindCeosRecord( sVolume.RecordList, VOLUME_DESCRIPTOR_RECORD_TC, CEOS_VOLUME_DIR_FILE, -1, -1 ); char szVolId[128]; szVolId[0] = '\0'; char szField[128]; szField[0] = '\0'; if( record != NULL ) { szVolId[16] = '\0'; GetCeosField( record, 61, "A16", szVolId ); SetMetadataItem( "CEOS_LOGICAL_VOLUME_ID", szVolId ); /* -------------------------------------------------------------------- */ /* Processing facility */ /* -------------------------------------------------------------------- */ szField[0] = '\0'; szField[12] = '\0'; GetCeosField( record, 149, "A12", szField ); if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_PROCESSING_FACILITY", szField ); /* -------------------------------------------------------------------- */ /* Agency */ /* -------------------------------------------------------------------- */ szField[8] = '\0'; GetCeosField( record, 141, "A8", szField ); if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_PROCESSING_AGENCY", szField ); /* -------------------------------------------------------------------- */ /* Country */ /* -------------------------------------------------------------------- */ szField[12] = '\0'; GetCeosField( record, 129, "A12", szField ); if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_PROCESSING_COUNTRY", szField ); /* -------------------------------------------------------------------- */ /* software id. */ /* -------------------------------------------------------------------- */ szField[12] = '\0'; GetCeosField( record, 33, "A12", szField ); if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_SOFTWARE_ID", szField ); /* -------------------------------------------------------------------- */ /* product identifier. */ /* -------------------------------------------------------------------- */ szField[8] = '\0'; GetCeosField( record, 261, "A8", szField ); if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_PRODUCT_ID", szField ); /* -------------------------------------------------------------------- */ /* volume identifier. */ /* -------------------------------------------------------------------- */ szField[16] = '\0'; GetCeosField( record, 77, "A16", szField ); if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_VOLSET_ID", szField ); } /* ==================================================================== */ /* Dataset summary record. */ /* ==================================================================== */ record = FindCeosRecord( sVolume.RecordList, LEADER_DATASET_SUMMARY_TC, CEOS_LEADER_FILE, -1, -1 ); if( record == NULL ) record = FindCeosRecord( sVolume.RecordList, LEADER_DATASET_SUMMARY_TC, CEOS_TRAILER_FILE, -1, -1 ); if( record == NULL ) record = FindCeosRecord( sVolume.RecordList, LEADER_DATASET_SUMMARY_ERS2_TC, CEOS_LEADER_FILE, -1, -1 ); if( record != NULL ) { /* -------------------------------------------------------------------- */ /* Get the acquisition date. */ /* -------------------------------------------------------------------- */ szField[0] = '\0'; szField[32] = '\0'; GetCeosField( record, 69, "A32", szField ); SetMetadataItem( "CEOS_ACQUISITION_TIME", szField ); /* -------------------------------------------------------------------- */ /* Ascending/Descending */ /* -------------------------------------------------------------------- */ GetCeosField( record, 101, "A16", szField ); szField[16] = '\0'; if( strstr(szVolId,"RSAT") != NULL && !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_ASC_DES", szField ); /* -------------------------------------------------------------------- */ /* True heading - at least for ERS2. */ /* -------------------------------------------------------------------- */ GetCeosField( record, 149, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_TRUE_HEADING", szField ); /* -------------------------------------------------------------------- */ /* Ellipsoid */ /* -------------------------------------------------------------------- */ GetCeosField( record, 165, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_ELLIPSOID", szField ); /* -------------------------------------------------------------------- */ /* Semimajor, semiminor axis */ /* -------------------------------------------------------------------- */ GetCeosField( record, 181, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_SEMI_MAJOR", szField ); GetCeosField( record, 197, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_SEMI_MINOR", szField ); /* -------------------------------------------------------------------- */ /* SCENE LENGTH KM */ /* -------------------------------------------------------------------- */ GetCeosField( record, 341, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_SCENE_LENGTH_KM", szField ); /* -------------------------------------------------------------------- */ /* SCENE WIDTH KM */ /* -------------------------------------------------------------------- */ GetCeosField( record, 357, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_SCENE_WIDTH_KM", szField ); /* -------------------------------------------------------------------- */ /* MISSION ID */ /* -------------------------------------------------------------------- */ GetCeosField( record, 397, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_MISSION_ID", szField ); /* -------------------------------------------------------------------- */ /* SENSOR ID */ /* -------------------------------------------------------------------- */ GetCeosField( record, 413, "A32", szField ); szField[32] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_SENSOR_ID", szField ); /* -------------------------------------------------------------------- */ /* ORBIT NUMBER */ /* -------------------------------------------------------------------- */ GetCeosField( record, 445, "A8", szField ); szField[8] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_ORBIT_NUMBER", szField ); /* -------------------------------------------------------------------- */ /* Platform latitude */ /* -------------------------------------------------------------------- */ GetCeosField( record, 453, "A8", szField ); szField[8] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_PLATFORM_LATITUDE", szField ); /* -------------------------------------------------------------------- */ /* Platform longitude */ /* -------------------------------------------------------------------- */ GetCeosField( record, 461, "A8", szField ); szField[8] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_PLATFORM_LONGITUDE", szField ); /* -------------------------------------------------------------------- */ /* Platform heading - at least for ERS2. */ /* -------------------------------------------------------------------- */ GetCeosField( record, 469, "A8", szField ); szField[8] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_PLATFORM_HEADING", szField ); /* -------------------------------------------------------------------- */ /* Look Angle. */ /* -------------------------------------------------------------------- */ GetCeosField( record, 477, "A8", szField ); szField[8] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_SENSOR_CLOCK_ANGLE", szField ); /* -------------------------------------------------------------------- */ /* Incidence angle */ /* -------------------------------------------------------------------- */ GetCeosField( record, 485, "A8", szField ); szField[8] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_INC_ANGLE", szField ); /* -------------------------------------------------------------------- */ /* Pixel time direction indicator */ /* -------------------------------------------------------------------- */ GetCeosField( record, 1527, "A8", szField ); szField[8] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_PIXEL_TIME_DIR", szField ); /* -------------------------------------------------------------------- */ /* Line spacing */ /* -------------------------------------------------------------------- */ GetCeosField( record, 1687, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_LINE_SPACING_METERS", szField ); /* -------------------------------------------------------------------- */ /* Pixel spacing */ /* -------------------------------------------------------------------- */ GetCeosField( record, 1703, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_PIXEL_SPACING_METERS", szField ); } /* -------------------------------------------------------------------- */ /* Get the beam mode, for radarsat. */ /* -------------------------------------------------------------------- */ record = FindCeosRecord( sVolume.RecordList, LEADER_RADIOMETRIC_COMPENSATION_TC, CEOS_LEADER_FILE, -1, -1 ); if( strstr(szVolId,"RSAT") != NULL && record != NULL ) { szField[16] = '\0'; GetCeosField( record, 4189, "A16", szField ); SetMetadataItem( "CEOS_BEAM_TYPE", szField ); } /* ==================================================================== */ /* ERS calibration and incidence angle info */ /* ==================================================================== */ record = FindCeosRecord( sVolume.RecordList, ERS_GENERAL_FACILITY_DATA_TC, CEOS_LEADER_FILE, -1, -1 ); if( record == NULL ) record = FindCeosRecord( sVolume.RecordList, ERS_GENERAL_FACILITY_DATA_ALT_TC, CEOS_LEADER_FILE, -1, -1 ); if( record != NULL ) { GetCeosField( record, 13 , "A64", szField ); szField[64] = '\0'; /* Avoid PCS records, which don't contain necessary info */ if( strstr( szField, "GENERAL") == NULL ) record = NULL; } if( record != NULL ) { GetCeosField( record, 583 , "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_INC_ANGLE_FIRST_RANGE", szField ); GetCeosField( record, 599 , "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_INC_ANGLE_CENTRE_RANGE", szField ); GetCeosField( record, 615, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_INC_ANGLE_LAST_RANGE", szField ); GetCeosField( record, 663, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_CALIBRATION_CONSTANT_K", szField ); GetCeosField( record, 1855, "A20", szField ); szField[20] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_GROUND_TO_SLANT_C0", szField ); GetCeosField( record, 1875, "A20", szField ); szField[20] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_GROUND_TO_SLANT_C1", szField ); GetCeosField( record, 1895, "A20", szField ); szField[20] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_GROUND_TO_SLANT_C2", szField ); GetCeosField( record, 1915, "A20", szField ); szField[20] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_GROUND_TO_SLANT_C3", szField ); } /* -------------------------------------------------------------------- */ /* Detailed Processing Parameters (Radarsat) */ /* -------------------------------------------------------------------- */ record = FindCeosRecord( sVolume.RecordList, RSAT_PROC_PARAM_TC, CEOS_LEADER_FILE, -1, -1 ); if( record == NULL ) record = FindCeosRecord( sVolume.RecordList, RSAT_PROC_PARAM_TC, CEOS_TRAILER_FILE, -1, -1 ); if( record != NULL ) { GetCeosField( record, 192, "A21", szField ); szField[21] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_PROC_START", szField ); GetCeosField( record, 213, "A21", szField ); szField[21] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_PROC_STOP", szField ); GetCeosField( record, 4649, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_EPH_ORB_DATA_0", szField ); GetCeosField( record, 4665, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_EPH_ORB_DATA_1", szField ); GetCeosField( record, 4681, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_EPH_ORB_DATA_2", szField ); GetCeosField( record, 4697, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_EPH_ORB_DATA_3", szField ); GetCeosField( record, 4713, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_EPH_ORB_DATA_4", szField ); GetCeosField( record, 4729, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_EPH_ORB_DATA_5", szField ); GetCeosField( record, 4745, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_EPH_ORB_DATA_6", szField ); GetCeosField( record, 4908, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_GROUND_TO_SLANT_C0", szField ); GetCeosField( record, 4924, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_GROUND_TO_SLANT_C1", szField ); GetCeosField( record, 4940, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_GROUND_TO_SLANT_C2", szField ); GetCeosField( record, 4956, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_GROUND_TO_SLANT_C3", szField ); GetCeosField( record, 4972, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_GROUND_TO_SLANT_C4", szField ); GetCeosField( record, 4988, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_GROUND_TO_SLANT_C5", szField ); GetCeosField( record, 7334, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_INC_ANGLE_FIRST_RANGE", szField ); GetCeosField( record, 7350, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_INC_ANGLE_LAST_RANGE", szField ); } /* -------------------------------------------------------------------- */ /* Get process-to-raw data coordinate translation values. These */ /* are likely specific to Atlantis APP products. */ /* -------------------------------------------------------------------- */ record = FindCeosRecord( sVolume.RecordList, IMAGE_HEADER_RECORD_TC, CEOS_IMAGRY_OPT_FILE, -1, -1 ); if( record != NULL ) { GetCeosField( record, 449, "A4", szField ); szField[4] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_DM_CORNER", szField ); GetCeosField( record, 453, "A4", szField ); szField[4] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_DM_TRANSPOSE", szField ); GetCeosField( record, 457, "A4", szField ); szField[4] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_DM_START_SAMPLE", szField ); GetCeosField( record, 461, "A5", szField ); szField[5] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_DM_START_PULSE", szField ); GetCeosField( record, 466, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_DM_FAST_ALPHA", szField ); GetCeosField( record, 482, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_DM_FAST_BETA", szField ); GetCeosField( record, 498, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_DM_SLOW_ALPHA", szField ); GetCeosField( record, 514, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_DM_SLOW_BETA", szField ); GetCeosField( record, 530, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_DM_FAST_ALPHA_2", szField ); } /* -------------------------------------------------------------------- */ /* Try to find calibration information from Radiometric Data */ /* Record. */ /* -------------------------------------------------------------------- */ record = FindCeosRecord( sVolume.RecordList, LEADER_RADIOMETRIC_DATA_RECORD_TC, CEOS_LEADER_FILE, -1, -1 ); if( record == NULL ) record = FindCeosRecord( sVolume.RecordList, LEADER_RADIOMETRIC_DATA_RECORD_TC, CEOS_TRAILER_FILE, -1, -1 ); if( record != NULL ) { GetCeosField( record, 8317, "A16", szField ); szField[16] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_CALIBRATION_OFFSET", szField ); } /* -------------------------------------------------------------------- */ /* For ERS Standard Format Landsat scenes we pick up the */ /* calibration offset and gain from the Radiometric Ancillary */ /* Record. */ /* -------------------------------------------------------------------- */ record = FindCeosRecord( sVolume.RecordList, QuadToTC( 0x3f, 0x24, 0x12, 0x09 ), CEOS_LEADER_FILE, -1, -1 ); if( record != NULL ) { GetCeosField( record, 29, "A20", szField ); szField[20] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_OFFSET_A0", szField ); GetCeosField( record, 49, "A20", szField ); szField[20] = '\0'; if( !STARTS_WITH_CI(szField, " ") ) SetMetadataItem( "CEOS_GAIN_A1", szField ); } /* -------------------------------------------------------------------- */ /* For ERS Standard Format Landsat scenes we pick up the */ /* gain setting from the Scene Header Record. */ /* -------------------------------------------------------------------- */ record = FindCeosRecord( sVolume.RecordList, QuadToTC( 0x12, 0x12, 0x12, 0x09 ), CEOS_LEADER_FILE, -1, -1 ); if( record != NULL ) { GetCeosField( record, 1486, "A1", szField ); szField[1] = '\0'; if( szField[0] == 'H' || szField[0] == 'V' ) SetMetadataItem( "CEOS_GAIN_SETTING", szField ); } } /************************************************************************/ /* ScanForMapProjection() */ /* */ /* Try to find a map projection record, and read corner points */ /* from it. This has only been tested with ERS products. */ /************************************************************************/ int SAR_CEOSDataset::ScanForMapProjection() { /* -------------------------------------------------------------------- */ /* Find record, and try to determine if it has useful GCPs. */ /* -------------------------------------------------------------------- */ CeosRecord_t *record = FindCeosRecord( sVolume.RecordList, LEADER_MAP_PROJ_RECORD_TC, CEOS_LEADER_FILE, -1, -1 ); /* JERS from Japan */ if( record == NULL ) record = FindCeosRecord( sVolume.RecordList, LEADER_MAP_PROJ_RECORD_JERS_TC, CEOS_LEADER_FILE, -1, -1 ); if( record == NULL ) return FALSE; char szField[100]; memset( szField, 0, 17 ); GetCeosField( record, 29, "A16", szField ); if( !STARTS_WITH_CI(szField, "Slant Range") && !STARTS_WITH_CI(szField, "Ground Range") && !STARTS_WITH_CI(szField, "GEOCODED") ) return FALSE; GetCeosField( record, 1073, "A16", szField ); if( STARTS_WITH_CI(szField, " ") ) return FALSE; /* -------------------------------------------------------------------- */ /* Read corner points. */ /* -------------------------------------------------------------------- */ nGCPCount = 4; pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nGCPCount); GDALInitGCPs( nGCPCount, pasGCPList ); for( int i = 0; i < nGCPCount; i++ ) { char szId[32]; snprintf( szId, sizeof(szId), "%d", i+1 ); pasGCPList[i].pszId = CPLStrdup( szId ); GetCeosField( record, 1073+32*i, "A16", szField ); pasGCPList[i].dfGCPY = CPLAtof(szField); GetCeosField( record, 1089+32*i, "A16", szField ); pasGCPList[i].dfGCPX = CPLAtof(szField); pasGCPList[i].dfGCPZ = 0.0; } pasGCPList[0].dfGCPLine = 0.5; pasGCPList[0].dfGCPPixel = 0.5; pasGCPList[1].dfGCPLine = 0.5; pasGCPList[1].dfGCPPixel = nRasterXSize-0.5; pasGCPList[2].dfGCPLine = nRasterYSize-0.5; pasGCPList[2].dfGCPPixel = nRasterXSize-0.5; pasGCPList[3].dfGCPLine = nRasterYSize-0.5; pasGCPList[3].dfGCPPixel = 0.5; return TRUE; } /************************************************************************/ /* ScanForGCPs() */ /************************************************************************/ void SAR_CEOSDataset::ScanForGCPs() { /* -------------------------------------------------------------------- */ /* Do we have a standard 180 bytes of prefix data (192 bytes */ /* including the record marker information)? If not, it is */ /* unlikely that the GCPs are available. */ /* -------------------------------------------------------------------- */ if( sVolume.ImageDesc.ImageDataStart < 192 ) { ScanForMapProjection(); return; } /* -------------------------------------------------------------------- */ /* Just sample fix scanlines through the image for GCPs, to */ /* return 15 GCPs. That is an adequate coverage for most */ /* purposes. A GCP is collected from the beginning, middle and */ /* end of each scanline. */ /* -------------------------------------------------------------------- */ nGCPCount = 0; int nGCPMax = 15; pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nGCPMax); int nStep = (GetRasterYSize()-1) / (nGCPMax / 3 - 1); for( int iScanline = 0; iScanline < GetRasterYSize(); iScanline += nStep ) { if( nGCPCount > nGCPMax-3 ) break; int nFileOffset; CalcCeosSARImageFilePosition( &sVolume, 1, iScanline+1, NULL, &nFileOffset ); GInt32 anRecord[192/4]; if( VSIFSeekL( fpImage, nFileOffset, SEEK_SET ) != 0 || VSIFReadL( anRecord, 1, 192, fpImage ) != 192 ) break; /* loop over first, middle and last pixel gcps */ for( int iGCP = 0; iGCP < 3; iGCP++ ) { const int nLat = CPL_MSBWORD32( anRecord[132/4 + iGCP] ); const int nLong = CPL_MSBWORD32( anRecord[144/4 + iGCP] ); if( nLat != 0 || nLong != 0 ) { GDALInitGCPs( 1, pasGCPList + nGCPCount ); CPLFree( pasGCPList[nGCPCount].pszId ); char szId[32]; snprintf( szId, sizeof(szId), "%d", nGCPCount+1 ); pasGCPList[nGCPCount].pszId = CPLStrdup( szId ); pasGCPList[nGCPCount].dfGCPX = nLong / 1000000.0; pasGCPList[nGCPCount].dfGCPY = nLat / 1000000.0; pasGCPList[nGCPCount].dfGCPZ = 0.0; pasGCPList[nGCPCount].dfGCPLine = iScanline + 0.5; if( iGCP == 0 ) pasGCPList[nGCPCount].dfGCPPixel = 0.5; else if( iGCP == 1 ) pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() / 2.0; else pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() - 0.5; nGCPCount++; } } } /* If general GCP's were not found, look for Map Projection (e.g. JERS) */ if( nGCPCount == 0 ) { ScanForMapProjection(); return; } } /************************************************************************/ /* Open() */ /************************************************************************/ GDALDataset *SAR_CEOSDataset::Open( GDALOpenInfo * poOpenInfo ) { /* -------------------------------------------------------------------- */ /* Does this appear to be a valid ceos leader record? */ /* -------------------------------------------------------------------- */ if( poOpenInfo->nHeaderBytes < CEOS_HEADER_LENGTH ) return NULL; if( (poOpenInfo->pabyHeader[4] != 0x3f && poOpenInfo->pabyHeader[4] != 0x32) || poOpenInfo->pabyHeader[5] != 0xc0 || poOpenInfo->pabyHeader[6] != 0x12 || poOpenInfo->pabyHeader[7] != 0x12 ) return NULL; // some products (#1862) have byte swapped record length/number // values and will blow stuff up -- explicitly ignore if record index // value appears to be little endian. if( poOpenInfo->pabyHeader[0] != 0 ) return NULL; /* -------------------------------------------------------------------- */ /* Confirm the requested access is supported. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->eAccess == GA_Update ) { CPLError( CE_Failure, CPLE_NotSupported, "The SAR_CEOS driver does not support update access to existing" " datasets.\n" ); return NULL; } /* -------------------------------------------------------------------- */ /* Open the file. */ /* -------------------------------------------------------------------- */ VSILFILE *fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" ); if( fp == NULL ) return NULL; /* -------------------------------------------------------------------- */ /* Create a corresponding GDALDataset. */ /* -------------------------------------------------------------------- */ SAR_CEOSDataset *poDS = new SAR_CEOSDataset(); CeosSARVolume_t *psVolume = &(poDS->sVolume); InitCeosSARVolume( psVolume, 0 ); /* -------------------------------------------------------------------- */ /* Try to read the current file as an imagery file. */ /* -------------------------------------------------------------------- */ psVolume->ImagryOptionsFile = TRUE; if( ProcessData( fp, CEOS_IMAGRY_OPT_FILE, psVolume, 4, VSI_L_OFFSET_MAX) != CE_None ) { delete poDS; CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); return NULL; } /* -------------------------------------------------------------------- */ /* Try the various filenames. */ /* -------------------------------------------------------------------- */ char *pszPath = CPLStrdup(CPLGetPath(poOpenInfo->pszFilename)); char *pszBasename = CPLStrdup(CPLGetBasename(poOpenInfo->pszFilename)); char *pszExtension = CPLStrdup(CPLGetExtension(poOpenInfo->pszFilename)); int nBand; if( strlen(pszBasename) > 4 ) nBand = atoi( pszBasename + 4 ); else nBand = 0; for( int iFile = 0; iFile < 5;iFile++ ) { /* skip image file ... we already did it */ if( iFile == 2 ) continue; int e = 0; while( CeosExtension[e][iFile] != NULL ) { char *pszFilename = NULL; /* build filename */ if( EQUAL(CeosExtension[e][5],"base") ) { char szMadeBasename[32]; snprintf( szMadeBasename, sizeof(szMadeBasename), CeosExtension[e][iFile], nBand ); pszFilename = CPLStrdup( CPLFormFilename(pszPath,szMadeBasename, pszExtension)); } else if( EQUAL(CeosExtension[e][5],"ext") ) { pszFilename = CPLStrdup( CPLFormFilename(pszPath,pszBasename, CeosExtension[e][iFile])); } else if( EQUAL(CeosExtension[e][5],"whole") ) { pszFilename = CPLStrdup( CPLFormFilename(pszPath,CeosExtension[e][iFile],"")); } // This is for SAR SLC as per the SAR Toolbox (from ASF). else if( EQUAL(CeosExtension[e][5],"ext2") ) { char szThisExtension[32]; if( strlen(pszExtension) > 3 ) snprintf( szThisExtension, sizeof(szThisExtension), "%s%s", CeosExtension[e][iFile], pszExtension+3 ); else snprintf( szThisExtension, sizeof(szThisExtension), "%s", CeosExtension[e][iFile] ); pszFilename = CPLStrdup( CPLFormFilename(pszPath,pszBasename,szThisExtension)); } CPLAssert( pszFilename != NULL ); if( pszFilename == NULL ) return NULL; /* try to open */ VSILFILE *process_fp = VSIFOpenL( pszFilename, "rb" ); /* try upper case */ if( process_fp == NULL ) { for( int i = static_cast<int>(strlen(pszFilename))-1; i >= 0 && pszFilename[i] != '/' && pszFilename[i] != '\\'; i-- ) { if( pszFilename[i] >= 'a' && pszFilename[i] <= 'z' ) pszFilename[i] = pszFilename[i] - 'a' + 'A'; } process_fp = VSIFOpenL( pszFilename, "rb" ); } if( process_fp != NULL ) { CPLDebug( "CEOS", "Opened %s.\n", pszFilename ); CPL_IGNORE_RET_VAL(VSIFSeekL( process_fp, 0, SEEK_END )); if( ProcessData( process_fp, iFile, psVolume, -1, VSIFTellL( process_fp ) ) == 0 ) { switch( iFile ) { case 0: psVolume->VolumeDirectoryFile = TRUE; break; case 1: psVolume->SARLeaderFile = TRUE; break; case 3: psVolume->SARTrailerFile = TRUE; break; case 4: psVolume->NullVolumeDirectoryFile = TRUE; break; } CPL_IGNORE_RET_VAL(VSIFCloseL( process_fp )); CPLFree( pszFilename ); break; /* Exit the while loop, we have this data type*/ } CPL_IGNORE_RET_VAL(VSIFCloseL( process_fp )); } CPLFree( pszFilename ); e++; } } CPLFree( pszPath ); CPLFree( pszBasename ); CPLFree( pszExtension ); /* -------------------------------------------------------------------- */ /* Check that we have an image description. */ /* -------------------------------------------------------------------- */ GetCeosSARImageDesc( psVolume ); struct CeosSARImageDesc *psImageDesc = &(psVolume->ImageDesc); if( !psImageDesc->ImageDescValid ) { delete poDS; CPLDebug( "CEOS", "Unable to extract CEOS image description\n" "from %s.", poOpenInfo->pszFilename ); CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); return NULL; } /* -------------------------------------------------------------------- */ /* Establish image type. */ /* -------------------------------------------------------------------- */ GDALDataType eType; switch( psImageDesc->DataType ) { case CEOS_TYP_CHAR: case CEOS_TYP_UCHAR: eType = GDT_Byte; break; case CEOS_TYP_SHORT: eType = GDT_Int16; break; case CEOS_TYP_COMPLEX_SHORT: case CEOS_TYP_PALSAR_COMPLEX_SHORT: eType = GDT_CInt16; break; case CEOS_TYP_USHORT: eType = GDT_UInt16; break; case CEOS_TYP_LONG: eType = GDT_Int32; break; case CEOS_TYP_ULONG: eType = GDT_UInt32; break; case CEOS_TYP_FLOAT: eType = GDT_Float32; break; case CEOS_TYP_DOUBLE: eType = GDT_Float64; break; case CEOS_TYP_COMPLEX_FLOAT: case CEOS_TYP_CCP_COMPLEX_FLOAT: eType = GDT_CFloat32; break; default: CPLError( CE_Failure, CPLE_AppDefined, "Unsupported CEOS image data type %d.\n", psImageDesc->DataType ); delete poDS; return NULL; } /* -------------------------------------------------------------------- */ /* Capture some information from the file that is of interest. */ /* -------------------------------------------------------------------- */ poDS->nRasterXSize = psImageDesc->PixelsPerLine; poDS->nRasterYSize = psImageDesc->Lines; const int bNative = #ifdef CPL_LSB FALSE #else TRUE #endif ; /* -------------------------------------------------------------------- */ /* Special case for compressed cross products. */ /* -------------------------------------------------------------------- */ if( psImageDesc->DataType == CEOS_TYP_CCP_COMPLEX_FLOAT ) { for( int iBand = 0; iBand < psImageDesc->NumChannels; iBand++ ) { poDS->SetBand( poDS->nBands+1, new CCPRasterBand( poDS, poDS->nBands+1, eType ) ); } /* mark this as a Scattering Matrix product */ if ( poDS->GetRasterCount() == 4 ) { poDS->SetMetadataItem( "MATRIX_REPRESENTATION", "SCATTERING" ); } } /* -------------------------------------------------------------------- */ /* Special case for PALSAR data. */ /* -------------------------------------------------------------------- */ else if( psImageDesc->DataType == CEOS_TYP_PALSAR_COMPLEX_SHORT ) { for( int iBand = 0; iBand < psImageDesc->NumChannels; iBand++ ) { poDS->SetBand( poDS->nBands+1, new PALSARRasterBand( poDS, poDS->nBands+1 ) ); } /* mark this as a Symmetrized Covariance product if appropriate */ if ( poDS->GetRasterCount() == 6 ) { poDS->SetMetadataItem( "MATRIX_REPRESENTATION", "SYMMETRIZED_COVARIANCE" ); } } /* -------------------------------------------------------------------- */ /* Roll our own ... */ /* -------------------------------------------------------------------- */ else if( psImageDesc->RecordsPerLine > 1 || psImageDesc->DataType == CEOS_TYP_CHAR || psImageDesc->DataType == CEOS_TYP_LONG || psImageDesc->DataType == CEOS_TYP_ULONG || psImageDesc->DataType == CEOS_TYP_DOUBLE ) { for( int iBand = 0; iBand < psImageDesc->NumChannels; iBand++ ) { poDS->SetBand( poDS->nBands+1, new SAR_CEOSRasterBand( poDS, poDS->nBands+1, eType ) ); } } /* -------------------------------------------------------------------- */ /* Use raw services for well behaved files. */ /* -------------------------------------------------------------------- */ else { int StartData; CalcCeosSARImageFilePosition( psVolume, 1, 1, NULL, &StartData ); /*StartData += psImageDesc->ImageDataStart; */ int nLineSize, nLineSize2; CalcCeosSARImageFilePosition( psVolume, 1, 1, NULL, &nLineSize ); CalcCeosSARImageFilePosition( psVolume, 1, 2, NULL, &nLineSize2 ); nLineSize = nLineSize2 - nLineSize; for( int iBand = 0; iBand < psImageDesc->NumChannels; iBand++ ) { int nStartData, nPixelOffset, nLineOffset; if( psImageDesc->ChannelInterleaving == CEOS_IL_PIXEL ) { CalcCeosSARImageFilePosition(psVolume,1,1,NULL,&nStartData); nStartData += psImageDesc->ImageDataStart; nStartData += psImageDesc->BytesPerPixel * iBand; nPixelOffset = psImageDesc->BytesPerPixel * psImageDesc->NumChannels; nLineOffset = nLineSize; } else if( psImageDesc->ChannelInterleaving == CEOS_IL_LINE ) { CalcCeosSARImageFilePosition(psVolume, iBand+1, 1, NULL, &nStartData); nStartData += psImageDesc->ImageDataStart; nPixelOffset = psImageDesc->BytesPerPixel; nLineOffset = nLineSize * psImageDesc->NumChannels; } else if( psImageDesc->ChannelInterleaving == CEOS_IL_BAND ) { CalcCeosSARImageFilePosition(psVolume, iBand+1, 1, NULL, &nStartData); nStartData += psImageDesc->ImageDataStart; nPixelOffset = psImageDesc->BytesPerPixel; nLineOffset = nLineSize; } else { CPLAssert( false ); return NULL; } poDS->SetBand( poDS->nBands+1, new RawRasterBand( poDS, poDS->nBands+1, fp, nStartData, nPixelOffset, nLineOffset, eType, bNative, TRUE ) ); } } /* -------------------------------------------------------------------- */ /* Adopt the file pointer. */ /* -------------------------------------------------------------------- */ poDS->fpImage = fp; /* -------------------------------------------------------------------- */ /* Collect metadata. */ /* -------------------------------------------------------------------- */ poDS->ScanForMetadata(); /* -------------------------------------------------------------------- */ /* Check for GCPs. */ /* -------------------------------------------------------------------- */ poDS->ScanForGCPs(); /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ poDS->SetDescription( poOpenInfo->pszFilename ); poDS->TryLoadXML(); /* -------------------------------------------------------------------- */ /* Open overviews. */ /* -------------------------------------------------------------------- */ poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); return poDS; } /************************************************************************/ /* ProcessData() */ /************************************************************************/ static int ProcessData( VSILFILE *fp, int fileid, CeosSARVolume_t *sar, int max_records, vsi_l_offset max_bytes ) { unsigned char temp_buffer[CEOS_HEADER_LENGTH]; unsigned char *temp_body = NULL; int start = 0; int CurrentBodyLength = 0; int CurrentType = 0; int CurrentSequence = 0; int iThisRecord = 0; while(max_records != 0 && max_bytes != 0) { iThisRecord++; if( VSIFSeekL( fp, start, SEEK_SET ) != 0 || VSIFReadL( temp_buffer, 1, CEOS_HEADER_LENGTH, fp ) != CEOS_HEADER_LENGTH ) { CPLError( CE_Failure, CPLE_AppDefined, "Corrupt CEOS File - cannot read record %d.", iThisRecord ); CPLFree(temp_body); return CE_Failure; } CeosRecord_t *record = (CeosRecord_t *) CPLMalloc( sizeof( CeosRecord_t ) ); record->Length = DetermineCeosRecordBodyLength( temp_buffer ); CeosToNative( &(record->Sequence), temp_buffer, 4, 4 ); if( iThisRecord != record->Sequence ) { if( fileid == CEOS_IMAGRY_OPT_FILE && iThisRecord == 2 ) { CPLDebug( "SAR_CEOS", "Ignoring CEOS file with wrong second record sequence number - likely it has padded records." ); CPLFree(record); CPLFree(temp_body); return CE_Warning; } else { CPLError( CE_Failure, CPLE_AppDefined, "Corrupt CEOS File - got record seq# %d instead of the expected %d.", record->Sequence, iThisRecord ); CPLFree(record); CPLFree(temp_body); return CE_Failure; } } if( record->Length <= CEOS_HEADER_LENGTH ) { CPLError( CE_Failure, CPLE_AppDefined, "Corrupt CEOS File - cannot read record %d.", iThisRecord ); CPLFree(record); CPLFree(temp_body); return CE_Failure; } if( record->Length > CurrentBodyLength ) { unsigned char* temp_body_new = (unsigned char *) VSI_REALLOC_VERBOSE( temp_body, record->Length ); if( temp_body_new == NULL ) { CPLFree(record); CPLFree(temp_body); return CE_Failure; } temp_body = temp_body_new; CurrentBodyLength = record->Length; } int nToRead = record->Length-CEOS_HEADER_LENGTH; if( (int)VSIFReadL( temp_body, 1, nToRead,fp) != nToRead ) { CPLError( CE_Failure, CPLE_AppDefined, "Corrupt CEOS File - cannot read record %d.", iThisRecord ); CPLFree(record); CPLFree(temp_body); return CE_Failure; } InitCeosRecordWithHeader( record, temp_buffer, temp_body ); if( record->Length == 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "Corrupt CEOS File - invalid record %d.", iThisRecord ); CPLFree(record); CPLFree(temp_body); return CE_Failure; } if( CurrentType == record->TypeCode.Int32Code ) record->Subsequence = ++CurrentSequence; else { CurrentType = record->TypeCode.Int32Code; record->Subsequence = 0; CurrentSequence = 0; } record->FileId = fileid; Link_t *TheLink = ceos2CreateLink( record ); if( sar->RecordList == NULL ) sar->RecordList = TheLink; else sar->RecordList = InsertLink( sar->RecordList, TheLink ); start += record->Length; if(max_records > 0) max_records--; if(max_bytes > 0) { if( (vsi_l_offset)record->Length <= max_bytes ) max_bytes -= record->Length; else { CPLDebug( "SAR_CEOS", "Partial record found. %d > " CPL_FRMT_GUIB, record->Length, max_bytes ); max_bytes = 0; } } } CPLFree(temp_body); return CE_None; } /************************************************************************/ /* GDALRegister_SAR_CEOS() */ /************************************************************************/ void GDALRegister_SAR_CEOS() { if( GDALGetDriverByName( "SAR_CEOS" ) != NULL ) return; GDALDriver *poDriver = new GDALDriver(); poDriver->SetDescription( "SAR_CEOS" ); poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" ); poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "CEOS SAR Image" ); poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_various.html#SAR_CEOS" ); poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" ); poDriver->pfnOpen = SAR_CEOSDataset::Open; GetGDALDriverManager()->RegisterDriver( poDriver ); }