gdal/frmts/ceos2/sar_ceosdataset.cpp

2359 строки
84 KiB
C++

/******************************************************************************
*
* 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 spatialys.com>
*
* 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"
#include <algorithm>
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"},
/* Radarsat-1 ASF */
{"", "L", "D", "", "", "ext"},
/* end marker */
{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}};
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)
/* Leader from ASF has different identifiers */
#define LEADER_MAP_PROJ_RECORD_ASF_TC QuadToTC(10, 20, 18, 20)
#define LEADER_DATASET_SUMMARY_ASF_TC QuadToTC(10, 10, 18, 20)
#define LEADER_FACILITY_ASF_TC QuadToTC(90, 210, 18, 61)
/* 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 final : public GDALPamDataset
{
friend class SAR_CEOSRasterBand;
friend class CCPRasterBand;
friend class PALSARRasterBand;
CeosSARVolume_t sVolume;
VSILFILE *fpImage;
char **papszTempMD;
OGRSpatialReference m_oSRS{};
int nGCPCount;
GDAL_GCP *pasGCPList;
void ScanForGCPs();
void ScanForMetadata();
int ScanForMapProjection();
char **papszExtraFiles;
public:
SAR_CEOSDataset();
~SAR_CEOSDataset() override;
int GetGCPCount() override;
const OGRSpatialReference *GetGCPSpatialRef() const override;
const GDAL_GCP *GetGCPs() override;
char **GetMetadataDomainList() override;
char **GetMetadata(const char *pszDomain) override;
static GDALDataset *Open(GDALOpenInfo *);
virtual char **GetFileList(void) override;
};
/************************************************************************/
/* ==================================================================== */
/* CCPRasterBand */
/* ==================================================================== */
/************************************************************************/
class CCPRasterBand final : public GDALPamRasterBand
{
friend class SAR_CEOSDataset;
public:
CCPRasterBand(SAR_CEOSDataset *, int, GDALDataType);
CPLErr IReadBlock(int, int, void *) override;
};
/************************************************************************/
/* ==================================================================== */
/* PALSARRasterBand */
/* ==================================================================== */
/************************************************************************/
class PALSARRasterBand final : public GDALPamRasterBand
{
friend class SAR_CEOSDataset;
public:
PALSARRasterBand(SAR_CEOSDataset *, int);
CPLErr IReadBlock(int, int, void *) override;
};
/************************************************************************/
/* ==================================================================== */
/* SAR_CEOSRasterBand */
/* ==================================================================== */
/************************************************************************/
class SAR_CEOSRasterBand final : public GDALPamRasterBand
{
friend class SAR_CEOSDataset;
public:
SAR_CEOSRasterBand(SAR_CEOSDataset *, int, GDALDataType);
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,
nullptr, &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(nullptr), papszTempMD(nullptr), nGCPCount(0), pasGCPList(nullptr),
papszExtraFiles(nullptr)
{
m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
m_oSRS.importFromWkt(SRS_WKT_WGS84_LAT_LONG);
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 = nullptr;
}
/************************************************************************/
/* ~SAR_CEOSDataset() */
/************************************************************************/
SAR_CEOSDataset::~SAR_CEOSDataset()
{
FlushCache(true);
CSLDestroy(papszTempMD);
if (fpImage != nullptr)
CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
if (nGCPCount > 0)
{
GDALDeinitGCPs(nGCPCount, pasGCPList);
}
CPLFree(pasGCPList);
if (sVolume.RecordList)
{
for (Link_t *Links = sVolume.RecordList; Links != nullptr;
Links = Links->next)
{
if (Links->object)
{
DeleteCeosRecord((CeosRecord_t *)Links->object);
Links->object = nullptr;
}
}
DestroyList(sVolume.RecordList);
}
FreeRecipes();
CSLDestroy(papszExtraFiles);
}
/************************************************************************/
/* GetGCPCount() */
/************************************************************************/
int SAR_CEOSDataset::GetGCPCount()
{
return nGCPCount;
}
/************************************************************************/
/* GetGCPSpatialRef() */
/************************************************************************/
const OGRSpatialReference *SAR_CEOSDataset::GetGCPSpatialRef() const
{
if (nGCPCount > 0)
return &m_oSRS;
return nullptr;
}
/************************************************************************/
/* 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 == nullptr || !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 nullptr;
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 nullptr;
}
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 == nullptr)
return nullptr;
/* -------------------------------------------------------------------- */
/* 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(nullptr, "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 != nullptr)
{
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 == nullptr)
record =
FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_ASF_TC,
CEOS_LEADER_FILE, -1, -1);
if (record == nullptr)
record = FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_TC,
CEOS_TRAILER_FILE, -1, -1);
if (record == nullptr)
record =
FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_ERS2_TC,
CEOS_LEADER_FILE, -1, -1);
if (record != nullptr)
{
/* --------------------------------------------------------------------
*/
/* 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") != nullptr &&
!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);
/* --------------------------------------------------------------------
*/
/* Facility */
/* --------------------------------------------------------------------
*/
GetCeosField(record, 1047, "A16", szField);
szField[16] = '\0';
if (!STARTS_WITH_CI(szField, " "))
SetMetadataItem("CEOS_FACILITY", 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") != nullptr && record != nullptr)
{
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 == nullptr)
record =
FindCeosRecord(sVolume.RecordList, ERS_GENERAL_FACILITY_DATA_ALT_TC,
CEOS_LEADER_FILE, -1, -1);
if (record != nullptr)
{
GetCeosField(record, 13, "A64", szField);
szField[64] = '\0';
/* Avoid PCS records, which don't contain necessary info */
if (strstr(szField, "GENERAL") == nullptr)
record = nullptr;
}
if (record != nullptr)
{
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 == nullptr)
record = FindCeosRecord(sVolume.RecordList, RSAT_PROC_PARAM_TC,
CEOS_TRAILER_FILE, -1, -1);
if (record != nullptr)
{
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 != nullptr)
{
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 == nullptr)
record = FindCeosRecord(sVolume.RecordList,
LEADER_RADIOMETRIC_DATA_RECORD_TC,
CEOS_TRAILER_FILE, -1, -1);
if (record != nullptr)
{
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 != nullptr)
{
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 != nullptr)
{
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);
int gcp_ordering_mode = CEOS_STD_MAPREC_GCP_ORDER;
/* JERS from Japan */
if (record == nullptr)
record =
FindCeosRecord(sVolume.RecordList, LEADER_MAP_PROJ_RECORD_JERS_TC,
CEOS_LEADER_FILE, -1, -1);
if (record == nullptr)
{
record =
FindCeosRecord(sVolume.RecordList, LEADER_MAP_PROJ_RECORD_ASF_TC,
CEOS_LEADER_FILE, -1, -1);
gcp_ordering_mode = CEOS_ASF_MAPREC_GCP_ORDER;
}
if (record == nullptr)
{
record = FindCeosRecord(sVolume.RecordList, LEADER_FACILITY_ASF_TC,
CEOS_LEADER_FILE, -1, -1);
gcp_ordering_mode = CEOS_ASF_FACREC_GCP_ORDER;
}
if (record == nullptr)
return FALSE;
char szField[100];
memset(szField, 0, 17);
GetCeosField(record, 29, "A16", szField);
int GCPFieldSize = 16;
int GCPOffset = 1073;
if (!STARTS_WITH_CI(szField, "Slant Range") &&
!STARTS_WITH_CI(szField, "Ground Range") &&
!STARTS_WITH_CI(szField, "GEOCODED"))
{
/* detect ASF map projection record */
GetCeosField(record, 1079, "A7", szField);
if (!STARTS_WITH_CI(szField, "Slant") &&
!STARTS_WITH_CI(szField, "Ground"))
{
return FALSE;
}
else
{
GCPFieldSize = 17;
GCPOffset = 157;
}
}
char FieldSize[4];
snprintf(FieldSize, sizeof(FieldSize), "A%d", GCPFieldSize);
GetCeosField(record, GCPOffset, FieldSize, 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);
CPLFree(pasGCPList[i].pszId);
pasGCPList[i].pszId = CPLStrdup(szId);
GetCeosField(record, GCPOffset + (GCPFieldSize * 2) * i, FieldSize,
szField);
pasGCPList[i].dfGCPY = CPLAtof(szField);
GetCeosField(record, GCPOffset + GCPFieldSize + (GCPFieldSize * 2) * i,
FieldSize, szField);
pasGCPList[i].dfGCPX = CPLAtof(szField);
pasGCPList[i].dfGCPZ = 0.0;
}
/* Map Projection Record has the order UL UR LR LL
ASF Facility Data Record has the order UL,LL,UR,LR
ASF Map Projection Record has the order LL, LR, UR, UL */
pasGCPList[0].dfGCPLine = 0.5;
pasGCPList[0].dfGCPPixel = 0.5;
switch (gcp_ordering_mode)
{
case CEOS_ASF_FACREC_GCP_ORDER:
pasGCPList[1].dfGCPLine = nRasterYSize - 0.5;
pasGCPList[1].dfGCPPixel = 0.5;
pasGCPList[2].dfGCPLine = 0.5;
pasGCPList[2].dfGCPPixel = nRasterXSize - 0.5;
pasGCPList[3].dfGCPLine = nRasterYSize - 0.5;
pasGCPList[3].dfGCPPixel = nRasterXSize - 0.5;
break;
case CEOS_STD_MAPREC_GCP_ORDER:
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;
break;
case CEOS_ASF_MAPREC_GCP_ORDER:
pasGCPList[0].dfGCPLine = nRasterYSize - 0.5;
pasGCPList[0].dfGCPPixel = 0.5;
pasGCPList[1].dfGCPLine = nRasterYSize - 0.5;
pasGCPList[1].dfGCPPixel = nRasterXSize - 0.5;
pasGCPList[2].dfGCPLine = 0.5;
pasGCPList[2].dfGCPPixel = nRasterXSize - 0.5;
pasGCPList[3].dfGCPLine = 0.5;
pasGCPList[3].dfGCPPixel = 0.5;
break;
}
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;
}
/* ASF L1 products do not have valid data
in the lat/long first/mid/last fields */
const char *pszValue = GetMetadataItem("CEOS_FACILITY");
if ((pszValue != nullptr) && (strncmp(pszValue, "ASF", 3) == 0))
{
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, nullptr,
&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)
{
CPLFree(pasGCPList);
pasGCPList = nullptr;
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 ||
poOpenInfo->fpL == nullptr)
return nullptr;
if ((poOpenInfo->pabyHeader[4] != 0x3f &&
poOpenInfo->pabyHeader[4] != 0x32) ||
poOpenInfo->pabyHeader[5] != 0xc0 ||
poOpenInfo->pabyHeader[6] != 0x12 || poOpenInfo->pabyHeader[7] != 0x12)
return nullptr;
// 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 nullptr;
/* -------------------------------------------------------------------- */
/* 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 nullptr;
}
/* -------------------------------------------------------------------- */
/* Create a corresponding GDALDataset. */
/* -------------------------------------------------------------------- */
auto poDS = cpl::make_unique<SAR_CEOSDataset>();
std::swap(poDS->fpImage, poOpenInfo->fpL);
CeosSARVolume_t *psVolume = &(poDS->sVolume);
InitCeosSARVolume(psVolume, 0);
/* -------------------------------------------------------------------- */
/* Try to read the current file as an imagery file. */
/* -------------------------------------------------------------------- */
psVolume->ImagryOptionsFile = TRUE;
if (ProcessData(poDS->fpImage, CEOS_IMAGRY_OPT_FILE, psVolume, 4,
VSI_L_OFFSET_MAX) != CE_None)
{
return nullptr;
}
/* -------------------------------------------------------------------- */
/* 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] != nullptr)
{
char *pszFilename = nullptr;
/* 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 != nullptr);
if (pszFilename == nullptr)
return nullptr;
/* try to open */
VSILFILE *process_fp = VSIFOpenL(pszFilename, "rb");
/* try upper case */
if (process_fp == nullptr)
{
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 != nullptr)
{
CPLDebug("CEOS", "Opened %s.\n", pszFilename);
poDS->papszExtraFiles =
CSLAddString(poDS->papszExtraFiles, 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)
{
CPLDebug("CEOS",
"Unable to extract CEOS image description\n"
"from %s.",
poOpenInfo->pszFilename);
return nullptr;
}
/* -------------------------------------------------------------------- */
/* 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);
return nullptr;
}
/* -------------------------------------------------------------------- */
/* Capture some information from the file that is of interest. */
/* -------------------------------------------------------------------- */
poDS->nRasterXSize = psImageDesc->PixelsPerLine +
psImageDesc->LeftBorderPixels +
psImageDesc->RightBorderPixels;
poDS->nRasterYSize = psImageDesc->Lines;
/* -------------------------------------------------------------------- */
/* 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.get(), 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.get(), 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.get(), poDS->nBands + 1, eType));
}
}
/* -------------------------------------------------------------------- */
/* Use raw services for well behaved files. */
/* -------------------------------------------------------------------- */
else
{
int StartData;
CalcCeosSARImageFilePosition(psVolume, 1, 1, nullptr, &StartData);
/*StartData += psImageDesc->ImageDataStart; */
int nLineSize, nLineSize2;
CalcCeosSARImageFilePosition(psVolume, 1, 1, nullptr, &nLineSize);
CalcCeosSARImageFilePosition(psVolume, 1, 2, nullptr, &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, nullptr,
&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, nullptr,
&nStartData);
nStartData += psImageDesc->ImageDataStart;
nPixelOffset = psImageDesc->BytesPerPixel;
nLineOffset = nLineSize * psImageDesc->NumChannels;
}
else if (psImageDesc->ChannelInterleaving == CEOS_IL_BAND)
{
CalcCeosSARImageFilePosition(psVolume, iBand + 1, 1, nullptr,
&nStartData);
nStartData += psImageDesc->ImageDataStart;
nPixelOffset = psImageDesc->BytesPerPixel;
nLineOffset = nLineSize;
}
else
{
CPLAssert(false);
return nullptr;
}
auto poBand = RawRasterBand::Create(
poDS.get(), poDS->nBands + 1, poDS->fpImage, nStartData,
nPixelOffset, nLineOffset, eType,
RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
RawRasterBand::OwnFP::NO);
if (!poBand)
return nullptr;
poDS->SetBand(poDS->nBands + 1, std::move(poBand));
}
}
/* -------------------------------------------------------------------- */
/* 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.get(), poOpenInfo->pszFilename);
return poDS.release();
}
/************************************************************************/
/* 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 = nullptr;
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 == nullptr)
{
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 == nullptr)
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") != nullptr)
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,
"drivers/raster/sar_ceos.html");
poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
poDriver->pfnOpen = SAR_CEOSDataset::Open;
GetGDALDriverManager()->RegisterDriver(poDriver);
}
/************************************************************************/
/* GetFileList() */
/************************************************************************/
char **SAR_CEOSDataset::GetFileList()
{
char **papszFileList = GDALPamDataset::GetFileList();
papszFileList = CSLInsertStrings(papszFileList, -1, papszExtraFiles);
return papszFileList;
}