• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15885686134

25 Jun 2025 07:44PM UTC coverage: 71.084%. Remained the same
15885686134

push

github

rouault
gdal_priv.h: fix C++11 compatibility

573814 of 807237 relevant lines covered (71.08%)

250621.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

8.54
/frmts/tsx/tsxdataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:     TerraSAR-X XML Product Support
4
 * Purpose:     Support for TerraSAR-X XML Metadata files
5
 * Author:      Philippe Vachon <philippe@cowpig.ca>
6
 * Description: This driver adds support for reading metadata and georef data
7
 *              associated with TerraSAR-X products.
8
 *
9
 ******************************************************************************
10
 * Copyright (c) 2007, Philippe Vachon <philippe@cowpig.ca>
11
 * Copyright (c) 2009-2012, Even Rouault <even dot rouault at spatialys.com>
12
 *
13
 * SPDX-License-Identifier: MIT
14
 ****************************************************************************/
15

16
#include "cpl_minixml.h"
17
#include "gdal_frmts.h"
18
#include "gdal_pam.h"
19
#include "ogr_spatialref.h"
20

21
#define MAX_GCPS 5000  // this should be more than enough ground control points
22

23
namespace gdal::TSX
24
{
25
enum ePolarization
26
{
27
    HH = 0,
28
    HV,
29
    VH,
30
    VV
31
};
32

33
enum eProductType
34
{
35
    eSSC = 0,
36
    eMGD,
37
    eEEC,
38
    eGEC,
39
    eUnknown
40
};
41
}  // namespace gdal::TSX
42

43
using namespace gdal::TSX;
44

45
/************************************************************************/
46
/* Helper Functions                                                     */
47
/************************************************************************/
48

49
/* GetFilePath: return a relative path to a file within an XML node.
50
 * Returns Null on failure
51
 */
52
static CPLString GetFilePath(CPLXMLNode *psXMLNode, const char **pszNodeType)
×
53
{
54
    const char *pszDirectory =
55
        CPLGetXMLValue(psXMLNode, "file.location.path", "");
×
56
    const char *pszFilename =
57
        CPLGetXMLValue(psXMLNode, "file.location.filename", "");
×
58
    *pszNodeType = CPLGetXMLValue(psXMLNode, "type", " ");
×
59

60
    if (pszDirectory == nullptr || pszFilename == nullptr)
×
61
    {
62
        return "";
×
63
    }
64

65
    return CPLString(pszDirectory) + '/' + pszFilename;
×
66
}
67

68
/************************************************************************/
69
/* ==================================================================== */
70
/*                                TSXDataset                                 */
71
/* ==================================================================== */
72
/************************************************************************/
73

74
class TSXDataset final : public GDALPamDataset
75
{
76
    int nGCPCount;
77
    GDAL_GCP *pasGCPList;
78

79
    OGRSpatialReference m_oGCPSRS{};
80

81
    OGRSpatialReference m_oSRS{};
82
    GDALGeoTransform m_gt{};
83
    bool bHaveGeoTransform;
84

85
    eProductType nProduct;
86

87
  public:
88
    TSXDataset();
89
    virtual ~TSXDataset();
90

91
    virtual int GetGCPCount() override;
92
    const OGRSpatialReference *GetGCPSpatialRef() const override;
93
    virtual const GDAL_GCP *GetGCPs() override;
94

95
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
96
    const OGRSpatialReference *GetSpatialRef() const override;
97

98
    static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
99
    static int Identify(GDALOpenInfo *poOpenInfo);
100

101
  private:
102
    bool getGCPsFromGEOREF_XML(char *pszGeorefFilename);
103
};
104

105
/************************************************************************/
106
/* ==================================================================== */
107
/*                                TSXRasterBand                           */
108
/* ==================================================================== */
109
/************************************************************************/
110

111
class TSXRasterBand final : public GDALPamRasterBand
112
{
113
    GDALDataset *poBand;
114
    ePolarization ePol;
115

116
  public:
117
    TSXRasterBand(TSXDataset *poDSIn, GDALDataType eDataType,
118
                  ePolarization ePol, GDALDataset *poBand);
119
    virtual ~TSXRasterBand();
120

121
    virtual CPLErr IReadBlock(int nBlockXOff, int nBlockYOff,
122
                              void *pImage) override;
123

124
    static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
125
};
126

127
/************************************************************************/
128
/*                            TSXRasterBand                             */
129
/************************************************************************/
130

131
TSXRasterBand::TSXRasterBand(TSXDataset *poDSIn, GDALDataType eDataTypeIn,
×
132
                             ePolarization ePolIn, GDALDataset *poBandIn)
×
133
    : poBand(poBandIn), ePol(ePolIn)
×
134
{
135
    poDS = poDSIn;
×
136
    eDataType = eDataTypeIn;
×
137

138
    switch (ePol)
×
139
    {
140
        case HH:
×
141
            SetMetadataItem("POLARIMETRIC_INTERP", "HH");
×
142
            break;
×
143
        case HV:
×
144
            SetMetadataItem("POLARIMETRIC_INTERP", "HV");
×
145
            break;
×
146
        case VH:
×
147
            SetMetadataItem("POLARIMETRIC_INTERP", "VH");
×
148
            break;
×
149
        case VV:
×
150
            SetMetadataItem("POLARIMETRIC_INTERP", "VV");
×
151
            break;
×
152
    }
153

154
    /* now setup the actual raster reader */
155
    GDALRasterBand *poSrcBand = poBandIn->GetRasterBand(1);
×
156
    poSrcBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
×
157
}
×
158

159
/************************************************************************/
160
/*                            TSXRasterBand()                           */
161
/************************************************************************/
162

163
TSXRasterBand::~TSXRasterBand()
×
164
{
165
    if (poBand != nullptr)
×
166
        GDALClose(reinterpret_cast<GDALRasterBandH>(poBand));
×
167
}
×
168

169
/************************************************************************/
170
/*                             IReadBlock()                             */
171
/************************************************************************/
172

173
CPLErr TSXRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
×
174
{
175
    int nRequestYSize;
176

177
    /* Check if the last strip is partial so we can avoid over-requesting */
178
    if ((nBlockYOff + 1) * nBlockYSize > nRasterYSize)
×
179
    {
180
        nRequestYSize = nRasterYSize - nBlockYOff * nBlockYSize;
×
181
        memset(pImage, 0,
×
182
               static_cast<size_t>(GDALGetDataTypeSizeBytes(eDataType)) *
×
183
                   nBlockXSize * nBlockYSize);
×
184
    }
185
    else
186
    {
187
        nRequestYSize = nBlockYSize;
×
188
    }
189

190
    /* Read Complex Data */
191
    if (eDataType == GDT_CInt16)
×
192
    {
193
        return poBand->RasterIO(
×
194
            GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
×
195
            nBlockXSize, nRequestYSize, pImage, nBlockXSize, nRequestYSize,
196
            GDT_CInt16, 1, nullptr, 4, nBlockXSize * 4, 0, nullptr);
×
197
    }
198

199
    // Detected Product
200
    return poBand->RasterIO(
×
201
        GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
×
202
        nBlockXSize, nRequestYSize, pImage, nBlockXSize, nRequestYSize,
203
        GDT_UInt16, 1, nullptr, 2, nBlockXSize * 2, 0, nullptr);
×
204
}
205

206
/************************************************************************/
207
/* ==================================================================== */
208
/*                                TSXDataset                                */
209
/* ==================================================================== */
210
/************************************************************************/
211

212
/************************************************************************/
213
/*                             TSXDataset()                             */
214
/************************************************************************/
215

216
TSXDataset::TSXDataset()
×
217
    : nGCPCount(0), pasGCPList(nullptr), bHaveGeoTransform(false),
218
      nProduct(eUnknown)
×
219
{
220
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
×
221
    m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
×
222
}
×
223

224
/************************************************************************/
225
/*                            ~TSXDataset()                             */
226
/************************************************************************/
227

228
TSXDataset::~TSXDataset()
×
229
{
230
    FlushCache(true);
×
231

232
    if (nGCPCount > 0)
×
233
    {
234
        GDALDeinitGCPs(nGCPCount, pasGCPList);
×
235
        CPLFree(pasGCPList);
×
236
    }
237
}
×
238

239
/************************************************************************/
240
/*                              Identify()                              */
241
/************************************************************************/
242

243
int TSXDataset::Identify(GDALOpenInfo *poOpenInfo)
58,260✔
244
{
245
    if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 260)
58,260✔
246
    {
247
        if (poOpenInfo->bIsDirectory)
54,547✔
248
        {
249
            const CPLString osFilename = CPLFormCIFilenameSafe(
×
250
                poOpenInfo->pszFilename,
612✔
251
                CPLGetFilename(poOpenInfo->pszFilename), "xml");
1,224✔
252

253
            /* Check if the filename contains TSX1_SAR (TerraSAR-X) or TDX1_SAR
254
             * (TanDEM-X) or PAZ1_SAR (PAZ) */
255
            if (!(STARTS_WITH_CI(CPLGetBasenameSafe(osFilename).c_str(),
1,836✔
256
                                 "TSX1_SAR") ||
1,224✔
257
                  STARTS_WITH_CI(CPLGetBasenameSafe(osFilename).c_str(),
1,224✔
258
                                 "TDX1_SAR") ||
259
                  STARTS_WITH_CI(CPLGetBasenameSafe(osFilename).c_str(),
1,224✔
260
                                 "PAZ1_SAR")))
261
                return 0;
612✔
262

263
            VSIStatBufL sStat;
264
            if (VSIStatL(osFilename, &sStat) == 0)
×
265
                return 1;
×
266
        }
267

268
        return 0;
53,935✔
269
    }
270

271
    /* Check if the filename contains TSX1_SAR (TerraSAR-X) or TDX1_SAR
272
     * (TanDEM-X) or PAZ1_SAR (PAZ) */
273
    if (!(STARTS_WITH_CI(CPLGetBasenameSafe(poOpenInfo->pszFilename).c_str(),
11,139✔
274
                         "TSX1_SAR") ||
7,426✔
275
          STARTS_WITH_CI(CPLGetBasenameSafe(poOpenInfo->pszFilename).c_str(),
7,426✔
276
                         "TDX1_SAR") ||
277
          STARTS_WITH_CI(CPLGetBasenameSafe(poOpenInfo->pszFilename).c_str(),
7,426✔
278
                         "PAZ1_SAR")))
279
        return 0;
3,713✔
280

281
    /* finally look for the <level1Product tag */
282
    if (!STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
×
283
                        "<level1Product"))
284
        return 0;
×
285

286
    return 1;
×
287
}
288

289
/************************************************************************/
290
/*                                getGCPsFromGEOREF_XML()               */
291
/*Reads georeferencing information from the TerraSAR-X GEOREF.XML file    */
292
/*and writes the information to the dataset's gcp list and projection     */
293
/*string.                                                                */
294
/*Returns true on success.                                                */
295
/************************************************************************/
296
bool TSXDataset::getGCPsFromGEOREF_XML(char *pszGeorefFilename)
×
297
{
298
    // open GEOREF.xml
299
    CPLXMLNode *psGeorefData = CPLParseXMLFile(pszGeorefFilename);
×
300
    if (psGeorefData == nullptr)
×
301
        return false;
×
302

303
    // get the ellipsoid and semi-major, semi-minor axes
304
    OGRSpatialReference osr;
×
305
    CPLXMLNode *psSphere =
306
        CPLGetXMLNode(psGeorefData, "=geoReference.referenceFrames.sphere");
×
307
    if (psSphere != nullptr)
×
308
    {
309
        const char *pszEllipsoidName =
310
            CPLGetXMLValue(psSphere, "ellipsoidID", "");
×
311
        const double minor_axis =
312
            CPLAtof(CPLGetXMLValue(psSphere, "semiMinorAxis", "0.0"));
×
313
        const double major_axis =
314
            CPLAtof(CPLGetXMLValue(psSphere, "semiMajorAxis", "0.0"));
×
315
        // save datum parameters to the spatial reference
316
        if (EQUAL(pszEllipsoidName, "") || minor_axis == 0.0 ||
×
317
            major_axis == 0.0)
318
        {
319
            CPLError(CE_Warning, CPLE_AppDefined,
×
320
                     "Warning- incomplete"
321
                     " ellipsoid information.  Using wgs-84 parameters.\n");
322
            osr.SetWellKnownGeogCS("WGS84");
×
323
        }
324
        else if (EQUAL(pszEllipsoidName, "WGS84"))
×
325
        {
326
            osr.SetWellKnownGeogCS("WGS84");
×
327
        }
328
        else
329
        {
330
            const double inv_flattening =
×
331
                major_axis / (major_axis - minor_axis);
×
332
            osr.SetGeogCS("", "", pszEllipsoidName, major_axis, inv_flattening);
×
333
        }
334
    }
335

336
    // get gcps
337
    CPLXMLNode *psGeolocationGrid =
338
        CPLGetXMLNode(psGeorefData, "=geoReference.geolocationGrid");
×
339
    if (psGeolocationGrid == nullptr)
×
340
    {
341
        CPLDestroyXMLNode(psGeorefData);
×
342
        return false;
×
343
    }
344
    nGCPCount = atoi(
×
345
        CPLGetXMLValue(psGeolocationGrid, "numberOfGridPoints.total", "0"));
346
    // count the gcps if the given count value is invalid
347
    CPLXMLNode *psNode = nullptr;
×
348
    if (nGCPCount <= 0)
×
349
    {
350
        for (psNode = psGeolocationGrid->psChild; psNode != nullptr;
×
351
             psNode = psNode->psNext)
×
352
            if (EQUAL(psNode->pszValue, "gridPoint"))
×
353
                nGCPCount++;
×
354
    }
355
    // if there are no gcps, fail
356
    if (nGCPCount <= 0)
×
357
    {
358
        CPLDestroyXMLNode(psGeorefData);
×
359
        return false;
×
360
    }
361

362
    // put some reasonable limits of the number of gcps
363
    if (nGCPCount > MAX_GCPS)
×
364
        nGCPCount = MAX_GCPS;
×
365
    // allocate memory for the gcps
366
    pasGCPList =
×
367
        reinterpret_cast<GDAL_GCP *>(CPLCalloc(sizeof(GDAL_GCP), nGCPCount));
×
368

369
    // loop through all gcps and set info
370

371
    // save the number allocated to ensure it does not run off the end of the
372
    // array
373
    const int gcps_allocated = nGCPCount;
×
374
    nGCPCount = 0;  // reset to zero and count
×
375
    // do a check on the grid point to make sure it has lat,long row, and column
376
    // it seems that only SSC products contain row, col - how to map lat long
377
    // otherwise?? for now fail if row and col are not present - just check the
378
    // first and assume the rest are the same
379
    for (psNode = psGeolocationGrid->psChild; psNode != nullptr;
×
380
         psNode = psNode->psNext)
×
381
    {
382
        if (!EQUAL(psNode->pszValue, "gridPoint"))
×
383
            continue;
×
384

385
        if (!strcmp(CPLGetXMLValue(psNode, "col", "error"), "error") ||
×
386
            !strcmp(CPLGetXMLValue(psNode, "row", "error"), "error") ||
×
387
            !strcmp(CPLGetXMLValue(psNode, "lon", "error"), "error") ||
×
388
            !strcmp(CPLGetXMLValue(psNode, "lat", "error"), "error"))
×
389
        {
390
            CPLDestroyXMLNode(psGeorefData);
×
391
            return false;
×
392
        }
393
    }
394
    for (psNode = psGeolocationGrid->psChild; psNode != nullptr;
×
395
         psNode = psNode->psNext)
×
396
    {
397
        // break out if the end of the array has been reached
398
        if (nGCPCount >= gcps_allocated)
×
399
        {
400
            CPLError(CE_Warning, CPLE_AppDefined,
×
401
                     "GDAL TSX driver: Truncating the number of GCPs.");
402
            break;
×
403
        }
404

405
        GDAL_GCP *psGCP = pasGCPList + nGCPCount;
×
406

407
        if (!EQUAL(psNode->pszValue, "gridPoint"))
×
408
            continue;
×
409

410
        nGCPCount++;
×
411

412
        char szID[32];
413
        snprintf(szID, sizeof(szID), "%d", nGCPCount);
×
414
        psGCP->pszId = CPLStrdup(szID);
×
415
        psGCP->pszInfo = CPLStrdup("");
×
416
        psGCP->dfGCPPixel = CPLAtof(CPLGetXMLValue(psNode, "col", "0"));
×
417
        psGCP->dfGCPLine = CPLAtof(CPLGetXMLValue(psNode, "row", "0"));
×
418
        psGCP->dfGCPX = CPLAtof(CPLGetXMLValue(psNode, "lon", ""));
×
419
        psGCP->dfGCPY = CPLAtof(CPLGetXMLValue(psNode, "lat", ""));
×
420
        // looks like height is in meters - should it be converted so xyz are
421
        // all on the same scale??
422
        psGCP->dfGCPZ = 0;
×
423
        // CPLAtof(CPLGetXMLValue(psNode,"height",""));
424
    }
425

426
    m_oGCPSRS = std::move(osr);
×
427

428
    CPLDestroyXMLNode(psGeorefData);
×
429

430
    return true;
×
431
}
432

433
/************************************************************************/
434
/*                                Open()                                */
435
/************************************************************************/
436

437
GDALDataset *TSXDataset::Open(GDALOpenInfo *poOpenInfo)
×
438
{
439
    /* -------------------------------------------------------------------- */
440
    /*      Is this a TerraSAR-X product file?                              */
441
    /* -------------------------------------------------------------------- */
442
    if (!TSXDataset::Identify(poOpenInfo))
×
443
    {
444
        return nullptr; /* nope */
×
445
    }
446

447
    /* -------------------------------------------------------------------- */
448
    /*      Confirm the requested access is supported.                      */
449
    /* -------------------------------------------------------------------- */
450
    if (poOpenInfo->eAccess == GA_Update)
×
451
    {
452
        ReportUpdateNotSupportedByDriver("TSX");
×
453
        return nullptr;
×
454
    }
455

456
    CPLString osFilename;
×
457

458
    if (poOpenInfo->bIsDirectory)
×
459
    {
460
        osFilename = CPLFormCIFilenameSafe(
×
461
            poOpenInfo->pszFilename, CPLGetFilename(poOpenInfo->pszFilename),
×
462
            "xml");
×
463
    }
464
    else
465
        osFilename = poOpenInfo->pszFilename;
×
466

467
    /* Ingest the XML */
468
    CPLXMLNode *psData = CPLParseXMLFile(osFilename);
×
469
    if (psData == nullptr)
×
470
        return nullptr;
×
471

472
    /* find the product components */
473
    CPLXMLNode *psComponents =
474
        CPLGetXMLNode(psData, "=level1Product.productComponents");
×
475
    if (psComponents == nullptr)
×
476
    {
477
        CPLError(CE_Failure, CPLE_OpenFailed,
×
478
                 "Unable to find <productComponents> tag in file.\n");
479
        CPLDestroyXMLNode(psData);
×
480
        return nullptr;
×
481
    }
482

483
    /* find the product info tag */
484
    CPLXMLNode *psProductInfo =
485
        CPLGetXMLNode(psData, "=level1Product.productInfo");
×
486
    if (psProductInfo == nullptr)
×
487
    {
488
        CPLError(CE_Failure, CPLE_OpenFailed,
×
489
                 "Unable to find <productInfo> tag in file.\n");
490
        CPLDestroyXMLNode(psData);
×
491
        return nullptr;
×
492
    }
493

494
    /* -------------------------------------------------------------------- */
495
    /*      Create the dataset.                                             */
496
    /* -------------------------------------------------------------------- */
497

498
    TSXDataset *poDS = new TSXDataset();
×
499

500
    /* -------------------------------------------------------------------- */
501
    /*      Read in product info.                                           */
502
    /* -------------------------------------------------------------------- */
503

504
    poDS->SetMetadataItem(
×
505
        "SCENE_CENTRE_TIME",
506
        CPLGetXMLValue(psProductInfo,
507
                       "sceneInfo.sceneCenterCoord.azimuthTimeUTC", "unknown"));
×
508
    poDS->SetMetadataItem("OPERATIONAL_MODE",
×
509
                          CPLGetXMLValue(psProductInfo,
510
                                         "generationInfo.groundOperationsType",
511
                                         "unknown"));
×
512
    poDS->SetMetadataItem(
×
513
        "ORBIT_CYCLE",
514
        CPLGetXMLValue(psProductInfo, "missionInfo.orbitCycle", "unknown"));
×
515
    poDS->SetMetadataItem(
×
516
        "ABSOLUTE_ORBIT",
517
        CPLGetXMLValue(psProductInfo, "missionInfo.absOrbit", "unknown"));
×
518
    poDS->SetMetadataItem(
×
519
        "ORBIT_DIRECTION",
520
        CPLGetXMLValue(psProductInfo, "missionInfo.orbitDirection", "unknown"));
×
521
    poDS->SetMetadataItem("IMAGING_MODE",
×
522
                          CPLGetXMLValue(psProductInfo,
523
                                         "acquisitionInfo.imagingMode",
524
                                         "unknown"));
×
525
    poDS->SetMetadataItem("PRODUCT_VARIANT",
×
526
                          CPLGetXMLValue(psProductInfo,
527
                                         "productVariantInfo.productVariant",
528
                                         "unknown"));
×
529
    char *pszDataType = CPLStrdup(CPLGetXMLValue(
×
530
        psProductInfo, "imageDataInfo.imageDataType", "unknown"));
531
    poDS->SetMetadataItem("IMAGE_TYPE", pszDataType);
×
532

533
    /* Get raster information */
534
    int nRows = atoi(CPLGetXMLValue(
×
535
        psProductInfo, "imageDataInfo.imageRaster.numberOfRows", ""));
536
    int nCols = atoi(CPLGetXMLValue(
×
537
        psProductInfo, "imageDataInfo.imageRaster.numberOfColumns", ""));
538

539
    poDS->nRasterXSize = nCols;
×
540
    poDS->nRasterYSize = nRows;
×
541

542
    poDS->SetMetadataItem("ROW_SPACING",
×
543
                          CPLGetXMLValue(psProductInfo,
544
                                         "imageDataInfo.imageRaster.rowSpacing",
545
                                         "unknown"));
×
546
    poDS->SetMetadataItem(
×
547
        "COL_SPACING",
548
        CPLGetXMLValue(psProductInfo, "imageDataInfo.imageRaster.columnSpacing",
549
                       "unknown"));
×
550
    poDS->SetMetadataItem(
×
551
        "COL_SPACING_UNITS",
552
        CPLGetXMLValue(psProductInfo,
553
                       "imageDataInfo.imageRaster.columnSpacing.units",
554
                       "unknown"));
×
555

556
    /* Get equivalent number of looks */
557
    poDS->SetMetadataItem(
×
558
        "AZIMUTH_LOOKS",
559
        CPLGetXMLValue(psProductInfo, "imageDataInfo.imageRaster.azimuthLooks",
560
                       "unknown"));
×
561
    poDS->SetMetadataItem("RANGE_LOOKS",
×
562
                          CPLGetXMLValue(psProductInfo,
563
                                         "imageDataInfo.imageRaster.rangeLooks",
564
                                         "unknown"));
×
565

566
    const char *pszProductVariant = CPLGetXMLValue(
×
567
        psProductInfo, "productVariantInfo.productVariant", "unknown");
568

569
    poDS->SetMetadataItem("PRODUCT_VARIANT", pszProductVariant);
×
570

571
    /* Determine what product variant this is */
572
    if (STARTS_WITH_CI(pszProductVariant, "SSC"))
×
573
        poDS->nProduct = eSSC;
×
574
    else if (STARTS_WITH_CI(pszProductVariant, "MGD"))
×
575
        poDS->nProduct = eMGD;
×
576
    else if (STARTS_WITH_CI(pszProductVariant, "EEC"))
×
577
        poDS->nProduct = eEEC;
×
578
    else if (STARTS_WITH_CI(pszProductVariant, "GEC"))
×
579
        poDS->nProduct = eGEC;
×
580
    else
581
        poDS->nProduct = eUnknown;
×
582

583
    /* Start reading in the product components */
584
    char *pszGeorefFile = nullptr;
×
585
    CPLErr geoTransformErr = CE_Failure;
×
586
    for (CPLXMLNode *psComponent = psComponents->psChild;
×
587
         psComponent != nullptr; psComponent = psComponent->psNext)
×
588
    {
589
        const char *pszType = nullptr;
×
590
        const std::string osPath =
591
            CPLFormFilenameSafe(CPLGetDirnameSafe(osFilename).c_str(),
×
592
                                GetFilePath(psComponent, &pszType).c_str(), "");
×
593
        const char *pszPolLayer = CPLGetXMLValue(psComponent, "polLayer", " ");
×
594

595
        if (!STARTS_WITH_CI(pszType, " "))
×
596
        {
597
            if (STARTS_WITH_CI(pszType, "MAPPING_GRID"))
×
598
            {
599
                /* the mapping grid... save as a metadata item this path */
600
                poDS->SetMetadataItem("MAPPING_GRID", osPath.c_str());
×
601
            }
602
            else if (STARTS_WITH_CI(pszType, "GEOREF"))
×
603
            {
604
                /* save the path to the georef data for later use */
605
                CPLFree(pszGeorefFile);
×
606
                pszGeorefFile = CPLStrdup(osPath.c_str());
×
607
            }
608
        }
609
        else if (!STARTS_WITH_CI(pszPolLayer, " ") &&
×
610
                 STARTS_WITH_CI(psComponent->pszValue, "imageData"))
×
611
        {
612
            /* determine the polarization of this band */
613
            ePolarization ePol;
614
            if (STARTS_WITH_CI(pszPolLayer, "HH"))
×
615
            {
616
                ePol = HH;
×
617
            }
618
            else if (STARTS_WITH_CI(pszPolLayer, "HV"))
×
619
            {
620
                ePol = HV;
×
621
            }
622
            else if (STARTS_WITH_CI(pszPolLayer, "VH"))
×
623
            {
624
                ePol = VH;
×
625
            }
626
            else
627
            {
628
                ePol = VV;
×
629
            }
630

631
            GDALDataType eDataType = STARTS_WITH_CI(pszDataType, "COMPLEX")
×
632
                                         ? GDT_CInt16
×
633
                                         : GDT_UInt16;
634

635
            /* try opening the file that represents that band */
636
            GDALDataset *poBandData =
637
                GDALDataset::FromHandle(GDALOpen(osPath.c_str(), GA_ReadOnly));
×
638
            if (poBandData != nullptr)
×
639
            {
640
                TSXRasterBand *poBand =
641
                    new TSXRasterBand(poDS, eDataType, ePol, poBandData);
×
642
                poDS->SetBand(poDS->GetRasterCount() + 1, poBand);
×
643

644
                // copy georeferencing info from the band
645
                // need error checking??
646
                // it will just save the info from the last band
647
                const auto poSrcSRS = poBandData->GetSpatialRef();
×
648
                if (poSrcSRS)
×
649
                    poDS->m_oSRS = *poSrcSRS;
×
650

651
                geoTransformErr = poBandData->GetGeoTransform(poDS->m_gt);
×
652
            }
653
        }
654
    }
655

656
    // now check if there is a geotransform
657
    if (!poDS->m_oSRS.IsEmpty() && geoTransformErr == CE_None)
×
658
    {
659
        poDS->bHaveGeoTransform = TRUE;
×
660
    }
661
    else
662
    {
663
        poDS->bHaveGeoTransform = FALSE;
×
664
        poDS->m_oSRS.Clear();
×
665
        poDS->m_gt = GDALGeoTransform();
×
666
    }
667

668
    CPLFree(pszDataType);
×
669

670
    /* -------------------------------------------------------------------- */
671
    /*      Check and set matrix representation.                            */
672
    /* -------------------------------------------------------------------- */
673

674
    if (poDS->GetRasterCount() == 4)
×
675
    {
676
        poDS->SetMetadataItem("MATRIX_REPRESENTATION", "SCATTERING");
×
677
    }
678

679
    /* -------------------------------------------------------------------- */
680
    /*      Read the four corners and centre GCPs in                        */
681
    /* -------------------------------------------------------------------- */
682

683
    CPLXMLNode *psSceneInfo =
684
        CPLGetXMLNode(psData, "=level1Product.productInfo.sceneInfo");
×
685
    if (psSceneInfo != nullptr)
×
686
    {
687
        /* extract the GCPs from the provided file */
688
        bool success = false;
×
689
        if (pszGeorefFile != nullptr)
×
690
            success = poDS->getGCPsFromGEOREF_XML(pszGeorefFile);
×
691

692
        // if the gcp's cannot be extracted from the georef file, try to get the
693
        // corner coordinates for now just SSC because the others don't have
694
        // refColumn and refRow
695
        if (!success && poDS->nProduct == eSSC)
×
696
        {
697
            int nGCP = 0;
×
698
            double dfAvgHeight = CPLAtof(
×
699
                CPLGetXMLValue(psSceneInfo, "sceneAverageHeight", "0.0"));
700

701
            // count and allocate gcps - there should be five - 4 corners and a
702
            // centre
703
            poDS->nGCPCount = 0;
×
704
            CPLXMLNode *psNode = psSceneInfo->psChild;
×
705
            for (; psNode != nullptr; psNode = psNode->psNext)
×
706
            {
707
                if (!EQUAL(psNode->pszValue, "sceneCenterCoord") &&
×
708
                    !EQUAL(psNode->pszValue, "sceneCornerCoord"))
×
709
                    continue;
×
710

711
                poDS->nGCPCount++;
×
712
            }
713
            if (poDS->nGCPCount > 0)
×
714
            {
715
                poDS->pasGCPList =
×
716
                    (GDAL_GCP *)CPLCalloc(sizeof(GDAL_GCP), poDS->nGCPCount);
×
717

718
                /* iterate over GCPs */
719
                for (psNode = psSceneInfo->psChild; psNode != nullptr;
×
720
                     psNode = psNode->psNext)
×
721
                {
722
                    GDAL_GCP *psGCP = poDS->pasGCPList + nGCP;
×
723

724
                    if (!EQUAL(psNode->pszValue, "sceneCenterCoord") &&
×
725
                        !EQUAL(psNode->pszValue, "sceneCornerCoord"))
×
726
                        continue;
×
727

728
                    psGCP->dfGCPPixel =
×
729
                        CPLAtof(CPLGetXMLValue(psNode, "refColumn", "0.0"));
×
730
                    psGCP->dfGCPLine =
×
731
                        CPLAtof(CPLGetXMLValue(psNode, "refRow", "0.0"));
×
732
                    psGCP->dfGCPX =
×
733
                        CPLAtof(CPLGetXMLValue(psNode, "lon", "0.0"));
×
734
                    psGCP->dfGCPY =
×
735
                        CPLAtof(CPLGetXMLValue(psNode, "lat", "0.0"));
×
736
                    psGCP->dfGCPZ = dfAvgHeight;
×
737
                    psGCP->pszId = CPLStrdup(CPLSPrintf("%d", nGCP));
×
738
                    psGCP->pszInfo = CPLStrdup("");
×
739

740
                    nGCP++;
×
741
                }
742

743
                // set the projection string - the fields are lat/long - seems
744
                // to be WGS84 datum
745
                poDS->m_oGCPSRS.SetWellKnownGeogCS("WGS84");
×
746
            }
747
        }
748

749
        // gcps override geotransform - does it make sense to have both??
750
        if (poDS->nGCPCount > 0)
×
751
        {
752
            poDS->bHaveGeoTransform = FALSE;
×
753
            poDS->m_oSRS.Clear();
×
754
            poDS->m_gt = GDALGeoTransform();
×
755
        }
756
    }
757
    else
758
    {
759
        CPLError(CE_Warning, CPLE_AppDefined,
×
760
                 "Unable to find sceneInfo tag in XML document. "
761
                 "Proceeding with caution.");
762
    }
763

764
    CPLFree(pszGeorefFile);
×
765

766
    /* -------------------------------------------------------------------- */
767
    /*      Initialize any PAM information.                                 */
768
    /* -------------------------------------------------------------------- */
769
    poDS->SetDescription(poOpenInfo->pszFilename);
×
770
    poDS->TryLoadXML();
×
771

772
    /* -------------------------------------------------------------------- */
773
    /*      Check for overviews.                                            */
774
    /* -------------------------------------------------------------------- */
775
    poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
×
776

777
    CPLDestroyXMLNode(psData);
×
778

779
    return poDS;
×
780
}
781

782
/************************************************************************/
783
/*                            GetGCPCount()                             */
784
/************************************************************************/
785

786
int TSXDataset::GetGCPCount()
×
787
{
788
    return nGCPCount;
×
789
}
790

791
/************************************************************************/
792
/*                          GetGCPSpatialRef()                          */
793
/************************************************************************/
794

795
const OGRSpatialReference *TSXDataset::GetGCPSpatialRef() const
×
796
{
797
    return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
×
798
}
799

800
/************************************************************************/
801
/*                               GetGCPs()                              */
802
/************************************************************************/
803

804
const GDAL_GCP *TSXDataset::GetGCPs()
×
805
{
806
    return pasGCPList;
×
807
}
808

809
/************************************************************************/
810
/*                          GetSpatialRef()                             */
811
/************************************************************************/
812

813
const OGRSpatialReference *TSXDataset::GetSpatialRef() const
×
814

815
{
816
    return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
×
817
}
818

819
/************************************************************************/
820
/*                               GetGeotransform()                      */
821
/************************************************************************/
822
CPLErr TSXDataset::GetGeoTransform(GDALGeoTransform &gt) const
×
823
{
824
    gt = m_gt;
×
825

826
    if (bHaveGeoTransform)
×
827
        return CE_None;
×
828

829
    return CE_Failure;
×
830
}
831

832
/************************************************************************/
833
/*                         GDALRegister_TSX()                           */
834
/************************************************************************/
835

836
void GDALRegister_TSX()
1,911✔
837
{
838
    if (GDALGetDriverByName("TSX") != nullptr)
1,911✔
839
        return;
282✔
840

841
    GDALDriver *poDriver = new GDALDriver();
1,629✔
842

843
    poDriver->SetDescription("TSX");
1,629✔
844
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1,629✔
845
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "TerraSAR-X Product");
1,629✔
846
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/tsx.html");
1,629✔
847
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1,629✔
848

849
    poDriver->pfnOpen = TSXDataset::Open;
1,629✔
850
    poDriver->pfnIdentify = TSXDataset::Identify;
1,629✔
851

852
    GetGDALDriverManager()->RegisterDriver(poDriver);
1,629✔
853
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc