Coverage Report

Created: 2025-11-15 08:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/raw/pauxdataset.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  PCI .aux Driver
4
 * Purpose:  Implementation of PAuxDataset
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1999, Frank Warmerdam
9
 * Copyright (c) 2008-2010, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_string.h"
15
#include "gdal_frmts.h"
16
#include "gdal_priv.h"
17
#include "ogr_spatialref.h"
18
#include "rawdataset.h"
19
20
#include <cmath>
21
22
/************************************************************************/
23
/* ==================================================================== */
24
/*                              PAuxDataset                             */
25
/* ==================================================================== */
26
/************************************************************************/
27
28
class PAuxRasterBand;
29
30
class PAuxDataset final : public RawDataset
31
{
32
    friend class PAuxRasterBand;
33
34
    VSILFILE *fpImage;  // Image data file.
35
36
    int nGCPCount;
37
    GDAL_GCP *pasGCPList;
38
    OGRSpatialReference m_oGCPSRS{};
39
40
    void ScanForGCPs();
41
    static OGRSpatialReference PCI2SRS(const char *pszGeosys,
42
                                       const char *pszProjParams);
43
44
    OGRSpatialReference m_oSRS{};
45
46
    CPL_DISALLOW_COPY_ASSIGN(PAuxDataset)
47
48
    CPLErr Close() override;
49
50
  public:
51
    PAuxDataset();
52
    ~PAuxDataset() override;
53
54
    // TODO(schwehr): Why are these public?
55
    char *pszAuxFilename;
56
    char **papszAuxLines;
57
58
    const OGRSpatialReference *GetSpatialRef() const override
59
0
    {
60
0
        return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
61
0
    }
62
63
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
64
65
    int GetGCPCount() override;
66
67
    const OGRSpatialReference *GetGCPSpatialRef() const override
68
0
    {
69
0
        return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
70
0
    }
71
72
    const GDAL_GCP *GetGCPs() override;
73
74
    char **GetFileList() override;
75
76
    static GDALDataset *Open(GDALOpenInfo *);
77
};
78
79
/************************************************************************/
80
/* ==================================================================== */
81
/*                           PAuxRasterBand                             */
82
/* ==================================================================== */
83
/************************************************************************/
84
85
class PAuxRasterBand final : public RawRasterBand
86
{
87
    CPL_DISALLOW_COPY_ASSIGN(PAuxRasterBand)
88
89
  public:
90
    PAuxRasterBand(GDALDataset *poDS, int nBand, VSILFILE *fpRaw,
91
                   vsi_l_offset nImgOffset, int nPixelOffset, int nLineOffset,
92
                   GDALDataType eDataType, int bNativeOrder);
93
94
    ~PAuxRasterBand() override;
95
96
    double GetNoDataValue(int *pbSuccess = nullptr) override;
97
98
    GDALColorTable *GetColorTable() override;
99
    GDALColorInterp GetColorInterpretation() override;
100
};
101
102
/************************************************************************/
103
/*                           PAuxRasterBand()                           */
104
/************************************************************************/
105
106
PAuxRasterBand::PAuxRasterBand(GDALDataset *poDSIn, int nBandIn,
107
                               VSILFILE *fpRawIn, vsi_l_offset nImgOffsetIn,
108
                               int nPixelOffsetIn, int nLineOffsetIn,
109
                               GDALDataType eDataTypeIn, int bNativeOrderIn)
110
0
    : RawRasterBand(poDSIn, nBandIn, fpRawIn, nImgOffsetIn, nPixelOffsetIn,
111
0
                    nLineOffsetIn, eDataTypeIn, bNativeOrderIn,
112
0
                    RawRasterBand::OwnFP::NO)
113
0
{
114
0
    PAuxDataset *poPDS = cpl::down_cast<PAuxDataset *>(poDS);
115
116
    /* -------------------------------------------------------------------- */
117
    /*      Does this channel have a description?                           */
118
    /* -------------------------------------------------------------------- */
119
0
    char szTarget[128] = {'\0'};
120
121
0
    snprintf(szTarget, sizeof(szTarget), "ChanDesc-%d", nBand);
122
0
    if (CSLFetchNameValue(poPDS->papszAuxLines, szTarget) != nullptr)
123
0
        GDALRasterBand::SetDescription(
124
0
            CSLFetchNameValue(poPDS->papszAuxLines, szTarget));
125
126
    /* -------------------------------------------------------------------- */
127
    /*      See if we have colors.  Currently we must have color zero,      */
128
    /*      but this should not really be a limitation.                     */
129
    /* -------------------------------------------------------------------- */
130
0
    snprintf(szTarget, sizeof(szTarget), "METADATA_IMG_%d_Class_%d_Color",
131
0
             nBand, 0);
132
0
    if (CSLFetchNameValue(poPDS->papszAuxLines, szTarget) != nullptr)
133
0
    {
134
0
        poCT = new GDALColorTable();
135
136
0
        for (int i = 0; i < 256; i++)
137
0
        {
138
0
            snprintf(szTarget, sizeof(szTarget),
139
0
                     "METADATA_IMG_%d_Class_%d_Color", nBand, i);
140
0
            const char *pszLine =
141
0
                CSLFetchNameValue(poPDS->papszAuxLines, szTarget);
142
0
            while (pszLine && *pszLine == ' ')
143
0
                pszLine++;
144
145
0
            int nRed = 0;
146
0
            int nGreen = 0;
147
0
            int nBlue = 0;
148
            // TODO(schwehr): Replace sscanf with something safe.
149
0
            if (pszLine != nullptr && STARTS_WITH_CI(pszLine, "(RGB:") &&
150
0
                sscanf(pszLine + 5, "%d %d %d", &nRed, &nGreen, &nBlue) == 3)
151
0
            {
152
0
                GDALColorEntry oColor = {static_cast<short>(nRed),
153
0
                                         static_cast<short>(nGreen),
154
0
                                         static_cast<short>(nBlue), 255};
155
156
0
                poCT->SetColorEntry(i, &oColor);
157
0
            }
158
0
        }
159
0
    }
160
0
}
161
162
/************************************************************************/
163
/*                          ~PAuxRasterBand()                           */
164
/************************************************************************/
165
166
PAuxRasterBand::~PAuxRasterBand()
167
168
0
{
169
0
}
170
171
/************************************************************************/
172
/*                           GetNoDataValue()                           */
173
/************************************************************************/
174
175
double PAuxRasterBand::GetNoDataValue(int *pbSuccess)
176
177
0
{
178
0
    char szTarget[128] = {'\0'};
179
0
    snprintf(szTarget, sizeof(szTarget), "METADATA_IMG_%d_NO_DATA_VALUE",
180
0
             nBand);
181
182
0
    PAuxDataset *poPDS = cpl::down_cast<PAuxDataset *>(poDS);
183
0
    const char *pszLine = CSLFetchNameValue(poPDS->papszAuxLines, szTarget);
184
185
0
    if (pbSuccess != nullptr)
186
0
        *pbSuccess = (pszLine != nullptr);
187
188
0
    if (pszLine == nullptr)
189
0
        return -1.0e8;
190
191
0
    return CPLAtof(pszLine);
192
0
}
193
194
/************************************************************************/
195
/*                           GetColorTable()                            */
196
/************************************************************************/
197
198
GDALColorTable *PAuxRasterBand::GetColorTable()
199
200
0
{
201
0
    return poCT;
202
0
}
203
204
/************************************************************************/
205
/*                       GetColorInterpretation()                       */
206
/************************************************************************/
207
208
GDALColorInterp PAuxRasterBand::GetColorInterpretation()
209
210
0
{
211
0
    if (poCT == nullptr)
212
0
        return GCI_Undefined;
213
214
0
    return GCI_PaletteIndex;
215
0
}
216
217
/************************************************************************/
218
/* ==================================================================== */
219
/*                              PAuxDataset                             */
220
/* ==================================================================== */
221
/************************************************************************/
222
223
/************************************************************************/
224
/*                            PAuxDataset()                             */
225
/************************************************************************/
226
227
PAuxDataset::PAuxDataset()
228
1
    : fpImage(nullptr), nGCPCount(0), pasGCPList(nullptr),
229
1
      pszAuxFilename(nullptr), papszAuxLines(nullptr)
230
1
{
231
1
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
232
1
    m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
233
1
}
234
235
/************************************************************************/
236
/*                            ~PAuxDataset()                            */
237
/************************************************************************/
238
239
PAuxDataset::~PAuxDataset()
240
241
1
{
242
1
    PAuxDataset::Close();
243
1
}
244
245
/************************************************************************/
246
/*                              Close()                                 */
247
/************************************************************************/
248
249
CPLErr PAuxDataset::Close()
250
1
{
251
1
    CPLErr eErr = CE_None;
252
1
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
253
1
    {
254
1
        if (PAuxDataset::FlushCache(true) != CE_None)
255
0
            eErr = CE_Failure;
256
257
1
        if (fpImage != nullptr)
258
0
        {
259
0
            if (VSIFCloseL(fpImage) != 0)
260
0
            {
261
0
                CPLError(CE_Failure, CPLE_FileIO, "I/O error");
262
0
                eErr = CE_Failure;
263
0
            }
264
0
        }
265
266
1
        GDALDeinitGCPs(nGCPCount, pasGCPList);
267
1
        CPLFree(pasGCPList);
268
269
1
        CPLFree(pszAuxFilename);
270
1
        CSLDestroy(papszAuxLines);
271
272
1
        if (GDALPamDataset::Close() != CE_None)
273
0
            eErr = CE_Failure;
274
1
    }
275
1
    return eErr;
276
1
}
277
278
/************************************************************************/
279
/*                            GetFileList()                             */
280
/************************************************************************/
281
282
char **PAuxDataset::GetFileList()
283
284
0
{
285
0
    char **papszFileList = RawDataset::GetFileList();
286
0
    papszFileList = CSLAddString(papszFileList, pszAuxFilename);
287
0
    return papszFileList;
288
0
}
289
290
/************************************************************************/
291
/*                              PCI2SRS()                               */
292
/*                                                                      */
293
/*      Convert PCI coordinate system to WKT.  For now this is very     */
294
/*      incomplete, but can be filled out in the future.                */
295
/************************************************************************/
296
297
OGRSpatialReference PAuxDataset::PCI2SRS(const char *pszGeosys,
298
                                         const char *pszProjParams)
299
300
0
{
301
0
    while (*pszGeosys == ' ')
302
0
        pszGeosys++;
303
304
    /* -------------------------------------------------------------------- */
305
    /*      Parse projection parameters array.                              */
306
    /* -------------------------------------------------------------------- */
307
0
    double adfProjParams[16] = {0.0};
308
309
0
    if (pszProjParams != nullptr)
310
0
    {
311
0
        char **papszTokens = CSLTokenizeString(pszProjParams);
312
313
0
        for (int i = 0;
314
0
             i < 16 && papszTokens != nullptr && papszTokens[i] != nullptr; i++)
315
0
            adfProjParams[i] = CPLAtof(papszTokens[i]);
316
317
0
        CSLDestroy(papszTokens);
318
0
    }
319
320
    /* -------------------------------------------------------------------- */
321
    /*      Convert to SRS.                                                 */
322
    /* -------------------------------------------------------------------- */
323
0
    OGRSpatialReference oSRS;
324
0
    oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
325
0
    if (oSRS.importFromPCI(pszGeosys, nullptr, adfProjParams) != OGRERR_NONE)
326
0
    {
327
0
        oSRS.Clear();
328
0
    }
329
330
0
    return oSRS;
331
0
}
332
333
/************************************************************************/
334
/*                            ScanForGCPs()                             */
335
/************************************************************************/
336
337
void PAuxDataset::ScanForGCPs()
338
339
0
{
340
0
    const int MAX_GCP = 256;
341
342
0
    nGCPCount = 0;
343
0
    CPLAssert(pasGCPList == nullptr);
344
0
    pasGCPList = static_cast<GDAL_GCP *>(CPLCalloc(sizeof(GDAL_GCP), MAX_GCP));
345
346
    /* -------------------------------------------------------------------- */
347
    /*      Get the GCP coordinate system.                                  */
348
    /* -------------------------------------------------------------------- */
349
0
    const char *pszMapUnits =
350
0
        CSLFetchNameValue(papszAuxLines, "GCP_1_MapUnits");
351
0
    const char *pszProjParams =
352
0
        CSLFetchNameValue(papszAuxLines, "GCP_1_ProjParms");
353
354
0
    if (pszMapUnits != nullptr)
355
0
        m_oGCPSRS = PCI2SRS(pszMapUnits, pszProjParams);
356
357
    /* -------------------------------------------------------------------- */
358
    /*      Collect standalone GCPs.  They look like:                       */
359
    /*                                                                      */
360
    /*      GCP_1_n = row, col, x, y [,z [,"id"[, "desc"]]]                 */
361
    /* -------------------------------------------------------------------- */
362
0
    for (int i = 0; nGCPCount < MAX_GCP; i++)
363
0
    {
364
0
        char szName[50] = {'\0'};
365
0
        snprintf(szName, sizeof(szName), "GCP_1_%d", i + 1);
366
0
        if (CSLFetchNameValue(papszAuxLines, szName) == nullptr)
367
0
            break;
368
369
0
        char **papszTokens = CSLTokenizeStringComplex(
370
0
            CSLFetchNameValue(papszAuxLines, szName), " ", TRUE, FALSE);
371
372
0
        if (CSLCount(papszTokens) >= 4)
373
0
        {
374
0
            GDALInitGCPs(1, pasGCPList + nGCPCount);
375
376
0
            pasGCPList[nGCPCount].dfGCPX = CPLAtof(papszTokens[2]);
377
0
            pasGCPList[nGCPCount].dfGCPY = CPLAtof(papszTokens[3]);
378
0
            pasGCPList[nGCPCount].dfGCPPixel = CPLAtof(papszTokens[0]);
379
0
            pasGCPList[nGCPCount].dfGCPLine = CPLAtof(papszTokens[1]);
380
381
0
            if (CSLCount(papszTokens) > 4)
382
0
                pasGCPList[nGCPCount].dfGCPZ = CPLAtof(papszTokens[4]);
383
384
0
            CPLFree(pasGCPList[nGCPCount].pszId);
385
0
            if (CSLCount(papszTokens) > 5)
386
0
            {
387
0
                pasGCPList[nGCPCount].pszId = CPLStrdup(papszTokens[5]);
388
0
            }
389
0
            else
390
0
            {
391
0
                snprintf(szName, sizeof(szName), "GCP_%d", i + 1);
392
0
                pasGCPList[nGCPCount].pszId = CPLStrdup(szName);
393
0
            }
394
395
0
            if (CSLCount(papszTokens) > 6)
396
0
            {
397
0
                CPLFree(pasGCPList[nGCPCount].pszInfo);
398
0
                pasGCPList[nGCPCount].pszInfo = CPLStrdup(papszTokens[6]);
399
0
            }
400
401
0
            nGCPCount++;
402
0
        }
403
404
0
        CSLDestroy(papszTokens);
405
0
    }
406
0
}
407
408
/************************************************************************/
409
/*                            GetGCPCount()                             */
410
/************************************************************************/
411
412
int PAuxDataset::GetGCPCount()
413
414
0
{
415
0
    return nGCPCount;
416
0
}
417
418
/************************************************************************/
419
/*                               GetGCP()                               */
420
/************************************************************************/
421
422
const GDAL_GCP *PAuxDataset::GetGCPs()
423
424
0
{
425
0
    return pasGCPList;
426
0
}
427
428
/************************************************************************/
429
/*                          GetGeoTransform()                           */
430
/************************************************************************/
431
432
CPLErr PAuxDataset::GetGeoTransform(GDALGeoTransform &gt) const
433
434
0
{
435
0
    if (CSLFetchNameValue(papszAuxLines, "UpLeftX") == nullptr ||
436
0
        CSLFetchNameValue(papszAuxLines, "UpLeftY") == nullptr ||
437
0
        CSLFetchNameValue(papszAuxLines, "LoRightX") == nullptr ||
438
0
        CSLFetchNameValue(papszAuxLines, "LoRightY") == nullptr)
439
0
    {
440
0
        gt = GDALGeoTransform();
441
0
        return CE_Failure;
442
0
    }
443
444
0
    const double dfUpLeftX =
445
0
        CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftX"));
446
0
    const double dfUpLeftY =
447
0
        CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftY"));
448
0
    const double dfLoRightX =
449
0
        CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightX"));
450
0
    const double dfLoRightY =
451
0
        CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightY"));
452
453
0
    gt[0] = dfUpLeftX;
454
0
    gt[1] = (dfLoRightX - dfUpLeftX) / GetRasterXSize();
455
0
    gt[2] = 0.0;
456
0
    gt[3] = dfUpLeftY;
457
0
    gt[4] = 0.0;
458
0
    gt[5] = (dfLoRightY - dfUpLeftY) / GetRasterYSize();
459
460
0
    return CE_None;
461
0
}
462
463
/************************************************************************/
464
/*                                Open()                                */
465
/************************************************************************/
466
467
GDALDataset *PAuxDataset::Open(GDALOpenInfo *poOpenInfo)
468
469
597k
{
470
597k
    if (poOpenInfo->nHeaderBytes < 1 ||
471
49.2k
        (!poOpenInfo->IsSingleAllowedDriver("PAux") &&
472
49.2k
         poOpenInfo->IsExtensionEqualToCI("zarr")))
473
548k
    {
474
548k
        return nullptr;
475
548k
    }
476
477
    /* -------------------------------------------------------------------- */
478
    /*      If this is an .aux file, fetch out and form the name of the     */
479
    /*      file it references.                                             */
480
    /* -------------------------------------------------------------------- */
481
482
49.2k
    CPLString osTarget = poOpenInfo->pszFilename;
483
484
49.2k
    if (poOpenInfo->IsExtensionEqualToCI("aux") &&
485
8.92k
        STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
486
49.2k
                       "AuxilaryTarget: "))
487
0
    {
488
0
        const char *pszSrc =
489
0
            reinterpret_cast<const char *>(poOpenInfo->pabyHeader + 16);
490
491
0
        char szAuxTarget[1024] = {'\0'};
492
0
        for (int i = 0; i < static_cast<int>(sizeof(szAuxTarget)) - 1 &&
493
0
                        pszSrc[i] != 10 && pszSrc[i] != 13 && pszSrc[i] != '\0';
494
0
             i++)
495
0
        {
496
0
            szAuxTarget[i] = pszSrc[i];
497
0
        }
498
0
        szAuxTarget[sizeof(szAuxTarget) - 1] = '\0';
499
500
0
        if (CPLHasPathTraversal(szAuxTarget))
501
0
        {
502
0
            CPLError(CE_Failure, CPLE_AppDefined,
503
0
                     "Path traversal detected in %s", szAuxTarget);
504
0
            return nullptr;
505
0
        }
506
0
        const std::string osPath(CPLGetPathSafe(poOpenInfo->pszFilename));
507
0
        osTarget = CPLFormFilenameSafe(osPath.c_str(), szAuxTarget, nullptr);
508
0
    }
509
510
    /* -------------------------------------------------------------------- */
511
    /*      Now we need to tear apart the filename to form a .aux           */
512
    /*      filename.                                                       */
513
    /* -------------------------------------------------------------------- */
514
49.2k
    CPLString osAuxFilename = CPLResetExtensionSafe(osTarget, "aux");
515
516
    /* -------------------------------------------------------------------- */
517
    /*      Do we have a .aux file?                                         */
518
    /* -------------------------------------------------------------------- */
519
49.2k
    CSLConstList papszSiblingFiles = poOpenInfo->GetSiblingFiles();
520
49.2k
    if (papszSiblingFiles != nullptr &&
521
41.8k
        CSLFindString(papszSiblingFiles, CPLGetFilename(osAuxFilename)) == -1)
522
32.2k
    {
523
32.2k
        return nullptr;
524
32.2k
    }
525
526
16.9k
    VSILFILE *fp = VSIFOpenL(osAuxFilename, "r");
527
16.9k
    if (fp == nullptr)
528
8.31k
    {
529
8.31k
        osAuxFilename = CPLResetExtensionSafe(osTarget, "AUX");
530
8.31k
        fp = VSIFOpenL(osAuxFilename, "r");
531
8.31k
    }
532
533
16.9k
    if (fp == nullptr)
534
7.43k
        return nullptr;
535
536
    /* -------------------------------------------------------------------- */
537
    /*      Is this file a PCI .aux file?  Check the first line for the     */
538
    /*      telltale AuxilaryTarget keyword.                                */
539
    /*                                                                      */
540
    /*      At this point we should be verifying that it refers to our      */
541
    /*      binary file, but that is a pretty involved test.                */
542
    /* -------------------------------------------------------------------- */
543
9.56k
    CPLPushErrorHandler(CPLQuietErrorHandler);
544
9.56k
    const char *pszLine = CPLReadLine2L(fp, 1024, nullptr);
545
9.56k
    CPLPopErrorHandler();
546
547
9.56k
    CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
548
549
9.56k
    if (pszLine == nullptr || (!STARTS_WITH_CI(pszLine, "AuxilaryTarget") &&
550
9.24k
                               !STARTS_WITH_CI(pszLine, "AuxiliaryTarget")))
551
9.56k
    {
552
9.56k
        CPLErrorReset();
553
9.56k
        return nullptr;
554
9.56k
    }
555
556
    /* -------------------------------------------------------------------- */
557
    /*      Create a corresponding GDALDataset.                             */
558
    /* -------------------------------------------------------------------- */
559
1
    auto poDS = std::make_unique<PAuxDataset>();
560
561
    /* -------------------------------------------------------------------- */
562
    /*      Load the .aux file into a string list suitable to be            */
563
    /*      searched with CSLFetchNameValue().                              */
564
    /* -------------------------------------------------------------------- */
565
1
    poDS->papszAuxLines = CSLLoad2(osAuxFilename, 1024, 1024, nullptr);
566
1
    poDS->pszAuxFilename = CPLStrdup(osAuxFilename);
567
568
    /* -------------------------------------------------------------------- */
569
    /*      Find the RawDefinition line to establish overall parameters.    */
570
    /* -------------------------------------------------------------------- */
571
1
    pszLine = CSLFetchNameValue(poDS->papszAuxLines, "RawDefinition");
572
573
    // It seems PCI now writes out .aux files without RawDefinition in
574
    // some cases.  See bug 947.
575
1
    if (pszLine == nullptr)
576
1
    {
577
1
        return nullptr;
578
1
    }
579
580
0
    const CPLStringList aosTokens(CSLTokenizeString(pszLine));
581
582
0
    if (aosTokens.size() < 3)
583
0
    {
584
0
        CPLError(CE_Failure, CPLE_AppDefined,
585
0
                 "RawDefinition missing or corrupt in %s.",
586
0
                 poOpenInfo->pszFilename);
587
0
        return nullptr;
588
0
    }
589
590
0
    poDS->nRasterXSize = atoi(aosTokens[0]);
591
0
    poDS->nRasterYSize = atoi(aosTokens[1]);
592
0
    int l_nBands = atoi(aosTokens[2]);
593
0
    poDS->eAccess = poOpenInfo->eAccess;
594
595
0
    if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
596
0
        !GDALCheckBandCount(l_nBands, FALSE))
597
0
    {
598
0
        return nullptr;
599
0
    }
600
601
    /* -------------------------------------------------------------------- */
602
    /*      Open the file.                                                  */
603
    /* -------------------------------------------------------------------- */
604
0
    if (poOpenInfo->eAccess == GA_Update)
605
0
    {
606
0
        poDS->fpImage = VSIFOpenL(osTarget, "rb+");
607
608
0
        if (poDS->fpImage == nullptr)
609
0
        {
610
0
            CPLError(CE_Failure, CPLE_OpenFailed,
611
0
                     "File %s is missing or read-only, check permissions.",
612
0
                     osTarget.c_str());
613
0
            return nullptr;
614
0
        }
615
0
    }
616
0
    else
617
0
    {
618
0
        poDS->fpImage = VSIFOpenL(osTarget, "rb");
619
620
0
        if (poDS->fpImage == nullptr)
621
0
        {
622
0
            CPLError(CE_Failure, CPLE_OpenFailed,
623
0
                     "File %s is missing or unreadable.", osTarget.c_str());
624
0
            return nullptr;
625
0
        }
626
0
    }
627
628
    /* -------------------------------------------------------------------- */
629
    /*      Collect raw definitions of each channel and create              */
630
    /*      corresponding bands.                                            */
631
    /* -------------------------------------------------------------------- */
632
0
    for (int i = 0; i < l_nBands; i++)
633
0
    {
634
0
        char szDefnName[32] = {'\0'};
635
0
        snprintf(szDefnName, sizeof(szDefnName), "ChanDefinition-%d", i + 1);
636
637
0
        pszLine = CSLFetchNameValue(poDS->papszAuxLines, szDefnName);
638
0
        if (pszLine == nullptr)
639
0
        {
640
0
            continue;
641
0
        }
642
643
0
        const CPLStringList aosTokensBand(CSLTokenizeString(pszLine));
644
0
        if (aosTokensBand.size() < 4)
645
0
        {
646
            // Skip the band with broken description
647
0
            continue;
648
0
        }
649
650
0
        GDALDataType eType = GDT_Unknown;
651
0
        if (EQUAL(aosTokensBand[0], "16U"))
652
0
            eType = GDT_UInt16;
653
0
        else if (EQUAL(aosTokensBand[0], "16S"))
654
0
            eType = GDT_Int16;
655
0
        else if (EQUAL(aosTokensBand[0], "32R"))
656
0
            eType = GDT_Float32;
657
0
        else
658
0
            eType = GDT_Byte;
659
660
0
        bool bNative = true;
661
0
        if (CSLCount(aosTokensBand) > 4)
662
0
        {
663
0
#ifdef CPL_LSB
664
0
            bNative = EQUAL(aosTokensBand[4], "Swapped");
665
#else
666
            bNative = EQUAL(aosTokensBand[4], "Unswapped");
667
#endif
668
0
        }
669
670
0
        const vsi_l_offset nBandOffset = CPLScanUIntBig(
671
0
            aosTokensBand[1], static_cast<int>(strlen(aosTokensBand[1])));
672
0
        const int nPixelOffset = atoi(aosTokensBand[2]);
673
0
        const int nLineOffset = atoi(aosTokensBand[3]);
674
675
0
        if (nPixelOffset <= 0 || nLineOffset <= 0)
676
0
        {
677
            // Skip the band with broken offsets.
678
0
            continue;
679
0
        }
680
681
0
        auto poBand = std::make_unique<PAuxRasterBand>(
682
0
            poDS.get(), poDS->nBands + 1, poDS->fpImage, nBandOffset,
683
0
            nPixelOffset, nLineOffset, eType, bNative);
684
0
        if (!poBand->IsValid())
685
0
            return nullptr;
686
0
        poDS->SetBand(poDS->nBands + 1, std::move(poBand));
687
0
    }
688
689
    /* -------------------------------------------------------------------- */
690
    /*      Get the projection.                                             */
691
    /* -------------------------------------------------------------------- */
692
0
    const char *pszMapUnits =
693
0
        CSLFetchNameValue(poDS->papszAuxLines, "MapUnits");
694
0
    const char *pszProjParams =
695
0
        CSLFetchNameValue(poDS->papszAuxLines, "ProjParams");
696
697
0
    if (pszMapUnits != nullptr)
698
0
    {
699
0
        poDS->m_oSRS = PCI2SRS(pszMapUnits, pszProjParams);
700
0
    }
701
702
    /* -------------------------------------------------------------------- */
703
    /*      Initialize any PAM information.                                 */
704
    /* -------------------------------------------------------------------- */
705
0
    poDS->SetDescription(osTarget);
706
0
    poDS->TryLoadXML();
707
708
    /* -------------------------------------------------------------------- */
709
    /*      Check for overviews.                                            */
710
    /* -------------------------------------------------------------------- */
711
0
    poDS->oOvManager.Initialize(poDS.get(), osTarget);
712
713
0
    poDS->ScanForGCPs();
714
715
0
    return poDS.release();
716
0
}
717
718
/************************************************************************/
719
/*                         GDALRegister_PAux()                          */
720
/************************************************************************/
721
722
void GDALRegister_PAux()
723
724
22
{
725
22
    if (GDALGetDriverByName("PAux") != nullptr)
726
0
        return;
727
728
22
    GDALDriver *poDriver = new GDALDriver();
729
730
22
    poDriver->SetDescription("PAux");
731
22
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
732
22
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PCI .aux Labelled");
733
22
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/paux.html");
734
22
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
735
736
22
    poDriver->pfnOpen = PAuxDataset::Open;
737
738
22
    GetGDALDriverManager()->RegisterDriver(poDriver);
739
22
}