• 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

67.62
/frmts/pcidsk/pcidskdataset2.cpp
1
/******************************************************************************
2
 *
3
 * Project:  PCIDSK Database File
4
 * Purpose:  Read/write PCIDSK Database File used by the PCI software, using
5
 *           the external PCIDSK library.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
10
 * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14

15
#include "gdal_frmts.h"
16
#include "pcidskdataset2.h"
17
#include "pcidskdrivercore.h"
18

19
#include <algorithm>
20

21
const PCIDSK::PCIDSKInterfaces *PCIDSK2GetInterfaces(void);
22

23
/************************************************************************/
24
/* ==================================================================== */
25
/*                            PCIDSK2Band                               */
26
/* ==================================================================== */
27
/************************************************************************/
28

29
/************************************************************************/
30
/*                            PCIDSK2Band()                             */
31
/*                                                                      */
32
/*      This constructor is used for main file channels.                */
33
/************************************************************************/
34

35
PCIDSK2Band::PCIDSK2Band(PCIDSKFile *poFileIn, PCIDSKChannel *poChannelIn)
233✔
36

37
{
38
    Initialize();
233✔
39

40
    poFile = poFileIn;
233✔
41
    poChannel = poChannelIn;
233✔
42

43
    nBlockXSize = static_cast<int>(poChannel->GetBlockWidth());
233✔
44
    nBlockYSize = static_cast<int>(poChannel->GetBlockHeight());
233✔
45

46
    eDataType = PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType());
233✔
47

48
    if (!STARTS_WITH_CI(poChannel->GetDescription().c_str(),
233✔
49
                        "Contents Not Specified"))
50
        GDALMajorObject::SetDescription(poChannel->GetDescription().c_str());
10✔
51

52
    /* -------------------------------------------------------------------- */
53
    /*      Do we have overviews?                                           */
54
    /* -------------------------------------------------------------------- */
55
    RefreshOverviewList();
233✔
56
}
233✔
57

58
/************************************************************************/
59
/*                            PCIDSK2Band()                             */
60
/*                                                                      */
61
/*      This constructor is used for overviews and bitmap segments      */
62
/*      as bands.                                                       */
63
/************************************************************************/
64

65
PCIDSK2Band::PCIDSK2Band(PCIDSKChannel *poChannelIn)
11✔
66

67
{
68
    Initialize();
11✔
69

70
    this->poChannel = poChannelIn;
11✔
71

72
    nBand = 1;
11✔
73

74
    nBlockXSize = static_cast<int>(poChannel->GetBlockWidth());
11✔
75
    nBlockYSize = static_cast<int>(poChannel->GetBlockHeight());
11✔
76

77
    nRasterXSize = static_cast<int>(poChannel->GetWidth());
11✔
78
    nRasterYSize = static_cast<int>(poChannel->GetHeight());
11✔
79

80
    eDataType = PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType());
11✔
81

82
    if (poChannel->GetType() == CHN_BIT)
11✔
83
    {
84
        PCIDSK2Band::SetMetadataItem("NBITS", "1", "IMAGE_STRUCTURE");
×
85

86
        if (!STARTS_WITH_CI(poChannel->GetDescription().c_str(),
×
87
                            "Contents Not Specified"))
88
            GDALMajorObject::SetDescription(
×
89
                poChannel->GetDescription().c_str());
×
90
    }
91
}
11✔
92

93
/************************************************************************/
94
/*                             Initialize()                             */
95
/************************************************************************/
96

97
void PCIDSK2Band::Initialize()
244✔
98

99
{
100
    papszLastMDListValue = nullptr;
244✔
101

102
    poChannel = nullptr;
244✔
103
    poFile = nullptr;
244✔
104
    poDS = nullptr;
244✔
105

106
    bCheckedForColorTable = false;
244✔
107
    poColorTable = nullptr;
244✔
108
    nPCTSegNumber = -1;
244✔
109

110
    papszCategoryNames = nullptr;
244✔
111
}
244✔
112

113
/************************************************************************/
114
/*                            ~PCIDSK2Band()                            */
115
/************************************************************************/
116

117
PCIDSK2Band::~PCIDSK2Band()
732✔
118

119
{
120
    while (!apoOverviews.empty())
255✔
121
    {
122
        delete apoOverviews.back();
11✔
123
        apoOverviews.pop_back();
11✔
124
    }
125
    CSLDestroy(papszLastMDListValue);
244✔
126
    CSLDestroy(papszCategoryNames);
244✔
127

128
    delete poColorTable;
244✔
129
}
488✔
130

131
/************************************************************************/
132
/*                           SetDescription()                           */
133
/************************************************************************/
134

135
void PCIDSK2Band::SetDescription(const char *pszDescription)
3✔
136

137
{
138
    if (GetAccess() == GA_ReadOnly)
3✔
139
    {
140
        CPLError(CE_Failure, CPLE_NoWriteAccess,
×
141
                 "Unable to set description on read-only file.");
142
        return;
×
143
    }
144

145
    try
146
    {
147
        poChannel->SetDescription(pszDescription);
3✔
148

149
        if (!STARTS_WITH_CI(poChannel->GetDescription().c_str(),
3✔
150
                            "Contents Not Specified"))
151
            GDALMajorObject::SetDescription(
3✔
152
                poChannel->GetDescription().c_str());
6✔
153
    }
154
    catch (const PCIDSKException &ex)
×
155
    {
156
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
157
    }
158
}
159

160
/************************************************************************/
161
/*                          GetCategoryNames()                          */
162
/*                                                                      */
163
/*      Offer category names from Class_*_ metadata.                    */
164
/************************************************************************/
165

166
char **PCIDSK2Band::GetCategoryNames()
4✔
167

168
{
169
    // already scanned?
170
    if (papszCategoryNames != nullptr)
4✔
171
        return papszCategoryNames;
×
172

173
    try
174
    {
175
        std::vector<std::string> aosMDKeys = poChannel->GetMetadataKeys();
8✔
176
        int nClassCount = 0;
4✔
177
        constexpr int nMaxClasses = 10000;
4✔
178
        papszCategoryNames = reinterpret_cast<char **>(
4✔
179
            CPLCalloc(nMaxClasses + 1, sizeof(char *)));
4✔
180

181
        for (size_t i = 0; i < aosMDKeys.size(); i++)
7✔
182
        {
183
            CPLString osKey = aosMDKeys[i];
3✔
184

185
            // is this a "Class_n_name" keyword?
186
            if (!STARTS_WITH_CI(osKey, "Class_"))
3✔
187
                continue;
3✔
188

189
            if (!EQUAL(osKey.c_str() + osKey.size() - 5, "_name"))
×
190
                continue;
×
191

192
            // Ignore unreasonable class values.
193
            int iClass = atoi(osKey.c_str() + 6);
×
194

195
            if (iClass < 0 || iClass > 10000)
×
196
                continue;
×
197

198
            // Fetch the name.
199
            CPLString osName = poChannel->GetMetadataValue(osKey);
×
200

201
            // do we need to put in place dummy class names for missing values?
202
            if (iClass >= nClassCount)
×
203
            {
204
                while (iClass >= nClassCount)
×
205
                {
206
                    papszCategoryNames[nClassCount++] = CPLStrdup("");
×
207
                    papszCategoryNames[nClassCount] = nullptr;
×
208
                }
209
            }
210

211
            // Replace target category name.
212
            CPLFree(papszCategoryNames[iClass]);
×
213
            papszCategoryNames[iClass] = nullptr;
×
214

215
            papszCategoryNames[iClass] = CPLStrdup(osName);
×
216
        }
217

218
        if (nClassCount == 0)
4✔
219
            return GDALPamRasterBand::GetCategoryNames();
4✔
220

221
        return papszCategoryNames;
×
222
    }
223
    catch (const PCIDSKException &ex)
×
224
    {
225
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
226
        return nullptr;
×
227
    }
228
}
229

230
/************************************************************************/
231
/*                         CheckForColorTable()                         */
232
/************************************************************************/
233

234
bool PCIDSK2Band::CheckForColorTable()
27✔
235

236
{
237
    if (bCheckedForColorTable || poFile == nullptr)
27✔
238
        return true;
14✔
239

240
    bCheckedForColorTable = true;
13✔
241

242
    try
243
    {
244
        /* --------------------------------------------------------------------
245
         */
246
        /*      Try to find an appropriate PCT segment to use. */
247
        /* --------------------------------------------------------------------
248
         */
249
        std::string osDefaultPCT =
250
            poChannel->GetMetadataValue("DEFAULT_PCT_REF");
39✔
251
        PCIDSKSegment *poPCTSeg = nullptr;
13✔
252

253
        // If there is no metadata, assume a single PCT in a file with only
254
        // one raster band must be intended for it.
255
        if (osDefaultPCT.empty() && poDS != nullptr &&
25✔
256
            poDS->GetRasterCount() == 1)
12✔
257
        {
258
            poPCTSeg = poFile->GetSegment(SEG_PCT, "");
12✔
259
            if (poPCTSeg != nullptr &&
12✔
260
                poFile->GetSegment(SEG_PCT, "", poPCTSeg->GetSegmentNumber()) !=
12✔
261
                    nullptr)
262
                poPCTSeg = nullptr;
×
263
        }
264
        // Parse default PCT ref assuming an in file reference.
265
        else if (!osDefaultPCT.empty() &&
2✔
266
                 strstr(osDefaultPCT.c_str(), "PCT:") != nullptr)
1✔
267
        {
268
            poPCTSeg = poFile->GetSegment(
1✔
269
                atoi(strstr(osDefaultPCT.c_str(), "PCT:") + 4));
1✔
270
        }
271

272
        if (poPCTSeg != nullptr)
13✔
273
        {
274
            poColorTable = new GDALColorTable();
1✔
275
            unsigned char abyPCT[768];
276

277
            PCIDSK_PCT *poPCT = dynamic_cast<PCIDSK_PCT *>(poPCTSeg);
1✔
278
            if (poPCT)
1✔
279
            {
280
                nPCTSegNumber = poPCTSeg->GetSegmentNumber();
1✔
281

282
                poPCT->ReadPCT(abyPCT);
1✔
283

284
                for (int i = 0; i < 256; i++)
257✔
285
                {
286
                    GDALColorEntry sEntry;
287

288
                    sEntry.c1 = abyPCT[256 * 0 + i];
256✔
289
                    sEntry.c2 = abyPCT[256 * 1 + i];
256✔
290
                    sEntry.c3 = abyPCT[256 * 2 + i];
256✔
291
                    sEntry.c4 = 255;
256✔
292
                    poColorTable->SetColorEntry(i, &sEntry);
256✔
293
                }
294
            }
295
        }
296

297
        /* --------------------------------------------------------------------
298
         */
299
        /*      If we did not find an appropriate PCT segment, check for */
300
        /*      Class_n color data from which to construct a color table. */
301
        /* --------------------------------------------------------------------
302
         */
303
        std::vector<std::string> aosMDKeys = poChannel->GetMetadataKeys();
26✔
304

305
        for (size_t i = 0; i < aosMDKeys.size(); i++)
23✔
306
        {
307
            CPLString osKey = aosMDKeys[i];
10✔
308

309
            // is this a "Class_n_name" keyword?
310

311
            if (!STARTS_WITH_CI(osKey, "Class_"))
10✔
312
                continue;
10✔
313

314
            if (!EQUAL(osKey.c_str() + osKey.size() - 6, "_Color"))
×
315
                continue;
×
316

317
            // Ignore unreasonable class values.
318
            const int iClass = atoi(osKey.c_str() + 6);
×
319

320
            if (iClass < 0 || iClass > 10000)
×
321
                continue;
×
322

323
            // Fetch and parse the RGB value "(RGB:red green blue)"
324
            CPLString osRGB = poChannel->GetMetadataValue(osKey);
×
325

326
            if (!STARTS_WITH_CI(osRGB, "(RGB:"))
×
327
                continue;
×
328

329
            int nRed, nGreen, nBlue;
330
            if (sscanf(osRGB.c_str() + 5, "%d %d %d", &nRed, &nGreen, &nBlue) !=
×
331
                3)
332
                continue;
×
333

334
            // we have an entry - apply to the color table.
335
            GDALColorEntry sEntry;
336

337
            sEntry.c1 = (short)nRed;
×
338
            sEntry.c2 = (short)nGreen;
×
339
            sEntry.c3 = (short)nBlue;
×
340
            sEntry.c4 = 255;
×
341

342
            if (poColorTable == nullptr)
×
343
            {
344
                CPLDebug("PCIDSK",
×
345
                         "Using Class_n_Color metadata for color table.");
346
                poColorTable = new GDALColorTable();
×
347
            }
348

349
            poColorTable->SetColorEntry(iClass, &sEntry);
×
350
        }
351
    }
352
    catch (const PCIDSKException &ex)
×
353
    {
354
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
355
        return false;
×
356
    }
357

358
    return true;
13✔
359
}
360

361
/************************************************************************/
362
/*                           GetColorTable()                            */
363
/************************************************************************/
364

365
GDALColorTable *PCIDSK2Band::GetColorTable()
10✔
366

367
{
368
    CheckForColorTable();
10✔
369

370
    if (poColorTable)
10✔
371
        return poColorTable;
2✔
372

373
    return GDALPamRasterBand::GetColorTable();
8✔
374
}
375

376
/************************************************************************/
377
/*                           SetColorTable()                            */
378
/************************************************************************/
379

380
CPLErr PCIDSK2Band::SetColorTable(GDALColorTable *poCT)
2✔
381

382
{
383
    if (!CheckForColorTable())
2✔
384
        return CE_Failure;
×
385

386
    // no color tables on overviews.
387
    if (poFile == nullptr)
2✔
388
        return CE_Failure;
×
389

390
    if (GetAccess() == GA_ReadOnly)
2✔
391
    {
392
        CPLError(CE_Failure, CPLE_NoWriteAccess,
×
393
                 "Unable to set color table on read-only file.");
394
        return CE_Failure;
×
395
    }
396

397
    try
398
    {
399
        /* --------------------------------------------------------------------
400
         */
401
        /*      Are we trying to delete the color table? */
402
        /* --------------------------------------------------------------------
403
         */
404
        if (poCT == nullptr)
2✔
405
        {
406
            delete poColorTable;
1✔
407
            poColorTable = nullptr;
1✔
408

409
            if (nPCTSegNumber != -1)
1✔
410
                poFile->DeleteSegment(nPCTSegNumber);
1✔
411
            poChannel->SetMetadataValue("DEFAULT_PCT_REF", "");
1✔
412
            nPCTSegNumber = -1;
1✔
413

414
            return CE_None;
1✔
415
        }
416

417
        /* --------------------------------------------------------------------
418
         */
419
        /*      Do we need to create the segment?  If so, also set the */
420
        /*      default pct metadata. */
421
        /* --------------------------------------------------------------------
422
         */
423
        if (nPCTSegNumber == -1)
1✔
424
        {
425
            nPCTSegNumber = poFile->CreateSegment(
1✔
426
                "PCTTable", "Default Pseudo-Color Table", SEG_PCT, 0);
1✔
427

428
            CPLString osRef;
1✔
429
            osRef.Printf("gdb:/{PCT:%d}", nPCTSegNumber);
1✔
430
            poChannel->SetMetadataValue("DEFAULT_PCT_REF", osRef);
1✔
431
        }
432

433
        /* --------------------------------------------------------------------
434
         */
435
        /*      Write out the PCT. */
436
        /* --------------------------------------------------------------------
437
         */
438
        const int nColorCount = std::min(256, poCT->GetColorEntryCount());
1✔
439

440
        unsigned char abyPCT[768];
441
        memset(abyPCT, 0, 768);
1✔
442

443
        for (int i = 0; i < nColorCount; i++)
4✔
444
        {
445
            GDALColorEntry sEntry;
446

447
            poCT->GetColorEntryAsRGB(i, &sEntry);
3✔
448
            abyPCT[256 * 0 + i] = (unsigned char)sEntry.c1;
3✔
449
            abyPCT[256 * 1 + i] = (unsigned char)sEntry.c2;
3✔
450
            abyPCT[256 * 2 + i] = (unsigned char)sEntry.c3;
3✔
451
        }
452

453
        PCIDSK_PCT *poPCT =
454
            dynamic_cast<PCIDSK_PCT *>(poFile->GetSegment(nPCTSegNumber));
1✔
455
        if (poPCT)
1✔
456
            poPCT->WritePCT(abyPCT);
1✔
457

458
        delete poColorTable;
1✔
459
        poColorTable = poCT->Clone();
1✔
460
    }
461

462
    /* -------------------------------------------------------------------- */
463
    /*      Trap exceptions.                                                */
464
    /* -------------------------------------------------------------------- */
465
    catch (const PCIDSKException &ex)
×
466
    {
467
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
468
        return CE_Failure;
×
469
    }
470

471
    return CE_None;
1✔
472
}
473

474
/************************************************************************/
475
/*                       GetColorInterpretation()                       */
476
/************************************************************************/
477

478
GDALColorInterp PCIDSK2Band::GetColorInterpretation()
15✔
479

480
{
481
    CheckForColorTable();
15✔
482

483
    if (poColorTable != nullptr)
15✔
484
        return GCI_PaletteIndex;
1✔
485

486
    return GDALPamRasterBand::GetColorInterpretation();
14✔
487
}
488

489
/************************************************************************/
490
/*                        RefreshOverviewList()                         */
491
/************************************************************************/
492

493
void PCIDSK2Band::RefreshOverviewList()
234✔
494

495
{
496
    /* -------------------------------------------------------------------- */
497
    /*      Clear existing overviews.                                       */
498
    /* -------------------------------------------------------------------- */
499
    while (!apoOverviews.empty())
234✔
500
    {
501
        delete apoOverviews.back();
×
502
        apoOverviews.pop_back();
×
503
    }
504

505
    /* -------------------------------------------------------------------- */
506
    /*      Fetch overviews.                                                */
507
    /* -------------------------------------------------------------------- */
508
    for (int iOver = 0; iOver < poChannel->GetOverviewCount(); iOver++)
245✔
509
    {
510
        auto poOvrBand = new PCIDSK2Band(poChannel->GetOverview(iOver));
11✔
511
        poOvrBand->eAccess = eAccess;
11✔
512
        apoOverviews.push_back(poOvrBand);
11✔
513
    }
514
}
234✔
515

516
/************************************************************************/
517
/*                             IReadBlock()                             */
518
/************************************************************************/
519

520
CPLErr PCIDSK2Band::IReadBlock(int iBlockX, int iBlockY, void *pData)
262✔
521

522
{
523
    try
524
    {
525
        poChannel->ReadBlock(iBlockX + iBlockY * nBlocksPerRow, pData);
262✔
526

527
        // Do we need to upsample 1bit to 8bit?
528
        if (poChannel->GetType() == CHN_BIT)
262✔
529
        {
530
            GByte *pabyData = reinterpret_cast<GByte *>(pData);
×
531

532
            for (int ii = nBlockXSize * nBlockYSize - 1; ii >= 0; ii--)
×
533
            {
534
                if ((pabyData[ii >> 3] & (0x80 >> (ii & 0x7))))
×
535
                    pabyData[ii] = 1;
×
536
                else
537
                    pabyData[ii] = 0;
×
538
            }
539
        }
540

541
        return CE_None;
262✔
542
    }
543
    catch (const PCIDSKException &ex)
×
544
    {
545
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
546
        return CE_Failure;
×
547
    }
548
}
549

550
/************************************************************************/
551
/*                             IWriteBlock()                            */
552
/************************************************************************/
553

554
CPLErr PCIDSK2Band::IWriteBlock(int iBlockX, int iBlockY, void *pData)
645✔
555

556
{
557
    try
558
    {
559
        poChannel->WriteBlock(iBlockX + iBlockY * nBlocksPerRow, pData);
645✔
560
    }
561
    catch (const PCIDSKException &ex)
×
562
    {
563
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
564
        return CE_Failure;
×
565
    }
566

567
    return CE_None;
645✔
568
}
569

570
/************************************************************************/
571
/*                          GetOverviewCount()                          */
572
/************************************************************************/
573

574
int PCIDSK2Band::GetOverviewCount()
16✔
575

576
{
577
    if (!apoOverviews.empty())
16✔
578
        return static_cast<int>(apoOverviews.size());
5✔
579

580
    return GDALPamRasterBand::GetOverviewCount();
11✔
581
}
582

583
/************************************************************************/
584
/*                            GetOverview()                             */
585
/************************************************************************/
586

587
GDALRasterBand *PCIDSK2Band::GetOverview(int iOverview)
6✔
588

589
{
590
    if (iOverview < 0 || iOverview >= static_cast<int>(apoOverviews.size()))
6✔
591
        return GDALPamRasterBand::GetOverview(iOverview);
1✔
592

593
    return apoOverviews[iOverview];
5✔
594
}
595

596
/************************************************************************/
597
/*                            SetMetadata()                             */
598
/************************************************************************/
599

600
CPLErr PCIDSK2Band::SetMetadata(char **papszMD, const char *pszDomain)
2✔
601

602
{
603
    /* -------------------------------------------------------------------- */
604
    /*      PCIDSK only supports metadata in the default domain.            */
605
    /* -------------------------------------------------------------------- */
606
    if (pszDomain != nullptr && strlen(pszDomain) > 0)
2✔
607
        return GDALPamRasterBand::SetMetadata(papszMD, pszDomain);
×
608

609
    /* -------------------------------------------------------------------- */
610
    /*      Set each item individually.                                     */
611
    /* -------------------------------------------------------------------- */
612
    CSLDestroy(papszLastMDListValue);
2✔
613
    papszLastMDListValue = nullptr;
2✔
614
    m_oCacheMetadataItem.clear();
2✔
615

616
    if (GetAccess() == GA_ReadOnly)
2✔
617
    {
618
        CPLError(CE_Failure, CPLE_NoWriteAccess,
×
619
                 "Unable to set metadata on read-only file.");
620
        return CE_Failure;
×
621
    }
622

623
    try
624
    {
625
        for (int iItem = 0; papszMD && papszMD[iItem]; iItem++)
5✔
626
        {
627
            char *pszItemName = nullptr;
3✔
628

629
            const char *pszItemValue =
630
                CPLParseNameValue(papszMD[iItem], &pszItemName);
3✔
631
            if (pszItemName != nullptr)
3✔
632
            {
633
                poChannel->SetMetadataValue(pszItemName, pszItemValue);
3✔
634
                CPLFree(pszItemName);
3✔
635
            }
636
        }
637
    }
638
    catch (const PCIDSKException &ex)
×
639
    {
640
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
641
        return CE_Failure;
×
642
    }
643

644
    return CE_None;
2✔
645
}
646

647
/************************************************************************/
648
/*                          SetMetadataItem()                           */
649
/************************************************************************/
650

651
CPLErr PCIDSK2Band::SetMetadataItem(const char *pszName, const char *pszValue,
5✔
652
                                    const char *pszDomain)
653

654
{
655
    /* -------------------------------------------------------------------- */
656
    /*      PCIDSK only supports metadata in the default domain.            */
657
    /* -------------------------------------------------------------------- */
658
    if (pszDomain != nullptr && strlen(pszDomain) > 0)
5✔
659
        return GDALPamRasterBand::SetMetadataItem(pszName, pszValue, pszDomain);
1✔
660

661
    /* -------------------------------------------------------------------- */
662
    /*      Set on the file.                                                */
663
    /* -------------------------------------------------------------------- */
664
    CSLDestroy(papszLastMDListValue);
4✔
665
    papszLastMDListValue = nullptr;
4✔
666
    m_oCacheMetadataItem.clear();
4✔
667

668
    if (GetAccess() == GA_ReadOnly)
4✔
669
    {
670
        CPLError(CE_Failure, CPLE_NoWriteAccess,
×
671
                 "Unable to set metadata on read-only file.");
672
        return CE_Failure;
×
673
    }
674

675
    try
676
    {
677
        if (!pszValue)
4✔
678
            pszValue = "";
×
679
        poChannel->SetMetadataValue(pszName, pszValue);
4✔
680
    }
681
    catch (const PCIDSKException &ex)
×
682
    {
683
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
684
        return CE_Failure;
×
685
    }
686

687
    return CE_None;
4✔
688
}
689

690
/************************************************************************/
691
/*                      GetMetadataDomainList()                         */
692
/************************************************************************/
693

694
char **PCIDSK2Band::GetMetadataDomainList()
×
695
{
696
    return BuildMetadataDomainList(GDALPamRasterBand::GetMetadataDomainList(),
×
697
                                   TRUE, "", nullptr);
×
698
}
699

700
/************************************************************************/
701
/*                          GetMetadataItem()                           */
702
/************************************************************************/
703

704
const char *PCIDSK2Band::GetMetadataItem(const char *pszName,
34✔
705
                                         const char *pszDomain)
706

707
{
708
    /* -------------------------------------------------------------------- */
709
    /*      PCIDSK only supports metadata in the default domain.            */
710
    /* -------------------------------------------------------------------- */
711
    if (pszDomain != nullptr && strlen(pszDomain) > 0)
34✔
712
        return GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
23✔
713

714
    /* -------------------------------------------------------------------- */
715
    /*      Try and fetch (use cached value if available)                   */
716
    /* -------------------------------------------------------------------- */
717
    auto oIter = m_oCacheMetadataItem.find(pszName);
11✔
718
    if (oIter != m_oCacheMetadataItem.end())
11✔
719
    {
720
        return oIter->second.empty() ? nullptr : oIter->second.c_str();
5✔
721
    }
722

723
    CPLString osValue;
12✔
724
    try
725
    {
726
        osValue = poChannel->GetMetadataValue(pszName);
6✔
727
    }
728
    catch (const PCIDSKException &ex)
×
729
    {
730
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
731
        return nullptr;
×
732
    }
733

734
    oIter = m_oCacheMetadataItem
6✔
735
                .insert(std::pair<std::string, std::string>(pszName, osValue))
6✔
736
                .first;
737
    return oIter->second.empty() ? nullptr : oIter->second.c_str();
6✔
738
}
739

740
/************************************************************************/
741
/*                            GetMetadata()                             */
742
/************************************************************************/
743

744
char **PCIDSK2Band::GetMetadata(const char *pszDomain)
6✔
745

746
{
747
    /* -------------------------------------------------------------------- */
748
    /*      PCIDSK only supports metadata in the default domain.            */
749
    /* -------------------------------------------------------------------- */
750
    if (pszDomain != nullptr && strlen(pszDomain) > 0)
6✔
751
        return GDALPamRasterBand::GetMetadata(pszDomain);
1✔
752

753
    /* -------------------------------------------------------------------- */
754
    /*      If we have a cached result, just use that.                      */
755
    /* -------------------------------------------------------------------- */
756
    if (papszLastMDListValue != nullptr)
5✔
757
        return papszLastMDListValue;
×
758

759
    /* -------------------------------------------------------------------- */
760
    /*      Fetch and build the list.                                       */
761
    /* -------------------------------------------------------------------- */
762
    try
763
    {
764
        std::vector<std::string> aosKeys = poChannel->GetMetadataKeys();
10✔
765

766
        for (unsigned int i = 0; i < aosKeys.size(); i++)
11✔
767
        {
768
            if (aosKeys[i].c_str()[0] == '_')
6✔
769
                continue;
3✔
770

771
            papszLastMDListValue = CSLSetNameValue(
6✔
772
                papszLastMDListValue, aosKeys[i].c_str(),
3✔
773
                poChannel->GetMetadataValue(aosKeys[i]).c_str());
6✔
774
        }
775
    }
776
    catch (const PCIDSKException &ex)
×
777
    {
778
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
779
        return nullptr;
×
780
    }
781

782
    return papszLastMDListValue;
5✔
783
}
784

785
/************************************************************************/
786
/* ==================================================================== */
787
/*                            PCIDSK2Dataset                            */
788
/* ==================================================================== */
789
/************************************************************************/
790

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

795
PCIDSK2Dataset::PCIDSK2Dataset()
245✔
796
    : papszLastMDListValue(nullptr), poFile(nullptr)
245✔
797
{
798
}
245✔
799

800
/************************************************************************/
801
/*                            ~PCIDSK2Dataset()                          */
802
/************************************************************************/
803

804
// FIXME? is an exception can really be thrown in the destructor, then it is
805
// very dangerous !
806
#ifdef _MSC_VER
807
#pragma warning(push)
808
#pragma warning(disable : 4702) /*  unreachable code */
809
#endif
810
PCIDSK2Dataset::~PCIDSK2Dataset()
490✔
811
{
812
    PCIDSK2Dataset::FlushCache(true);
245✔
813

814
    while (!apoLayers.empty())
1,428✔
815
    {
816
        delete apoLayers.back();
1,183✔
817
        apoLayers.pop_back();
1,183✔
818
    }
819

820
    if (m_poSRS)
245✔
821
        m_poSRS->Release();
7✔
822

823
    try
824
    {
825
        if (poFile != nullptr)
245✔
826
            delete poFile;
245✔
827
    }
828

829
    /* -------------------------------------------------------------------- */
830
    /*      Trap exceptions.                                                */
831
    /* -------------------------------------------------------------------- */
832
    catch (const PCIDSKException &ex)
833
    {
834
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
835
    }
836
    catch (...)
837
    {
838
        CPLError(CE_Failure, CPLE_AppDefined,
839
                 "PCIDSK SDK Failure in Close(), unexpected exception.");
840
    }
841

842
    CSLDestroy(papszLastMDListValue);
245✔
843
}
490✔
844
#ifdef _MSC_VER
845
#pragma warning(pop)
846
#endif
847

848
/************************************************************************/
849
/*                            GetFileList()                             */
850
/************************************************************************/
851

852
char **PCIDSK2Dataset::GetFileList()
57✔
853

854
{
855
    char **papszFileList = GDALPamDataset::GetFileList();
57✔
856
    CPLString osBaseDir = CPLGetPathSafe(GetDescription());
114✔
857

858
    try
859
    {
860
        for (int nChan = 1; nChan <= poFile->GetChannels(); nChan++)
77✔
861
        {
862
            PCIDSKChannel *poChannel = poFile->GetChannel(nChan);
20✔
863
            CPLString osChanFilename;
40✔
864
            uint64 image_offset, pixel_offset, line_offset;
865
            bool little_endian;
866

867
            poChannel->GetChanInfo(osChanFilename, image_offset, pixel_offset,
20✔
868
                                   line_offset, little_endian);
20✔
869

870
            if (osChanFilename != "")
20✔
871
            {
872
                papszFileList = CSLAddString(
1✔
873
                    papszFileList,
874
                    CPLProjectRelativeFilenameSafe(osBaseDir, osChanFilename)
2✔
875
                        .c_str());
876
            }
877
        }
878

879
        return papszFileList;
57✔
880
    }
881
    catch (const PCIDSKException &ex)
×
882
    {
883
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
884
        return papszFileList;
×
885
    }
886
}
887

888
/************************************************************************/
889
/*                             ProcessRPC()                             */
890
/************************************************************************/
891

892
void PCIDSK2Dataset::ProcessRPC()
245✔
893

894
{
895
    /* -------------------------------------------------------------------- */
896
    /*      Search all BIN segments looking for an RPC segment.             */
897
    /* -------------------------------------------------------------------- */
898
    PCIDSKSegment *poSeg = poFile->GetSegment(SEG_BIN, "");
245✔
899
    PCIDSKRPCSegment *poRPCSeg = nullptr;
245✔
900

901
    while (poSeg != nullptr &&
245✔
902
           (poRPCSeg = dynamic_cast<PCIDSKRPCSegment *>(poSeg)) == nullptr)
×
903

904
    {
905
        poSeg = poFile->GetSegment(SEG_BIN, "", poSeg->GetSegmentNumber());
×
906
    }
907

908
    if (poRPCSeg == nullptr)
245✔
909
        return;
245✔
910

911
    /* -------------------------------------------------------------------- */
912
    /*      Turn RPC segment into GDAL RFC 22 style metadata.               */
913
    /* -------------------------------------------------------------------- */
914
    try
915
    {
916
        CPLString osValue;
×
917
        double dfLineOffset, dfLineScale, dfSampOffset, dfSampScale;
918
        double dfLatOffset, dfLatScale, dfLongOffset, dfLongScale,
919
            dfHeightOffset, dfHeightScale;
920

921
        poRPCSeg->GetRPCTranslationCoeffs(
×
922
            dfLongOffset, dfLongScale, dfLatOffset, dfLatScale, dfHeightOffset,
923
            dfHeightScale, dfSampOffset, dfSampScale, dfLineOffset,
924
            dfLineScale);
×
925

926
        osValue.Printf("%.16g", dfLineOffset);
×
927
        GDALPamDataset::SetMetadataItem("LINE_OFF", osValue, "RPC");
×
928

929
        osValue.Printf("%.16g", dfLineScale);
×
930
        GDALPamDataset::SetMetadataItem("LINE_SCALE", osValue, "RPC");
×
931

932
        osValue.Printf("%.16g", dfSampOffset);
×
933
        GDALPamDataset::SetMetadataItem("SAMP_OFF", osValue, "RPC");
×
934

935
        osValue.Printf("%.16g", dfSampScale);
×
936
        GDALPamDataset::SetMetadataItem("SAMP_SCALE", osValue, "RPC");
×
937

938
        osValue.Printf("%.16g", dfLongOffset);
×
939
        GDALPamDataset::SetMetadataItem("LONG_OFF", osValue, "RPC");
×
940

941
        osValue.Printf("%.16g", dfLongScale);
×
942
        GDALPamDataset::SetMetadataItem("LONG_SCALE", osValue, "RPC");
×
943

944
        osValue.Printf("%.16g", dfLatOffset);
×
945
        GDALPamDataset::SetMetadataItem("LAT_OFF", osValue, "RPC");
×
946

947
        osValue.Printf("%.16g", dfLatScale);
×
948
        GDALPamDataset::SetMetadataItem("LAT_SCALE", osValue, "RPC");
×
949

950
        osValue.Printf("%.16g", dfHeightOffset);
×
951
        GDALPamDataset::SetMetadataItem("HEIGHT_OFF", osValue, "RPC");
×
952

953
        osValue.Printf("%.16g", dfHeightScale);
×
954
        GDALPamDataset::SetMetadataItem("HEIGHT_SCALE", osValue, "RPC");
×
955

956
        if (poRPCSeg->GetXNumerator().size() != 20 ||
×
957
            poRPCSeg->GetXDenominator().size() != 20 ||
×
958
            poRPCSeg->GetYNumerator().size() != 20 ||
×
959
            poRPCSeg->GetYDenominator().size() != 20)
×
960
        {
961
            GDALPamDataset::SetMetadata(nullptr, "RPC");
×
962
            CPLError(CE_Failure, CPLE_AppDefined,
×
963
                     "Did not get 20 values in the RPC coefficients lists.");
964
            return;
×
965
        }
966

967
        std::vector<double> adfCoef = poRPCSeg->GetYNumerator();
×
968
        CPLString osCoefList = "";
×
969
        for (int i = 0; i < 20; i++)
×
970
        {
971
            osValue.Printf("%.16g ", adfCoef[i]);
×
972
            osCoefList += osValue;
×
973
        }
974
        GDALPamDataset::SetMetadataItem("LINE_NUM_COEFF", osCoefList, "RPC");
×
975

976
        adfCoef = poRPCSeg->GetYDenominator();
×
977
        osCoefList = "";
×
978
        for (int i = 0; i < 20; i++)
×
979
        {
980
            osValue.Printf("%.16g ", adfCoef[i]);
×
981
            osCoefList += osValue;
×
982
        }
983
        GDALPamDataset::SetMetadataItem("LINE_DEN_COEFF", osCoefList, "RPC");
×
984

985
        adfCoef = poRPCSeg->GetXNumerator();
×
986
        osCoefList = "";
×
987
        for (int i = 0; i < 20; i++)
×
988
        {
989
            osValue.Printf("%.16g ", adfCoef[i]);
×
990
            osCoefList += osValue;
×
991
        }
992
        GDALPamDataset::SetMetadataItem("SAMP_NUM_COEFF", osCoefList, "RPC");
×
993

994
        adfCoef = poRPCSeg->GetXDenominator();
×
995
        osCoefList = "";
×
996
        for (int i = 0; i < 20; i++)
×
997
        {
998
            osValue.Printf("%.16g ", adfCoef[i]);
×
999
            osCoefList += osValue;
×
1000
        }
1001
        GDALPamDataset::SetMetadataItem("SAMP_DEN_COEFF", osCoefList, "RPC");
×
1002
    }
1003
    catch (const PCIDSKException &ex)
×
1004
    {
1005
        GDALPamDataset::SetMetadata(nullptr, "RPC");
×
1006
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
1007
    }
1008
}
1009

1010
/************************************************************************/
1011
/*                             FlushCache()                             */
1012
/************************************************************************/
1013

1014
CPLErr PCIDSK2Dataset::FlushCache(bool bAtClosing)
257✔
1015

1016
{
1017
    CPLErr eErr = GDALPamDataset::FlushCache(bAtClosing);
257✔
1018

1019
    if (poFile)
257✔
1020
    {
1021
        try
1022
        {
1023
            poFile->Synchronize();
257✔
1024
        }
1025
        catch (const PCIDSKException &ex)
×
1026
        {
1027
            eErr = CE_Failure;
×
1028
            CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
1029
        }
1030
    }
1031
    return eErr;
257✔
1032
}
1033

1034
/************************************************************************/
1035
/*                            SetMetadata()                             */
1036
/************************************************************************/
1037

1038
CPLErr PCIDSK2Dataset::SetMetadata(char **papszMD, const char *pszDomain)
26✔
1039

1040
{
1041
    /* -------------------------------------------------------------------- */
1042
    /*      PCIDSK only supports metadata in the default domain.            */
1043
    /* -------------------------------------------------------------------- */
1044
    if (pszDomain != nullptr && strlen(pszDomain) > 0)
26✔
1045
        return GDALPamDataset::SetMetadata(papszMD, pszDomain);
×
1046

1047
    /* -------------------------------------------------------------------- */
1048
    /*      Set each item individually.                                     */
1049
    /* -------------------------------------------------------------------- */
1050
    CSLDestroy(papszLastMDListValue);
26✔
1051
    papszLastMDListValue = nullptr;
26✔
1052
    m_oCacheMetadataItem.clear();
26✔
1053

1054
    if (GetAccess() == GA_ReadOnly)
26✔
1055
    {
1056
        CPLError(CE_Failure, CPLE_NoWriteAccess,
×
1057
                 "Unable to set metadata on read-only file.");
1058
        return CE_Failure;
×
1059
    }
1060

1061
    try
1062
    {
1063
        for (int iItem = 0; papszMD && papszMD[iItem]; iItem++)
59✔
1064
        {
1065
            char *pszItemName = nullptr;
33✔
1066
            const char *pszItemValue =
1067
                CPLParseNameValue(papszMD[iItem], &pszItemName);
33✔
1068
            if (pszItemName != nullptr)
33✔
1069
            {
1070
                poFile->SetMetadataValue(pszItemName, pszItemValue);
17✔
1071
                CPLFree(pszItemName);
17✔
1072
            }
1073
        }
1074
    }
1075
    catch (const PCIDSKException &ex)
×
1076
    {
1077
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
1078
        return CE_Failure;
×
1079
    }
1080

1081
    return CE_None;
26✔
1082
}
1083

1084
/************************************************************************/
1085
/*                          SetMetadataItem()                           */
1086
/************************************************************************/
1087

1088
CPLErr PCIDSK2Dataset::SetMetadataItem(const char *pszName,
222✔
1089
                                       const char *pszValue,
1090
                                       const char *pszDomain)
1091

1092
{
1093
    /* -------------------------------------------------------------------- */
1094
    /*      PCIDSK only supports metadata in the default domain.            */
1095
    /* -------------------------------------------------------------------- */
1096
    if (pszDomain != nullptr && strlen(pszDomain) > 0)
222✔
1097
        return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
218✔
1098

1099
    /* -------------------------------------------------------------------- */
1100
    /*      Set on the file.                                                */
1101
    /* -------------------------------------------------------------------- */
1102
    CSLDestroy(papszLastMDListValue);
4✔
1103
    papszLastMDListValue = nullptr;
4✔
1104
    m_oCacheMetadataItem.clear();
4✔
1105

1106
    if (GetAccess() == GA_ReadOnly)
4✔
1107
    {
1108
        CPLError(CE_Failure, CPLE_NoWriteAccess,
×
1109
                 "Unable to set metadata on read-only file.");
1110
        return CE_Failure;
×
1111
    }
1112

1113
    try
1114
    {
1115
        poFile->SetMetadataValue(pszName, pszValue);
4✔
1116
    }
1117
    catch (const PCIDSKException &ex)
×
1118
    {
1119
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
1120
        return CE_Failure;
×
1121
    }
1122

1123
    return CE_None;
4✔
1124
}
1125

1126
/************************************************************************/
1127
/*                      GetMetadataDomainList()                         */
1128
/************************************************************************/
1129

1130
char **PCIDSK2Dataset::GetMetadataDomainList()
×
1131
{
1132
    return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(),
×
1133
                                   TRUE, "", nullptr);
×
1134
}
1135

1136
/************************************************************************/
1137
/*                          GetMetadataItem()                           */
1138
/************************************************************************/
1139

1140
const char *PCIDSK2Dataset::GetMetadataItem(const char *pszName,
1,240✔
1141
                                            const char *pszDomain)
1142

1143
{
1144
    /* -------------------------------------------------------------------- */
1145
    /*      PCIDSK only supports metadata in the default domain.            */
1146
    /* -------------------------------------------------------------------- */
1147
    if (pszDomain != nullptr && strlen(pszDomain) > 0)
1,240✔
1148
        return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
97✔
1149

1150
    /* -------------------------------------------------------------------- */
1151
    /*      Try and fetch (use cached value if available)                   */
1152
    /* -------------------------------------------------------------------- */
1153
    auto oIter = m_oCacheMetadataItem.find(pszName);
1,143✔
1154
    if (oIter != m_oCacheMetadataItem.end())
1,143✔
1155
    {
1156
        return oIter->second.empty() ? nullptr : oIter->second.c_str();
1,054✔
1157
    }
1158

1159
    CPLString osValue;
178✔
1160
    try
1161
    {
1162
        osValue = poFile->GetMetadataValue(pszName);
89✔
1163
    }
1164
    catch (const PCIDSKException &ex)
×
1165
    {
1166
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
1167
        return nullptr;
×
1168
    }
1169

1170
    oIter = m_oCacheMetadataItem
89✔
1171
                .insert(std::pair<std::string, std::string>(pszName, osValue))
89✔
1172
                .first;
1173
    return oIter->second.empty() ? nullptr : oIter->second.c_str();
89✔
1174
}
1175

1176
/************************************************************************/
1177
/*                            GetMetadata()                             */
1178
/************************************************************************/
1179

1180
char **PCIDSK2Dataset::GetMetadata(const char *pszDomain)
52✔
1181

1182
{
1183
    /* -------------------------------------------------------------------- */
1184
    /*      PCIDSK only supports metadata in the default domain.            */
1185
    /* -------------------------------------------------------------------- */
1186
    if (pszDomain != nullptr && strlen(pszDomain) > 0)
52✔
1187
        return GDALPamDataset::GetMetadata(pszDomain);
25✔
1188

1189
    /* -------------------------------------------------------------------- */
1190
    /*      If we have a cached result, just use that.                      */
1191
    /* -------------------------------------------------------------------- */
1192
    if (papszLastMDListValue != nullptr)
27✔
1193
        return papszLastMDListValue;
3✔
1194

1195
    /* -------------------------------------------------------------------- */
1196
    /*      Fetch and build the list.                                       */
1197
    /* -------------------------------------------------------------------- */
1198
    try
1199
    {
1200
        std::vector<std::string> aosKeys = poFile->GetMetadataKeys();
48✔
1201

1202
        for (unsigned int i = 0; i < aosKeys.size(); i++)
38✔
1203
        {
1204
            if (aosKeys[i].c_str()[0] == '_')
14✔
1205
                continue;
2✔
1206

1207
            papszLastMDListValue =
12✔
1208
                CSLSetNameValue(papszLastMDListValue, aosKeys[i].c_str(),
12✔
1209
                                poFile->GetMetadataValue(aosKeys[i]).c_str());
24✔
1210
        }
1211
    }
1212
    catch (const PCIDSKException &ex)
×
1213
    {
1214
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
1215
        return nullptr;
×
1216
    }
1217

1218
    return papszLastMDListValue;
24✔
1219
}
1220

1221
/************************************************************************/
1222
/*                          SetGeoTransform()                           */
1223
/************************************************************************/
1224

1225
CPLErr PCIDSK2Dataset::SetGeoTransform(const GDALGeoTransform &gt)
58✔
1226
{
1227
    PCIDSKGeoref *poGeoref = nullptr;
58✔
1228
    try
1229
    {
1230
        PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
58✔
1231
        poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
58✔
1232
    }
1233
    catch (const PCIDSKException &)
×
1234
    {
1235
        // I should really check whether this is an expected issue.
1236
    }
1237

1238
    if (poGeoref == nullptr)
58✔
1239
        return GDALPamDataset::SetGeoTransform(gt);
×
1240

1241
    if (GetAccess() == GA_ReadOnly)
58✔
1242
    {
1243
        CPLError(CE_Failure, CPLE_NoWriteAccess,
×
1244
                 "Unable to set GeoTransform on read-only file.");
1245
        return CE_Failure;
×
1246
    }
1247

1248
    try
1249
    {
1250
        poGeoref->WriteSimple(poGeoref->GetGeosys(), gt[0], gt[1], gt[2], gt[3],
58✔
1251
                              gt[4], gt[5]);
58✔
1252
    }
1253
    catch (const PCIDSKException &ex)
×
1254
    {
1255
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
1256
        return CE_Failure;
×
1257
    }
1258

1259
    return CE_None;
58✔
1260
}
1261

1262
/************************************************************************/
1263
/*                          GetGeoTransform()                           */
1264
/************************************************************************/
1265

1266
CPLErr PCIDSK2Dataset::GetGeoTransform(GDALGeoTransform &gt) const
44✔
1267
{
1268
    PCIDSKGeoref *poGeoref = nullptr;
44✔
1269
    try
1270
    {
1271
        PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
44✔
1272
        poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
44✔
1273
    }
1274
    catch (const PCIDSKException &)
×
1275
    {
1276
        // I should really check whether this is an expected issue.
1277
    }
1278

1279
    if (poGeoref != nullptr)
44✔
1280
    {
1281
        try
1282
        {
1283
            poGeoref->GetTransform(gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]);
44✔
1284
        }
1285
        catch (const PCIDSKException &ex)
×
1286
        {
1287
            CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
1288
            return CE_Failure;
×
1289
        }
1290

1291
        // If we got anything non-default return it.
1292
        if (gt != GDALGeoTransform())
44✔
1293
            return CE_None;
41✔
1294
    }
1295

1296
    /* -------------------------------------------------------------------- */
1297
    /*      Check for worldfile if we have no other georeferencing.         */
1298
    /* -------------------------------------------------------------------- */
1299
    if (GDALReadWorldFile(GetDescription(), "pxw", gt.data()))
3✔
1300
        return CE_None;
×
1301

1302
    return GDALPamDataset::GetGeoTransform(gt);
3✔
1303
}
1304

1305
/************************************************************************/
1306
/*                           SetSpatialRef()                            */
1307
/************************************************************************/
1308

1309
CPLErr PCIDSK2Dataset::SetSpatialRef(const OGRSpatialReference *poSRS)
58✔
1310

1311
{
1312
    PCIDSKGeoref *poGeoref = nullptr;
58✔
1313

1314
    try
1315
    {
1316
        PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
58✔
1317
        poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
58✔
1318
    }
1319
    catch (const PCIDSKException &)
×
1320
    {
1321
        // I should really check whether this is an expected issue.
1322
    }
1323

1324
    if (poGeoref == nullptr)
58✔
1325
    {
1326
        return GDALPamDataset::SetSpatialRef(poSRS);
×
1327
    }
1328

1329
    char *pszGeosys = nullptr;
58✔
1330
    char *pszUnits = nullptr;
58✔
1331
    double *padfPrjParams = nullptr;
58✔
1332

1333
    if (poSRS == nullptr || poSRS->exportToPCI(&pszGeosys, &pszUnits,
58✔
1334
                                               &padfPrjParams) != OGRERR_NONE)
1335
    {
1336
        return GDALPamDataset::SetSpatialRef(poSRS);
×
1337
    }
1338

1339
    if (GetAccess() == GA_ReadOnly)
58✔
1340
    {
1341
        CPLError(CE_Failure, CPLE_NoWriteAccess,
×
1342
                 "Unable to set projection on read-only file.");
1343
        CPLFree(pszGeosys);
×
1344
        CPLFree(pszUnits);
×
1345
        CPLFree(padfPrjParams);
×
1346
        return CE_Failure;
×
1347
    }
1348

1349
    try
1350
    {
1351
        double adfGT[6];
1352
        poGeoref->GetTransform(adfGT[0], adfGT[1], adfGT[2], adfGT[3], adfGT[4],
58✔
1353
                               adfGT[5]);
58✔
1354

1355
        poGeoref->WriteSimple(pszGeosys, adfGT[0], adfGT[1], adfGT[2], adfGT[3],
58✔
1356
                              adfGT[4], adfGT[5]);
58✔
1357

1358
        std::vector<double> adfPCIParameters;
116✔
1359
        for (unsigned int i = 0; i < 17; i++)
1,044✔
1360
            adfPCIParameters.push_back(padfPrjParams[i]);
986✔
1361

1362
        if (STARTS_WITH_CI(pszUnits, "FOOT"))
58✔
1363
            adfPCIParameters.push_back(
×
1364
                static_cast<double>(static_cast<int>(PCIDSK::UNIT_US_FOOT)));
×
1365
        else if (EQUALN(pszUnits, "INTL FOOT", 9))
58✔
1366
            adfPCIParameters.push_back(
×
1367
                static_cast<double>(static_cast<int>(PCIDSK::UNIT_INTL_FOOT)));
×
1368
        else if (EQUALN(pszUnits, "DEGREE", 6))
58✔
1369
            adfPCIParameters.push_back(
50✔
1370
                static_cast<double>(static_cast<int>(PCIDSK::UNIT_DEGREE)));
50✔
1371
        else
1372
            adfPCIParameters.push_back(
8✔
1373
                static_cast<double>(static_cast<int>(PCIDSK::UNIT_METER)));
8✔
1374

1375
        poGeoref->WriteParameters(adfPCIParameters);
58✔
1376
    }
1377
    catch (const PCIDSKException &ex)
×
1378
    {
1379
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
1380
        return CE_Failure;
×
1381
    }
1382

1383
    CPLFree(pszGeosys);
58✔
1384
    CPLFree(pszUnits);
58✔
1385
    CPLFree(padfPrjParams);
58✔
1386

1387
    return CE_None;
58✔
1388
}
1389

1390
/************************************************************************/
1391
/*                          GetSpatialRef()                             */
1392
/************************************************************************/
1393

1394
const OGRSpatialReference *PCIDSK2Dataset::GetSpatialRef() const
13✔
1395
{
1396
    if (m_poSRS)
13✔
1397
        return m_poSRS;
3✔
1398

1399
    PCIDSKGeoref *poGeoref = nullptr;
10✔
1400

1401
    try
1402
    {
1403
        PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
10✔
1404
        poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
10✔
1405
    }
1406
    catch (const PCIDSKException &)
×
1407
    {
1408
        // I should really check whether this is an expected issue.
1409
    }
1410

1411
    if (poGeoref == nullptr)
10✔
1412
    {
1413
        return GDALPamDataset::GetSpatialRef();
×
1414
    }
1415

1416
    CPLString osGeosys;
20✔
1417
    const char *pszUnits = nullptr;
10✔
1418

1419
    std::vector<double> adfParameters;
20✔
1420
    adfParameters.resize(18);
10✔
1421

1422
    try
1423
    {
1424
        osGeosys = poGeoref->GetGeosys();
10✔
1425
        adfParameters = poGeoref->GetParameters();
10✔
1426
        const UnitCode code =
1427
            static_cast<UnitCode>(static_cast<int>(adfParameters[16]));
10✔
1428

1429
        if (code == PCIDSK::UNIT_DEGREE)
10✔
1430
            pszUnits = "DEGREE";
×
1431
        else if (code == PCIDSK::UNIT_METER)
10✔
1432
            pszUnits = "METER";
×
1433
        else if (code == PCIDSK::UNIT_US_FOOT)
10✔
1434
            pszUnits = "FOOT";
×
1435
        else if (code == PCIDSK::UNIT_INTL_FOOT)
10✔
1436
            pszUnits = "INTL FOOT";
×
1437
    }
1438
    catch (const PCIDSKException &ex)
×
1439
    {
1440
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
1441
    }
1442

1443
    OGRSpatialReference oSRS;
20✔
1444
    oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
10✔
1445
    if (oSRS.importFromPCI(osGeosys, pszUnits, &(adfParameters[0])) ==
10✔
1446
        OGRERR_NONE)
1447
    {
1448
        m_poSRS = oSRS.Clone();
7✔
1449
        return m_poSRS;
7✔
1450
    }
1451
    else
1452
    {
1453
        return GDALPamDataset::GetSpatialRef();
3✔
1454
    }
1455
}
1456

1457
/************************************************************************/
1458
/*                          IBuildOverviews()                           */
1459
/************************************************************************/
1460

1461
CPLErr PCIDSK2Dataset::IBuildOverviews(
3✔
1462
    const char *pszResampling, int nOverviews, const int *panOverviewList,
1463
    int nListBands, const int *panBandList, GDALProgressFunc pfnProgress,
1464
    void *pProgressData, CSLConstList papszOptions)
1465

1466
{
1467
    PCIDSK2Band *poBand =
1468
        reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[0]));
3✔
1469

1470
    /* -------------------------------------------------------------------- */
1471
    /*      If RRD overviews requested, then invoke generic handling.       */
1472
    /* -------------------------------------------------------------------- */
1473
    bool bUseGenericHandling = false;
3✔
1474

1475
    if (CPLTestBool(CPLGetConfigOption("USE_RRD", "NO")))
3✔
1476
    {
1477
        bUseGenericHandling = true;
1✔
1478
    }
1479

1480
    /* -------------------------------------------------------------------- */
1481
    /*      If we don't have read access, then create the overviews         */
1482
    /*      externally.                                                     */
1483
    /* -------------------------------------------------------------------- */
1484
    if (GetAccess() != GA_Update)
3✔
1485
    {
1486
        CPLDebug("PCIDSK", "File open for read-only accessing, "
1✔
1487
                           "creating overviews externally.");
1488

1489
        bUseGenericHandling = true;
1✔
1490
    }
1491

1492
    if (bUseGenericHandling)
3✔
1493
    {
1494
        if (poBand->GetOverviewCount() != 0)
2✔
1495
        {
1496
            CPLError(CE_Failure, CPLE_NotSupported,
×
1497
                     "Cannot add external overviews when there are already "
1498
                     "internal overviews");
1499
            return CE_Failure;
×
1500
        }
1501

1502
        return GDALDataset::IBuildOverviews(
2✔
1503
            pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
1504
            pfnProgress, pProgressData, papszOptions);
2✔
1505
    }
1506

1507
    if (nListBands == 0)
1✔
1508
        return CE_None;
×
1509

1510
    /* -------------------------------------------------------------------- */
1511
    /*      Currently no support for clearing overviews.                    */
1512
    /* -------------------------------------------------------------------- */
1513
    if (nOverviews == 0)
1✔
1514
    {
1515
        CPLError(CE_Failure, CPLE_AppDefined,
×
1516
                 "PCIDSK2 driver does not currently support clearing existing "
1517
                 "overviews. ");
1518
        return CE_Failure;
×
1519
    }
1520

1521
    /* -------------------------------------------------------------------- */
1522
    /*      Establish which of the overview levels we already have, and     */
1523
    /*      which are new.  We assume that band 1 of the file is            */
1524
    /*      representative.                                                 */
1525
    /* -------------------------------------------------------------------- */
1526

1527
    int nNewOverviews = 0;
1✔
1528
    int *panNewOverviewList =
1529
        reinterpret_cast<int *>(CPLCalloc(sizeof(int), nOverviews));
1✔
1530
    std::vector<bool> abFoundOverviewFactor(nOverviews);
2✔
1531
    for (int i = 0; i < nOverviews && poBand != nullptr; i++)
2✔
1532
    {
1533
        for (int j = 0; j < poBand->GetOverviewCount(); j++)
1✔
1534
        {
1535
            GDALRasterBand *poOverview = poBand->GetOverview(j);
×
1536

1537
            int nOvFactor =
1538
                GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(),
×
1539
                                    poOverview->GetYSize(), poBand->GetYSize());
1540

1541
            if (nOvFactor == panOverviewList[i] ||
×
1542
                nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
×
1543
                                                poBand->GetXSize(),
1544
                                                poBand->GetYSize()))
1545
                abFoundOverviewFactor[i] = true;
×
1546
        }
1547

1548
        if (!abFoundOverviewFactor[i])
1✔
1549
            panNewOverviewList[nNewOverviews++] = panOverviewList[i];
1✔
1550
    }
1551

1552
    /* -------------------------------------------------------------------- */
1553
    /*      Create the overviews that are missing.                          */
1554
    /* -------------------------------------------------------------------- */
1555
    for (int i = 0; i < nNewOverviews; i++)
2✔
1556
    {
1557
        try
1558
        {
1559
            // conveniently our resampling values mostly match PCIDSK.
1560
            poFile->CreateOverviews(nListBands, panBandList,
2✔
1561
                                    panNewOverviewList[i], pszResampling);
2✔
1562
        }
1563
        catch (const PCIDSKException &ex)
×
1564
        {
1565
            CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
1566
            CPLFree(panNewOverviewList);
×
1567
            return CE_Failure;
×
1568
        }
1569
    }
1570

1571
    CPLFree(panNewOverviewList);
1✔
1572
    panNewOverviewList = nullptr;
1✔
1573

1574
    for (int iBand = 0; iBand < nListBands; iBand++)
2✔
1575
    {
1576
        poBand =
1577
            reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[iBand]));
1✔
1578
        reinterpret_cast<PCIDSK2Band *>(poBand)->RefreshOverviewList();
1✔
1579
    }
1580

1581
    /* -------------------------------------------------------------------- */
1582
    /*      Actually generate the overview imagery.                         */
1583
    /* -------------------------------------------------------------------- */
1584
    CPLErr eErr = CE_None;
1✔
1585
    std::vector<int> anRegenLevels;
1✔
1586

1587
    GDALRasterBand **papoOverviewBands = reinterpret_cast<GDALRasterBand **>(
1588
        CPLCalloc(sizeof(void *), nOverviews));
1✔
1589

1590
    for (int iBand = 0; iBand < nListBands && eErr == CE_None; iBand++)
2✔
1591
    {
1592
        nNewOverviews = 0;
1✔
1593

1594
        poBand =
1595
            reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[iBand]));
1✔
1596

1597
        for (int i = 0; i < nOverviews && poBand != nullptr; i++)
2✔
1598
        {
1599
            for (int j = 0; j < poBand->GetOverviewCount(); j++)
1✔
1600
            {
1601
                GDALRasterBand *poOverview = poBand->GetOverview(j);
1✔
1602

1603
                int nOvFactor = GDALComputeOvFactor(
1✔
1604
                    poOverview->GetXSize(), poBand->GetXSize(),
1605
                    poOverview->GetYSize(), poBand->GetYSize());
1606

1607
                if (nOvFactor == panOverviewList[i] ||
1✔
1608
                    nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
×
1609
                                                    poBand->GetXSize(),
1610
                                                    poBand->GetYSize()))
1611
                {
1612
                    papoOverviewBands[nNewOverviews++] = poOverview;
1✔
1613
                    anRegenLevels.push_back(j);
1✔
1614
                    break;
1✔
1615
                }
1616
            }
1617
        }
1618

1619
        if (nNewOverviews > 0)
1✔
1620
        {
1621
            eErr = GDALRegenerateOverviewsEx(
1✔
1622
                (GDALRasterBandH)poBand, nNewOverviews,
1623
                reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
1624
                pszResampling, pfnProgress, pProgressData, papszOptions);
1625

1626
            // Mark the regenerated overviews as valid.
1627
            for (int i = 0; i < static_cast<int>(anRegenLevels.size()); i++)
2✔
1628
                poBand->poChannel->SetOverviewValidity(anRegenLevels[i], true);
1✔
1629
        }
1630
    }
1631

1632
    CPLFree(papoOverviewBands);
1✔
1633

1634
    return eErr;
1✔
1635
}
1636

1637
/************************************************************************/
1638
/*                         PCIDSKTypeToGDAL()                           */
1639
/************************************************************************/
1640

1641
GDALDataType PCIDSK2Dataset::PCIDSKTypeToGDAL(eChanType eType)
477✔
1642
{
1643
    switch (eType)
477✔
1644
    {
1645
        case CHN_8U:
339✔
1646
            return GDT_Byte;
339✔
1647

1648
        case CHN_16U:
66✔
1649
            return GDT_UInt16;
66✔
1650

1651
        case CHN_16S:
18✔
1652
            return GDT_Int16;
18✔
1653

1654
        case CHN_32R:
18✔
1655
            return GDT_Float32;
18✔
1656

1657
        case CHN_BIT:
×
1658
            return GDT_Byte;
×
1659

1660
        case CHN_C16U:
×
1661
            return GDT_CInt16;
×
1662

1663
        case CHN_C16S:
18✔
1664
            return GDT_CInt16;
18✔
1665

1666
        case CHN_C32R:
18✔
1667
            return GDT_CFloat32;
18✔
1668

1669
        default:
×
1670
            return GDT_Unknown;
×
1671
    }
1672
}
1673

1674
/************************************************************************/
1675
/*                                Open()                                */
1676
/************************************************************************/
1677

1678
GDALDataset *PCIDSK2Dataset::Open(GDALOpenInfo *poOpenInfo)
138✔
1679
{
1680
    if (!PCIDSKDriverIdentify(poOpenInfo))
138✔
1681
        return nullptr;
×
1682

1683
    /* -------------------------------------------------------------------- */
1684
    /*      Try opening the file.                                           */
1685
    /* -------------------------------------------------------------------- */
1686
    PCIDSKFile *poFile = nullptr;
138✔
1687
    const int nMaxBandCount =
1688
        atoi(CPLGetConfigOption("GDAL_MAX_BAND_COUNT", "65536"));
138✔
1689
    try
1690
    {
1691
        poFile = PCIDSK::Open(poOpenInfo->pszFilename,
280✔
1692
                              poOpenInfo->eAccess == GA_ReadOnly ? "r" : "r+",
138✔
1693
                              PCIDSK2GetInterfaces(), nMaxBandCount);
1694
        if (poFile == nullptr)
137✔
1695
        {
1696
            CPLError(CE_Failure, CPLE_OpenFailed,
×
1697
                     "Failed to re-open %s within PCIDSK driver.\n",
1698
                     poOpenInfo->pszFilename);
1699
            return nullptr;
×
1700
        }
1701

1702
        const bool bValidRasterDimensions =
1703
            poFile->GetWidth() && poFile->GetHeight();
137✔
1704
        if (!bValidRasterDimensions &&
137✔
1705
            (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
×
1706
            (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0)
×
1707
        {
1708
            delete poFile;
×
1709
            return nullptr;
×
1710
        }
1711

1712
        /* Check if this is a vector-only PCIDSK file and that we are */
1713
        /* opened in raster-only mode */
1714
        if (poOpenInfo->eAccess == GA_ReadOnly &&
404✔
1715
            (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
130✔
1716
            (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0 &&
120✔
1717
            poFile->GetChannels() == 0 &&
270✔
1718
            poFile->GetSegment(PCIDSK::SEG_VEC, "") != nullptr)
140✔
1719
        {
1720
            CPLDebug("PCIDSK",
2✔
1721
                     "This is a vector-only PCIDSK dataset, "
1722
                     "but it has been opened in read-only in raster-only mode");
1723
            delete poFile;
2✔
1724
            return nullptr;
2✔
1725
        }
1726
        /* Reverse test */
1727
        if (poOpenInfo->eAccess == GA_ReadOnly &&
398✔
1728
            (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
128✔
1729
            (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
10✔
1730
            poFile->GetChannels() != 0 &&
263✔
1731
            poFile->GetSegment(PCIDSK::SEG_VEC, "") == nullptr)
135✔
1732
        {
1733
            CPLDebug("PCIDSK",
×
1734
                     "This is a raster-only PCIDSK dataset, "
1735
                     "but it has been opened in read-only in vector-only mode");
1736
            delete poFile;
×
1737
            return nullptr;
×
1738
        }
1739

1740
        return LLOpen(poOpenInfo->pszFilename, poFile, poOpenInfo->eAccess,
135✔
1741
                      poOpenInfo->GetSiblingFiles());
135✔
1742
    }
1743
    /* -------------------------------------------------------------------- */
1744
    /*      Trap exceptions.                                                */
1745
    /* -------------------------------------------------------------------- */
1746
    catch (const PCIDSKException &ex)
1✔
1747
    {
1748
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1✔
1749
        delete poFile;
1✔
1750
        return nullptr;
1✔
1751
    }
1752
    catch (...)
×
1753
    {
1754
        CPLError(CE_Failure, CPLE_AppDefined,
×
1755
                 "PCIDSK::Create() failed, unexpected exception.");
1756
        delete poFile;
×
1757
        return nullptr;
×
1758
    }
1759
}
1760

1761
/************************************************************************/
1762
/*                               LLOpen()                               */
1763
/*                                                                      */
1764
/*      Low level variant of open that takes the preexisting            */
1765
/*      PCIDSKFile.                                                     */
1766
/************************************************************************/
1767

1768
GDALDataset *PCIDSK2Dataset::LLOpen(const char *pszFilename,
245✔
1769
                                    PCIDSK::PCIDSKFile *poFile,
1770
                                    GDALAccess eAccessIn,
1771
                                    char **papszSiblingFiles)
1772

1773
{
1774
    PCIDSK2Dataset *poDS = new PCIDSK2Dataset();
245✔
1775
    /* -------------------------------------------------------------------- */
1776
    /*      Create a corresponding GDALDataset.                             */
1777
    /* -------------------------------------------------------------------- */
1778
    poDS->poFile = poFile;
245✔
1779
    poDS->eAccess = eAccessIn;
245✔
1780
    poDS->nRasterXSize = poFile->GetWidth();
245✔
1781
    poDS->nRasterYSize = poFile->GetHeight();
245✔
1782

1783
    const bool bValidRasterDimensions =
1784
        poFile->GetWidth() && poFile->GetHeight();
245✔
1785
    if (!bValidRasterDimensions)
245✔
1786
    {
1787
        poDS->nRasterXSize = 512;
×
1788
        poDS->nRasterYSize = 512;
×
1789
    }
1790

1791
    try
1792
    {
1793

1794
        /* --------------------------------------------------------------------
1795
         */
1796
        /*      Are we specifically PIXEL or BAND interleaving? */
1797
        /*                                                                      */
1798
        /*      We don't set anything for FILE since it is harder to know if */
1799
        /*      this is tiled or what the on disk interleaving is. */
1800
        /* --------------------------------------------------------------------
1801
         */
1802
        if (EQUAL(poFile->GetInterleaving().c_str(), "PIXEL"))
245✔
1803
            poDS->SetMetadataItem("IMAGE_STRUCTURE", "PIXEL",
×
1804
                                  "IMAGE_STRUCTURE");
1805
        else if (EQUAL(poFile->GetInterleaving().c_str(), "BAND"))
245✔
1806
            poDS->SetMetadataItem("IMAGE_STRUCTURE", "BAND", "IMAGE_STRUCTURE");
217✔
1807

1808
        /* --------------------------------------------------------------------
1809
         */
1810
        /*      Create band objects. */
1811
        /* --------------------------------------------------------------------
1812
         */
1813
        for (int iBand = 0;
478✔
1814
             bValidRasterDimensions && iBand < poFile->GetChannels(); iBand++)
478✔
1815
        {
1816
            PCIDSKChannel *poChannel = poFile->GetChannel(iBand + 1);
233✔
1817
            if (poChannel->GetBlockWidth() <= 0 ||
466✔
1818
                poChannel->GetBlockHeight() <= 0)
233✔
1819
            {
1820
                delete poDS;
×
1821
                return nullptr;
×
1822
            }
1823

1824
            if (PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType()) ==
233✔
1825
                GDT_Unknown)
1826
            {
1827
                continue;
×
1828
            }
1829

1830
            poDS->SetBand(poDS->GetRasterCount() + 1,
233✔
1831
                          new PCIDSK2Band(poFile, poChannel));
233✔
1832
        }
1833

1834
        /* --------------------------------------------------------------------
1835
         */
1836
        /*      Create band objects for bitmap segments. */
1837
        /* --------------------------------------------------------------------
1838
         */
1839
        int nLastBitmapSegment = 0;
245✔
1840
        PCIDSKSegment *poBitSeg = nullptr;
245✔
1841

1842
        while (bValidRasterDimensions &&
490✔
1843
               (poBitSeg = poFile->GetSegment(SEG_BIT, "",
490✔
1844
                                              nLastBitmapSegment)) != nullptr)
245✔
1845
        {
1846
            PCIDSKChannel *poChannel = dynamic_cast<PCIDSKChannel *>(poBitSeg);
×
1847
            if (poChannel == nullptr || poChannel->GetBlockWidth() <= 0 ||
×
1848
                poChannel->GetBlockHeight() <= 0)
×
1849
            {
1850
                delete poDS;
×
1851
                return nullptr;
×
1852
            }
1853

1854
            if (PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType()) ==
×
1855
                GDT_Unknown)
1856
            {
1857
                continue;
×
1858
            }
1859

1860
            poDS->SetBand(poDS->GetRasterCount() + 1,
×
1861
                          new PCIDSK2Band(poChannel));
×
1862

1863
            nLastBitmapSegment = poBitSeg->GetSegmentNumber();
×
1864
        }
1865

1866
        /* --------------------------------------------------------------------
1867
         */
1868
        /*      Create vector layers from vector segments. */
1869
        /* --------------------------------------------------------------------
1870
         */
1871
        PCIDSK::PCIDSKSegment *segobj = poFile->GetSegment(PCIDSK::SEG_VEC, "");
245✔
1872
        for (; segobj != nullptr;
340✔
1873
             segobj = poFile->GetSegment(PCIDSK::SEG_VEC, "",
95✔
1874
                                         segobj->GetSegmentNumber()))
95✔
1875
        {
1876
            PCIDSK::PCIDSKVectorSegment *poVecSeg =
1877
                dynamic_cast<PCIDSK::PCIDSKVectorSegment *>(segobj);
95✔
1878
            if (poVecSeg)
95✔
1879
                poDS->apoLayers.push_back(new OGRPCIDSKLayer(
95✔
1880
                    poDS, segobj, poVecSeg, eAccessIn == GA_Update));
95✔
1881
        }
1882

1883
        /* --------------------------------------------------------------------
1884
         */
1885
        /*      Process RPC segment, if there is one. */
1886
        /* --------------------------------------------------------------------
1887
         */
1888
        poDS->ProcessRPC();
245✔
1889

1890
        /* --------------------------------------------------------------------
1891
         */
1892
        /*      Initialize any PAM information. */
1893
        /* --------------------------------------------------------------------
1894
         */
1895
        poDS->SetDescription(pszFilename);
245✔
1896
        poDS->TryLoadXML(papszSiblingFiles);
245✔
1897

1898
        /* --------------------------------------------------------------------
1899
         */
1900
        /*      Open overviews. */
1901
        /* --------------------------------------------------------------------
1902
         */
1903
        poDS->oOvManager.Initialize(poDS, pszFilename, papszSiblingFiles);
245✔
1904

1905
        return poDS;
245✔
1906
    }
1907

1908
    /* -------------------------------------------------------------------- */
1909
    /*      Trap exceptions.                                                */
1910
    /* -------------------------------------------------------------------- */
1911
    catch (const PCIDSKException &ex)
×
1912
    {
1913
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
1914
    }
1915
    catch (...)
×
1916
    {
1917
        CPLError(CE_Failure, CPLE_AppDefined,
×
1918
                 "PCIDSK SDK Failure in Open(), unexpected exception.");
1919
    }
1920

1921
    /* -------------------------------------------------------------------- */
1922
    /*      In case of exception, close dataset                             */
1923
    /* -------------------------------------------------------------------- */
1924
    delete poDS;
×
1925

1926
    return nullptr;
×
1927
}
1928

1929
/************************************************************************/
1930
/*                               Create()                               */
1931
/************************************************************************/
1932

1933
GDALDataset *PCIDSK2Dataset::Create(const char *pszFilename, int nXSize,
124✔
1934
                                    int nYSize, int nBandsIn,
1935
                                    GDALDataType eType, char **papszParamList)
1936

1937
{
1938
    /* -------------------------------------------------------------------- */
1939
    /*      Prepare channel type list.                                      */
1940
    /* -------------------------------------------------------------------- */
1941
    std::vector<eChanType> aeChanTypes;
248✔
1942

1943
    if (eType == GDT_Float32)
124✔
1944
        aeChanTypes.resize(std::max(1, nBandsIn), CHN_32R);
3✔
1945
    else if (eType == GDT_Int16)
121✔
1946
        aeChanTypes.resize(std::max(1, nBandsIn), CHN_16S);
3✔
1947
    else if (eType == GDT_UInt16)
118✔
1948
        aeChanTypes.resize(std::max(1, nBandsIn), CHN_16U);
11✔
1949
    else if (eType == GDT_CInt16)
107✔
1950
        aeChanTypes.resize(std::max(1, nBandsIn), CHN_C16S);
3✔
1951
    else if (eType == GDT_CFloat32)
104✔
1952
        aeChanTypes.resize(std::max(1, nBandsIn), CHN_C32R);
3✔
1953
    else
1954
        aeChanTypes.resize(std::max(1, nBandsIn), CHN_8U);
101✔
1955

1956
    /* -------------------------------------------------------------------- */
1957
    /*      Reformat options.  Currently no support for jpeg compression    */
1958
    /*      quality.                                                        */
1959
    /* -------------------------------------------------------------------- */
1960
    CPLString osOptions;
248✔
1961
    const char *pszValue = CSLFetchNameValue(papszParamList, "INTERLEAVING");
124✔
1962
    if (pszValue == nullptr)
124✔
1963
        pszValue = "BAND";
116✔
1964

1965
    osOptions = pszValue;
124✔
1966

1967
    if (osOptions == "TILED")
124✔
1968
    {
1969
        pszValue = CSLFetchNameValue(papszParamList, "TILESIZE");
7✔
1970
        if (pszValue != nullptr)
7✔
1971
            osOptions += pszValue;
6✔
1972

1973
        pszValue = CSLFetchNameValue(papszParamList, "COMPRESSION");
7✔
1974
        if (pszValue != nullptr)
7✔
1975
        {
1976
            osOptions += " ";
4✔
1977
            osOptions += pszValue;
4✔
1978
        }
1979

1980
        pszValue = CSLFetchNameValue(papszParamList, "TILEVERSION");
7✔
1981
        if (pszValue != nullptr)
7✔
1982
        {
1983
            osOptions += " TILEV";
4✔
1984
            osOptions += pszValue;
4✔
1985
        }
1986
    }
1987

1988
    /* -------------------------------------------------------------------- */
1989
    /*      Try creation.                                                   */
1990
    /* -------------------------------------------------------------------- */
1991

1992
    try
1993
    {
1994
        if (nBandsIn == 0)
124✔
1995
        {
1996
            nXSize = 512;
43✔
1997
            nYSize = 512;
43✔
1998
        }
1999
        PCIDSKFile *poFile = PCIDSK::Create(pszFilename, nXSize, nYSize,
276✔
2000
                                            nBandsIn, &(aeChanTypes[0]),
124✔
2001
                                            osOptions, PCIDSK2GetInterfaces());
2002

2003
        /* --------------------------------------------------------------------
2004
         */
2005
        /*      Apply band descriptions, if provided as creation options. */
2006
        /* --------------------------------------------------------------------
2007
         */
2008
        for (size_t i = 0;
132✔
2009
             papszParamList != nullptr && papszParamList[i] != nullptr; i++)
132✔
2010
        {
2011
            if (STARTS_WITH_CI(papszParamList[i], "BANDDESC"))
22✔
2012
            {
2013
                int nBand = atoi(papszParamList[i] + 8);
×
2014
                const char *pszDescription = strstr(papszParamList[i], "=");
×
2015
                if (pszDescription && nBand > 0 && nBand <= nBandsIn)
×
2016
                {
2017
                    poFile->GetChannel(nBand)->SetDescription(pszDescription +
×
2018
                                                              1);
×
2019
                }
2020
            }
2021
        }
2022

2023
        return LLOpen(pszFilename, poFile, GA_Update);
110✔
2024
    }
2025
    /* -------------------------------------------------------------------- */
2026
    /*      Trap exceptions.                                                */
2027
    /* -------------------------------------------------------------------- */
2028
    catch (const PCIDSKException &ex)
28✔
2029
    {
2030
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
14✔
2031
    }
2032
    catch (...)
×
2033
    {
2034
        CPLError(CE_Failure, CPLE_AppDefined,
×
2035
                 "PCIDSK::Create() failed, unexpected exception.");
2036
    }
2037

2038
    return nullptr;
14✔
2039
}
2040

2041
/************************************************************************/
2042
/*                           TestCapability()                           */
2043
/************************************************************************/
2044

2045
int PCIDSK2Dataset::TestCapability(const char *pszCap)
79✔
2046

2047
{
2048
    if (EQUAL(pszCap, ODsCCreateLayer))
79✔
2049
        return eAccess == GA_Update;
37✔
2050
    if (EQUAL(pszCap, ODsCRandomLayerWrite))
42✔
2051
        return eAccess == GA_Update;
×
2052
    if (EQUAL(pszCap, ODsCZGeometries))
42✔
2053
        return TRUE;
12✔
2054

2055
    return FALSE;
30✔
2056
}
2057

2058
/************************************************************************/
2059
/*                              GetLayer()                              */
2060
/************************************************************************/
2061

2062
OGRLayer *PCIDSK2Dataset::GetLayer(int iLayer)
1,655✔
2063

2064
{
2065
    if (iLayer < 0 || iLayer >= static_cast<int>(apoLayers.size()))
1,655✔
2066
        return nullptr;
2✔
2067

2068
    return apoLayers[iLayer];
1,653✔
2069
}
2070

2071
/************************************************************************/
2072
/*                           ICreateLayer()                             */
2073
/************************************************************************/
2074

2075
OGRLayer *PCIDSK2Dataset::ICreateLayer(const char *pszLayerName,
1,089✔
2076
                                       const OGRGeomFieldDefn *poGeomFieldDefn,
2077
                                       CSLConstList /*papszOptions*/)
2078
{
2079
    /* -------------------------------------------------------------------- */
2080
    /*      Verify we are in update mode.                                   */
2081
    /* -------------------------------------------------------------------- */
2082
    if (eAccess != GA_Update)
1,089✔
2083
    {
2084
        CPLError(CE_Failure, CPLE_NoWriteAccess,
×
2085
                 "Data source %s opened read-only.\n"
2086
                 "New layer %s cannot be created.\n",
2087
                 GetDescription(), pszLayerName);
×
2088
        return nullptr;
×
2089
    }
2090

2091
    const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
1,089✔
2092
    const auto poSRS =
2093
        poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
1,089✔
2094

2095
    /* -------------------------------------------------------------------- */
2096
    /*      Figure out what type of layer we need.                          */
2097
    /* -------------------------------------------------------------------- */
2098
    std::string osLayerType;
2,178✔
2099

2100
    switch (wkbFlatten(eType))
1,089✔
2101
    {
2102
        case wkbPoint:
10✔
2103
            osLayerType = "POINTS";
10✔
2104
            break;
10✔
2105

2106
        case wkbLineString:
10✔
2107
            osLayerType = "ARCS";
10✔
2108
            break;
10✔
2109

2110
        case wkbPolygon:
6✔
2111
            osLayerType = "WHOLE_POLYGONS";
6✔
2112
            break;
6✔
2113

2114
        case wkbNone:
7✔
2115
            osLayerType = "TABLE";
7✔
2116
            break;
7✔
2117

2118
        default:
1,056✔
2119
            break;
1,056✔
2120
    }
2121

2122
    /* -------------------------------------------------------------------- */
2123
    /*      Create the segment.                                             */
2124
    /* -------------------------------------------------------------------- */
2125
    int nSegNum;
2126
    try
2127
    {
2128
        nSegNum = poFile->CreateSegment(pszLayerName, "", PCIDSK::SEG_VEC, 0L);
1,093✔
2129
    }
2130
    catch (const PCIDSKException &ex)
1✔
2131
    {
2132
        CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1✔
2133
        return nullptr;
1✔
2134
    }
2135
    PCIDSK::PCIDSKSegment *poSeg = poFile->GetSegment(nSegNum);
1,088✔
2136
    PCIDSK::PCIDSKVectorSegment *poVecSeg =
2137
        dynamic_cast<PCIDSK::PCIDSKVectorSegment *>(poSeg);
1,088✔
2138
    if (poVecSeg == nullptr)
1,088✔
2139
        return nullptr;
×
2140

2141
    if (osLayerType != "")
1,088✔
2142
        poSeg->SetMetadataValue("LAYER_TYPE", osLayerType);
33✔
2143

2144
    /* -------------------------------------------------------------------- */
2145
    /*      Do we need to apply a coordinate system?                        */
2146
    /* -------------------------------------------------------------------- */
2147
    char *pszGeosys = nullptr;
1,088✔
2148
    char *pszUnits = nullptr;
1,088✔
2149
    double *padfPrjParams = nullptr;
1,088✔
2150

2151
    if (poSRS != nullptr && poSRS->exportToPCI(&pszGeosys, &pszUnits,
1,088✔
2152
                                               &padfPrjParams) == OGRERR_NONE)
2153
    {
2154
        try
2155
        {
2156
            std::vector<double> adfPCIParameters;
6✔
2157

2158
            for (int i = 0; i < 17; i++)
108✔
2159
                adfPCIParameters.push_back(padfPrjParams[i]);
102✔
2160

2161
            if (STARTS_WITH_CI(pszUnits, "FOOT"))
6✔
2162
                adfPCIParameters.push_back(static_cast<double>(
×
2163
                    static_cast<int>(PCIDSK::UNIT_US_FOOT)));
2164
            else if (STARTS_WITH_CI(pszUnits, "INTL FOOT"))
6✔
2165
                adfPCIParameters.push_back(static_cast<double>(
×
2166
                    static_cast<int>(PCIDSK::UNIT_INTL_FOOT)));
2167
            else if (STARTS_WITH_CI(pszUnits, "DEGREE"))
6✔
2168
                adfPCIParameters.push_back(
2✔
2169
                    static_cast<double>(static_cast<int>(PCIDSK::UNIT_DEGREE)));
2✔
2170
            else
2171
                adfPCIParameters.push_back(
4✔
2172
                    static_cast<double>(static_cast<int>(PCIDSK::UNIT_METER)));
4✔
2173

2174
            poVecSeg->SetProjection(pszGeosys, adfPCIParameters);
6✔
2175
        }
2176
        catch (const PCIDSKException &ex)
×
2177
        {
2178
            CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
×
2179
        }
2180

2181
        CPLFree(pszGeosys);
6✔
2182
        CPLFree(pszUnits);
6✔
2183
        CPLFree(padfPrjParams);
6✔
2184
    }
2185

2186
    /* -------------------------------------------------------------------- */
2187
    /*      Create the layer object.                                        */
2188
    /* -------------------------------------------------------------------- */
2189

2190
    apoLayers.push_back(new OGRPCIDSKLayer(this, poSeg, poVecSeg, TRUE));
1,088✔
2191

2192
    return apoLayers.back();
1,088✔
2193
}
2194

2195
/************************************************************************/
2196
/*                        GDALRegister_PCIDSK()                         */
2197
/************************************************************************/
2198

2199
void GDALRegister_PCIDSK()
14✔
2200

2201
{
2202
    if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
14✔
2203
        return;
×
2204

2205
    GDALDriver *poDriver = new GDALDriver();
14✔
2206
    PCIDSKDriverSetCommonMetadata(poDriver);
14✔
2207

2208
    poDriver->pfnOpen = PCIDSK2Dataset::Open;
14✔
2209
    poDriver->pfnCreate = PCIDSK2Dataset::Create;
14✔
2210

2211
    GetGDALDriverManager()->RegisterDriver(poDriver);
14✔
2212
}
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