Line data Source code
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 235 : PCIDSK2Band::PCIDSK2Band(PCIDSKFile *poFileIn, PCIDSKChannel *poChannelIn)
36 :
37 : {
38 235 : Initialize();
39 :
40 235 : poFile = poFileIn;
41 235 : poChannel = poChannelIn;
42 :
43 235 : nBlockXSize = static_cast<int>(poChannel->GetBlockWidth());
44 235 : nBlockYSize = static_cast<int>(poChannel->GetBlockHeight());
45 :
46 235 : eDataType = PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType());
47 :
48 235 : if (!STARTS_WITH_CI(poChannel->GetDescription().c_str(),
49 : "Contents Not Specified"))
50 10 : GDALMajorObject::SetDescription(poChannel->GetDescription().c_str());
51 :
52 : /* -------------------------------------------------------------------- */
53 : /* Do we have overviews? */
54 : /* -------------------------------------------------------------------- */
55 235 : RefreshOverviewList();
56 235 : }
57 :
58 : /************************************************************************/
59 : /* PCIDSK2Band() */
60 : /* */
61 : /* This constructor is used for overviews and bitmap segments */
62 : /* as bands. */
63 : /************************************************************************/
64 :
65 11 : PCIDSK2Band::PCIDSK2Band(PCIDSKChannel *poChannelIn)
66 :
67 : {
68 11 : Initialize();
69 :
70 11 : this->poChannel = poChannelIn;
71 :
72 11 : nBand = 1;
73 :
74 11 : nBlockXSize = static_cast<int>(poChannel->GetBlockWidth());
75 11 : nBlockYSize = static_cast<int>(poChannel->GetBlockHeight());
76 :
77 11 : nRasterXSize = static_cast<int>(poChannel->GetWidth());
78 11 : nRasterYSize = static_cast<int>(poChannel->GetHeight());
79 :
80 11 : eDataType = PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType());
81 :
82 11 : if (poChannel->GetType() == CHN_BIT)
83 : {
84 0 : PCIDSK2Band::SetMetadataItem(GDALMD_NBITS, "1",
85 : GDAL_MDD_IMAGE_STRUCTURE);
86 :
87 0 : if (!STARTS_WITH_CI(poChannel->GetDescription().c_str(),
88 : "Contents Not Specified"))
89 0 : GDALMajorObject::SetDescription(
90 0 : poChannel->GetDescription().c_str());
91 : }
92 11 : }
93 :
94 : /************************************************************************/
95 : /* Initialize() */
96 : /************************************************************************/
97 :
98 246 : void PCIDSK2Band::Initialize()
99 :
100 : {
101 246 : papszLastMDListValue = nullptr;
102 :
103 246 : poChannel = nullptr;
104 246 : poFile = nullptr;
105 246 : poDS = nullptr;
106 :
107 246 : bCheckedForColorTable = false;
108 246 : poColorTable = nullptr;
109 246 : nPCTSegNumber = -1;
110 :
111 246 : papszCategoryNames = nullptr;
112 246 : }
113 :
114 : /************************************************************************/
115 : /* ~PCIDSK2Band() */
116 : /************************************************************************/
117 :
118 738 : PCIDSK2Band::~PCIDSK2Band()
119 :
120 : {
121 257 : while (!apoOverviews.empty())
122 : {
123 11 : delete apoOverviews.back();
124 11 : apoOverviews.pop_back();
125 : }
126 246 : CSLDestroy(papszLastMDListValue);
127 246 : CSLDestroy(papszCategoryNames);
128 :
129 246 : delete poColorTable;
130 492 : }
131 :
132 : /************************************************************************/
133 : /* SetDescription() */
134 : /************************************************************************/
135 :
136 3 : void PCIDSK2Band::SetDescription(const char *pszDescription)
137 :
138 : {
139 3 : if (GetAccess() == GA_ReadOnly)
140 : {
141 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
142 : "Unable to set description on read-only file.");
143 0 : return;
144 : }
145 :
146 : try
147 : {
148 3 : poChannel->SetDescription(pszDescription);
149 :
150 3 : if (!STARTS_WITH_CI(poChannel->GetDescription().c_str(),
151 : "Contents Not Specified"))
152 3 : GDALMajorObject::SetDescription(
153 6 : poChannel->GetDescription().c_str());
154 : }
155 0 : catch (const PCIDSKException &ex)
156 : {
157 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
158 : }
159 : }
160 :
161 : /************************************************************************/
162 : /* GetCategoryNames() */
163 : /* */
164 : /* Offer category names from Class_*_ metadata. */
165 : /************************************************************************/
166 :
167 4 : char **PCIDSK2Band::GetCategoryNames()
168 :
169 : {
170 : // already scanned?
171 4 : if (papszCategoryNames != nullptr)
172 0 : return papszCategoryNames;
173 :
174 : try
175 : {
176 8 : std::vector<std::string> aosMDKeys = poChannel->GetMetadataKeys();
177 4 : int nClassCount = 0;
178 4 : constexpr int nMaxClasses = 10000;
179 4 : papszCategoryNames = reinterpret_cast<char **>(
180 4 : CPLCalloc(nMaxClasses + 1, sizeof(char *)));
181 :
182 7 : for (size_t i = 0; i < aosMDKeys.size(); i++)
183 : {
184 3 : CPLString osKey = aosMDKeys[i];
185 :
186 : // is this a "Class_n_name" keyword?
187 3 : if (!STARTS_WITH_CI(osKey, "Class_"))
188 3 : continue;
189 :
190 0 : if (!EQUAL(osKey.c_str() + osKey.size() - 5, "_name"))
191 0 : continue;
192 :
193 : // Ignore unreasonable class values.
194 0 : int iClass = atoi(osKey.c_str() + 6);
195 :
196 0 : if (iClass < 0 || iClass > 10000)
197 0 : continue;
198 :
199 : // Fetch the name.
200 0 : CPLString osName = poChannel->GetMetadataValue(osKey);
201 :
202 : // do we need to put in place dummy class names for missing values?
203 0 : if (iClass >= nClassCount)
204 : {
205 0 : while (iClass >= nClassCount)
206 : {
207 0 : papszCategoryNames[nClassCount++] = CPLStrdup("");
208 0 : papszCategoryNames[nClassCount] = nullptr;
209 : }
210 : }
211 :
212 : // Replace target category name.
213 0 : CPLFree(papszCategoryNames[iClass]);
214 0 : papszCategoryNames[iClass] = nullptr;
215 :
216 0 : papszCategoryNames[iClass] = CPLStrdup(osName);
217 : }
218 :
219 4 : if (nClassCount == 0)
220 4 : return GDALPamRasterBand::GetCategoryNames();
221 :
222 0 : return papszCategoryNames;
223 : }
224 0 : catch (const PCIDSKException &ex)
225 : {
226 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
227 0 : return nullptr;
228 : }
229 : }
230 :
231 : /************************************************************************/
232 : /* CheckForColorTable() */
233 : /************************************************************************/
234 :
235 27 : bool PCIDSK2Band::CheckForColorTable()
236 :
237 : {
238 27 : if (bCheckedForColorTable || poFile == nullptr)
239 14 : return true;
240 :
241 13 : bCheckedForColorTable = true;
242 :
243 : try
244 : {
245 : /* --------------------------------------------------------------------
246 : */
247 : /* Try to find an appropriate PCT segment to use. */
248 : /* --------------------------------------------------------------------
249 : */
250 : std::string osDefaultPCT =
251 39 : poChannel->GetMetadataValue("DEFAULT_PCT_REF");
252 13 : PCIDSKSegment *poPCTSeg = nullptr;
253 :
254 : // If there is no metadata, assume a single PCT in a file with only
255 : // one raster band must be intended for it.
256 25 : if (osDefaultPCT.empty() && poDS != nullptr &&
257 12 : poDS->GetRasterCount() == 1)
258 : {
259 12 : poPCTSeg = poFile->GetSegment(SEG_PCT, "");
260 12 : if (poPCTSeg != nullptr &&
261 12 : poFile->GetSegment(SEG_PCT, "", poPCTSeg->GetSegmentNumber()) !=
262 : nullptr)
263 0 : poPCTSeg = nullptr;
264 : }
265 : // Parse default PCT ref assuming an in file reference.
266 2 : else if (!osDefaultPCT.empty() &&
267 1 : strstr(osDefaultPCT.c_str(), "PCT:") != nullptr)
268 : {
269 1 : poPCTSeg = poFile->GetSegment(
270 1 : atoi(strstr(osDefaultPCT.c_str(), "PCT:") + 4));
271 : }
272 :
273 13 : if (poPCTSeg != nullptr)
274 : {
275 1 : poColorTable = new GDALColorTable();
276 : unsigned char abyPCT[768];
277 :
278 1 : PCIDSK_PCT *poPCT = dynamic_cast<PCIDSK_PCT *>(poPCTSeg);
279 1 : if (poPCT)
280 : {
281 1 : nPCTSegNumber = poPCTSeg->GetSegmentNumber();
282 :
283 1 : poPCT->ReadPCT(abyPCT);
284 :
285 257 : for (int i = 0; i < 256; i++)
286 : {
287 : GDALColorEntry sEntry;
288 :
289 256 : sEntry.c1 = abyPCT[256 * 0 + i];
290 256 : sEntry.c2 = abyPCT[256 * 1 + i];
291 256 : sEntry.c3 = abyPCT[256 * 2 + i];
292 256 : sEntry.c4 = 255;
293 256 : poColorTable->SetColorEntry(i, &sEntry);
294 : }
295 : }
296 : }
297 :
298 : /* --------------------------------------------------------------------
299 : */
300 : /* If we did not find an appropriate PCT segment, check for */
301 : /* Class_n color data from which to construct a color table. */
302 : /* --------------------------------------------------------------------
303 : */
304 26 : std::vector<std::string> aosMDKeys = poChannel->GetMetadataKeys();
305 :
306 23 : for (size_t i = 0; i < aosMDKeys.size(); i++)
307 : {
308 10 : CPLString osKey = aosMDKeys[i];
309 :
310 : // is this a "Class_n_name" keyword?
311 :
312 10 : if (!STARTS_WITH_CI(osKey, "Class_"))
313 10 : continue;
314 :
315 0 : if (!EQUAL(osKey.c_str() + osKey.size() - 6, "_Color"))
316 0 : continue;
317 :
318 : // Ignore unreasonable class values.
319 0 : const int iClass = atoi(osKey.c_str() + 6);
320 :
321 0 : if (iClass < 0 || iClass > 10000)
322 0 : continue;
323 :
324 : // Fetch and parse the RGB value "(RGB:red green blue)"
325 0 : CPLString osRGB = poChannel->GetMetadataValue(osKey);
326 :
327 0 : if (!STARTS_WITH_CI(osRGB, "(RGB:"))
328 0 : continue;
329 :
330 : int nRed, nGreen, nBlue;
331 0 : if (sscanf(osRGB.c_str() + 5, "%d %d %d", &nRed, &nGreen, &nBlue) !=
332 : 3)
333 0 : continue;
334 :
335 : // we have an entry - apply to the color table.
336 : GDALColorEntry sEntry;
337 :
338 0 : sEntry.c1 = (short)nRed;
339 0 : sEntry.c2 = (short)nGreen;
340 0 : sEntry.c3 = (short)nBlue;
341 0 : sEntry.c4 = 255;
342 :
343 0 : if (poColorTable == nullptr)
344 : {
345 0 : CPLDebug("PCIDSK",
346 : "Using Class_n_Color metadata for color table.");
347 0 : poColorTable = new GDALColorTable();
348 : }
349 :
350 0 : poColorTable->SetColorEntry(iClass, &sEntry);
351 : }
352 : }
353 0 : catch (const PCIDSKException &ex)
354 : {
355 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
356 0 : return false;
357 : }
358 :
359 13 : return true;
360 : }
361 :
362 : /************************************************************************/
363 : /* GetColorTable() */
364 : /************************************************************************/
365 :
366 10 : GDALColorTable *PCIDSK2Band::GetColorTable()
367 :
368 : {
369 10 : CheckForColorTable();
370 :
371 10 : if (poColorTable)
372 2 : return poColorTable;
373 :
374 8 : return GDALPamRasterBand::GetColorTable();
375 : }
376 :
377 : /************************************************************************/
378 : /* SetColorTable() */
379 : /************************************************************************/
380 :
381 2 : CPLErr PCIDSK2Band::SetColorTable(GDALColorTable *poCT)
382 :
383 : {
384 2 : if (!CheckForColorTable())
385 0 : return CE_Failure;
386 :
387 : // no color tables on overviews.
388 2 : if (poFile == nullptr)
389 0 : return CE_Failure;
390 :
391 2 : if (GetAccess() == GA_ReadOnly)
392 : {
393 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
394 : "Unable to set color table on read-only file.");
395 0 : return CE_Failure;
396 : }
397 :
398 : try
399 : {
400 : /* --------------------------------------------------------------------
401 : */
402 : /* Are we trying to delete the color table? */
403 : /* --------------------------------------------------------------------
404 : */
405 2 : if (poCT == nullptr)
406 : {
407 1 : delete poColorTable;
408 1 : poColorTable = nullptr;
409 :
410 1 : if (nPCTSegNumber != -1)
411 1 : poFile->DeleteSegment(nPCTSegNumber);
412 1 : poChannel->SetMetadataValue("DEFAULT_PCT_REF", "");
413 1 : nPCTSegNumber = -1;
414 :
415 1 : return CE_None;
416 : }
417 :
418 : /* --------------------------------------------------------------------
419 : */
420 : /* Do we need to create the segment? If so, also set the */
421 : /* default pct metadata. */
422 : /* --------------------------------------------------------------------
423 : */
424 1 : if (nPCTSegNumber == -1)
425 : {
426 1 : nPCTSegNumber = poFile->CreateSegment(
427 1 : "PCTTable", "Default Pseudo-Color Table", SEG_PCT, 0);
428 :
429 1 : CPLString osRef;
430 1 : osRef.Printf("gdb:/{PCT:%d}", nPCTSegNumber);
431 1 : poChannel->SetMetadataValue("DEFAULT_PCT_REF", osRef);
432 : }
433 :
434 : /* --------------------------------------------------------------------
435 : */
436 : /* Write out the PCT. */
437 : /* --------------------------------------------------------------------
438 : */
439 1 : const int nColorCount = std::min(256, poCT->GetColorEntryCount());
440 :
441 : unsigned char abyPCT[768];
442 1 : memset(abyPCT, 0, 768);
443 :
444 4 : for (int i = 0; i < nColorCount; i++)
445 : {
446 : GDALColorEntry sEntry;
447 :
448 3 : poCT->GetColorEntryAsRGB(i, &sEntry);
449 3 : abyPCT[256 * 0 + i] = (unsigned char)sEntry.c1;
450 3 : abyPCT[256 * 1 + i] = (unsigned char)sEntry.c2;
451 3 : abyPCT[256 * 2 + i] = (unsigned char)sEntry.c3;
452 : }
453 :
454 : PCIDSK_PCT *poPCT =
455 1 : dynamic_cast<PCIDSK_PCT *>(poFile->GetSegment(nPCTSegNumber));
456 1 : if (poPCT)
457 1 : poPCT->WritePCT(abyPCT);
458 :
459 1 : delete poColorTable;
460 1 : poColorTable = poCT->Clone();
461 : }
462 :
463 : /* -------------------------------------------------------------------- */
464 : /* Trap exceptions. */
465 : /* -------------------------------------------------------------------- */
466 0 : catch (const PCIDSKException &ex)
467 : {
468 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
469 0 : return CE_Failure;
470 : }
471 :
472 1 : return CE_None;
473 : }
474 :
475 : /************************************************************************/
476 : /* GetColorInterpretation() */
477 : /************************************************************************/
478 :
479 15 : GDALColorInterp PCIDSK2Band::GetColorInterpretation()
480 :
481 : {
482 15 : CheckForColorTable();
483 :
484 15 : if (poColorTable != nullptr)
485 1 : return GCI_PaletteIndex;
486 :
487 14 : return GDALPamRasterBand::GetColorInterpretation();
488 : }
489 :
490 : /************************************************************************/
491 : /* RefreshOverviewList() */
492 : /************************************************************************/
493 :
494 236 : void PCIDSK2Band::RefreshOverviewList()
495 :
496 : {
497 : /* -------------------------------------------------------------------- */
498 : /* Clear existing overviews. */
499 : /* -------------------------------------------------------------------- */
500 236 : while (!apoOverviews.empty())
501 : {
502 0 : delete apoOverviews.back();
503 0 : apoOverviews.pop_back();
504 : }
505 :
506 : /* -------------------------------------------------------------------- */
507 : /* Fetch overviews. */
508 : /* -------------------------------------------------------------------- */
509 247 : for (int iOver = 0; iOver < poChannel->GetOverviewCount(); iOver++)
510 : {
511 11 : auto poOvrBand = new PCIDSK2Band(poChannel->GetOverview(iOver));
512 11 : poOvrBand->eAccess = eAccess;
513 11 : apoOverviews.push_back(poOvrBand);
514 : }
515 236 : }
516 :
517 : /************************************************************************/
518 : /* IReadBlock() */
519 : /************************************************************************/
520 :
521 262 : CPLErr PCIDSK2Band::IReadBlock(int iBlockX, int iBlockY, void *pData)
522 :
523 : {
524 : try
525 : {
526 262 : poChannel->ReadBlock(iBlockX + iBlockY * nBlocksPerRow, pData);
527 :
528 : // Do we need to upsample 1bit to 8bit?
529 262 : if (poChannel->GetType() == CHN_BIT)
530 : {
531 0 : GByte *pabyData = reinterpret_cast<GByte *>(pData);
532 :
533 0 : for (int ii = nBlockXSize * nBlockYSize - 1; ii >= 0; ii--)
534 : {
535 0 : if ((pabyData[ii >> 3] & (0x80 >> (ii & 0x7))))
536 0 : pabyData[ii] = 1;
537 : else
538 0 : pabyData[ii] = 0;
539 : }
540 : }
541 :
542 262 : return CE_None;
543 : }
544 0 : catch (const PCIDSKException &ex)
545 : {
546 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
547 0 : return CE_Failure;
548 : }
549 : }
550 :
551 : /************************************************************************/
552 : /* IWriteBlock() */
553 : /************************************************************************/
554 :
555 645 : CPLErr PCIDSK2Band::IWriteBlock(int iBlockX, int iBlockY, void *pData)
556 :
557 : {
558 : try
559 : {
560 645 : poChannel->WriteBlock(iBlockX + iBlockY * nBlocksPerRow, pData);
561 : }
562 0 : catch (const PCIDSKException &ex)
563 : {
564 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
565 0 : return CE_Failure;
566 : }
567 :
568 645 : return CE_None;
569 : }
570 :
571 : /************************************************************************/
572 : /* GetOverviewCount() */
573 : /************************************************************************/
574 :
575 16 : int PCIDSK2Band::GetOverviewCount()
576 :
577 : {
578 16 : if (!apoOverviews.empty())
579 5 : return static_cast<int>(apoOverviews.size());
580 :
581 11 : return GDALPamRasterBand::GetOverviewCount();
582 : }
583 :
584 : /************************************************************************/
585 : /* GetOverview() */
586 : /************************************************************************/
587 :
588 6 : GDALRasterBand *PCIDSK2Band::GetOverview(int iOverview)
589 :
590 : {
591 6 : if (iOverview < 0 || iOverview >= static_cast<int>(apoOverviews.size()))
592 1 : return GDALPamRasterBand::GetOverview(iOverview);
593 :
594 5 : return apoOverviews[iOverview];
595 : }
596 :
597 : /************************************************************************/
598 : /* SetMetadata() */
599 : /************************************************************************/
600 :
601 2 : CPLErr PCIDSK2Band::SetMetadata(CSLConstList papszMD, const char *pszDomain)
602 :
603 : {
604 : /* -------------------------------------------------------------------- */
605 : /* PCIDSK only supports metadata in the default domain. */
606 : /* -------------------------------------------------------------------- */
607 2 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
608 0 : return GDALPamRasterBand::SetMetadata(papszMD, pszDomain);
609 :
610 : /* -------------------------------------------------------------------- */
611 : /* Set each item individually. */
612 : /* -------------------------------------------------------------------- */
613 2 : CSLDestroy(papszLastMDListValue);
614 2 : papszLastMDListValue = nullptr;
615 2 : m_oCacheMetadataItem.clear();
616 :
617 2 : if (GetAccess() == GA_ReadOnly)
618 : {
619 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
620 : "Unable to set metadata on read-only file.");
621 0 : return CE_Failure;
622 : }
623 :
624 : try
625 : {
626 5 : for (int iItem = 0; papszMD && papszMD[iItem]; iItem++)
627 : {
628 3 : char *pszItemName = nullptr;
629 :
630 : const char *pszItemValue =
631 3 : CPLParseNameValue(papszMD[iItem], &pszItemName);
632 3 : if (pszItemName != nullptr)
633 : {
634 3 : poChannel->SetMetadataValue(pszItemName, pszItemValue);
635 3 : CPLFree(pszItemName);
636 : }
637 : }
638 : }
639 0 : catch (const PCIDSKException &ex)
640 : {
641 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
642 0 : return CE_Failure;
643 : }
644 :
645 2 : return CE_None;
646 : }
647 :
648 : /************************************************************************/
649 : /* SetMetadataItem() */
650 : /************************************************************************/
651 :
652 6 : CPLErr PCIDSK2Band::SetMetadataItem(const char *pszName, const char *pszValue,
653 : const char *pszDomain)
654 :
655 : {
656 : /* -------------------------------------------------------------------- */
657 : /* PCIDSK only supports metadata in the default domain. */
658 : /* -------------------------------------------------------------------- */
659 6 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
660 1 : return GDALPamRasterBand::SetMetadataItem(pszName, pszValue, pszDomain);
661 :
662 : /* -------------------------------------------------------------------- */
663 : /* Set on the file. */
664 : /* -------------------------------------------------------------------- */
665 5 : CSLDestroy(papszLastMDListValue);
666 5 : papszLastMDListValue = nullptr;
667 5 : m_oCacheMetadataItem.clear();
668 :
669 5 : if (GetAccess() == GA_ReadOnly)
670 : {
671 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
672 : "Unable to set metadata on read-only file.");
673 0 : return CE_Failure;
674 : }
675 :
676 : try
677 : {
678 5 : if (!pszValue)
679 0 : pszValue = "";
680 5 : poChannel->SetMetadataValue(pszName, pszValue);
681 : }
682 0 : catch (const PCIDSKException &ex)
683 : {
684 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
685 0 : return CE_Failure;
686 : }
687 :
688 5 : return CE_None;
689 : }
690 :
691 : /************************************************************************/
692 : /* GetMetadataDomainList() */
693 : /************************************************************************/
694 :
695 0 : char **PCIDSK2Band::GetMetadataDomainList()
696 : {
697 0 : return BuildMetadataDomainList(GDALPamRasterBand::GetMetadataDomainList(),
698 0 : TRUE, "", nullptr);
699 : }
700 :
701 : /************************************************************************/
702 : /* GetNoDataValue() */
703 : /************************************************************************/
704 :
705 65 : double PCIDSK2Band::GetNoDataValue(int *pbSuccess)
706 : {
707 65 : const char *pszNoData = GetMetadataItem("NO_DATA_VALUE", "");
708 65 : if (pszNoData != nullptr)
709 : {
710 1 : if (pbSuccess)
711 1 : *pbSuccess = TRUE;
712 1 : return CPLAtof(pszNoData);
713 : }
714 :
715 64 : PCIDSK2Dataset *poGDS = cpl::down_cast<PCIDSK2Dataset *>(poDS);
716 64 : pszNoData = poGDS->GetMetadataItem("NO_DATA_VALUE", "");
717 64 : if (pszNoData != nullptr)
718 : {
719 1 : if (pbSuccess)
720 1 : *pbSuccess = TRUE;
721 1 : return CPLAtof(pszNoData);
722 : }
723 :
724 63 : if (pbSuccess)
725 63 : *pbSuccess = FALSE;
726 63 : return 0.0;
727 : }
728 :
729 : /************************************************************************/
730 : /* SetNoDataValue() */
731 : /************************************************************************/
732 :
733 1 : CPLErr PCIDSK2Band::SetNoDataValue(double dfNoData)
734 : {
735 1 : return SetMetadataItem("NO_DATA_VALUE", CPLSPrintf("%.17g", dfNoData), "");
736 : }
737 :
738 : /************************************************************************/
739 : /* GetMetadataItem() */
740 : /************************************************************************/
741 :
742 99 : const char *PCIDSK2Band::GetMetadataItem(const char *pszName,
743 : const char *pszDomain)
744 :
745 : {
746 : /* -------------------------------------------------------------------- */
747 : /* PCIDSK only supports metadata in the default domain. */
748 : /* -------------------------------------------------------------------- */
749 99 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
750 23 : return GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
751 :
752 : /* -------------------------------------------------------------------- */
753 : /* Try and fetch (use cached value if available) */
754 : /* -------------------------------------------------------------------- */
755 76 : auto oIter = m_oCacheMetadataItem.find(pszName);
756 76 : if (oIter != m_oCacheMetadataItem.end())
757 : {
758 39 : return oIter->second.empty() ? nullptr : oIter->second.c_str();
759 : }
760 :
761 74 : CPLString osValue;
762 : try
763 : {
764 37 : osValue = poChannel->GetMetadataValue(pszName);
765 : }
766 0 : catch (const PCIDSKException &ex)
767 : {
768 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
769 0 : return nullptr;
770 : }
771 :
772 37 : oIter = m_oCacheMetadataItem
773 37 : .insert(std::pair<std::string, std::string>(pszName, osValue))
774 : .first;
775 37 : return oIter->second.empty() ? nullptr : oIter->second.c_str();
776 : }
777 :
778 : /************************************************************************/
779 : /* GetMetadata() */
780 : /************************************************************************/
781 :
782 6 : CSLConstList PCIDSK2Band::GetMetadata(const char *pszDomain)
783 :
784 : {
785 : /* -------------------------------------------------------------------- */
786 : /* PCIDSK only supports metadata in the default domain. */
787 : /* -------------------------------------------------------------------- */
788 6 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
789 1 : return GDALPamRasterBand::GetMetadata(pszDomain);
790 :
791 : /* -------------------------------------------------------------------- */
792 : /* If we have a cached result, just use that. */
793 : /* -------------------------------------------------------------------- */
794 5 : if (papszLastMDListValue != nullptr)
795 0 : return papszLastMDListValue;
796 :
797 : /* -------------------------------------------------------------------- */
798 : /* Fetch and build the list. */
799 : /* -------------------------------------------------------------------- */
800 : try
801 : {
802 10 : std::vector<std::string> aosKeys = poChannel->GetMetadataKeys();
803 :
804 11 : for (unsigned int i = 0; i < aosKeys.size(); i++)
805 : {
806 6 : if (aosKeys[i].c_str()[0] == '_')
807 3 : continue;
808 :
809 6 : papszLastMDListValue = CSLSetNameValue(
810 3 : papszLastMDListValue, aosKeys[i].c_str(),
811 6 : poChannel->GetMetadataValue(aosKeys[i]).c_str());
812 : }
813 : }
814 0 : catch (const PCIDSKException &ex)
815 : {
816 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
817 0 : return nullptr;
818 : }
819 :
820 5 : return papszLastMDListValue;
821 : }
822 :
823 : /************************************************************************/
824 : /* ==================================================================== */
825 : /* PCIDSK2Dataset */
826 : /* ==================================================================== */
827 : /************************************************************************/
828 :
829 : /************************************************************************/
830 : /* PCIDSK2Dataset() */
831 : /************************************************************************/
832 :
833 245 : PCIDSK2Dataset::PCIDSK2Dataset()
834 245 : : papszLastMDListValue(nullptr), poFile(nullptr)
835 : {
836 245 : }
837 :
838 : /************************************************************************/
839 : /* ~PCIDSK2Dataset() */
840 : /************************************************************************/
841 :
842 : // FIXME? is an exception can really be thrown in the destructor, then it is
843 : // very dangerous !
844 : #ifdef _MSC_VER
845 : #pragma warning(push)
846 : #pragma warning(disable : 4702) /* unreachable code */
847 : #endif
848 490 : PCIDSK2Dataset::~PCIDSK2Dataset()
849 : {
850 245 : PCIDSK2Dataset::FlushCache(true);
851 :
852 1428 : while (!apoLayers.empty())
853 : {
854 1183 : delete apoLayers.back();
855 1183 : apoLayers.pop_back();
856 : }
857 :
858 245 : if (m_poSRS)
859 7 : m_poSRS->Release();
860 :
861 : try
862 : {
863 245 : if (poFile != nullptr)
864 245 : delete poFile;
865 : }
866 :
867 : /* -------------------------------------------------------------------- */
868 : /* Trap exceptions. */
869 : /* -------------------------------------------------------------------- */
870 : catch (const PCIDSKException &ex)
871 : {
872 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
873 : }
874 : catch (...)
875 : {
876 : CPLError(CE_Failure, CPLE_AppDefined,
877 : "PCIDSK SDK Failure in Close(), unexpected exception.");
878 : }
879 :
880 245 : CSLDestroy(papszLastMDListValue);
881 490 : }
882 : #ifdef _MSC_VER
883 : #pragma warning(pop)
884 : #endif
885 :
886 : /************************************************************************/
887 : /* GetFileList() */
888 : /************************************************************************/
889 :
890 55 : char **PCIDSK2Dataset::GetFileList()
891 :
892 : {
893 55 : char **papszFileList = GDALPamDataset::GetFileList();
894 110 : CPLString osBaseDir = CPLGetPathSafe(GetDescription());
895 :
896 : try
897 : {
898 75 : for (int nChan = 1; nChan <= poFile->GetChannels(); nChan++)
899 : {
900 20 : PCIDSKChannel *poChannel = poFile->GetChannel(nChan);
901 40 : CPLString osChanFilename;
902 : uint64 image_offset, pixel_offset, line_offset;
903 : bool little_endian;
904 :
905 20 : poChannel->GetChanInfo(osChanFilename, image_offset, pixel_offset,
906 20 : line_offset, little_endian);
907 :
908 20 : if (osChanFilename != "")
909 : {
910 1 : papszFileList = CSLAddString(
911 : papszFileList,
912 2 : CPLProjectRelativeFilenameSafe(osBaseDir, osChanFilename)
913 : .c_str());
914 : }
915 : }
916 :
917 55 : return papszFileList;
918 : }
919 0 : catch (const PCIDSKException &ex)
920 : {
921 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
922 0 : return papszFileList;
923 : }
924 : }
925 :
926 : /************************************************************************/
927 : /* ProcessRPC() */
928 : /************************************************************************/
929 :
930 245 : void PCIDSK2Dataset::ProcessRPC()
931 :
932 : {
933 : /* -------------------------------------------------------------------- */
934 : /* Search all BIN segments looking for an RPC segment. */
935 : /* -------------------------------------------------------------------- */
936 245 : PCIDSKSegment *poSeg = poFile->GetSegment(SEG_BIN, "");
937 245 : PCIDSKRPCSegment *poRPCSeg = nullptr;
938 :
939 245 : while (poSeg != nullptr &&
940 0 : (poRPCSeg = dynamic_cast<PCIDSKRPCSegment *>(poSeg)) == nullptr)
941 :
942 : {
943 0 : poSeg = poFile->GetSegment(SEG_BIN, "", poSeg->GetSegmentNumber());
944 : }
945 :
946 245 : if (poRPCSeg == nullptr)
947 245 : return;
948 :
949 : /* -------------------------------------------------------------------- */
950 : /* Turn RPC segment into GDAL RFC 22 style metadata. */
951 : /* -------------------------------------------------------------------- */
952 : try
953 : {
954 0 : CPLString osValue;
955 : double dfLineOffset, dfLineScale, dfSampOffset, dfSampScale;
956 : double dfLatOffset, dfLatScale, dfLongOffset, dfLongScale,
957 : dfHeightOffset, dfHeightScale;
958 :
959 0 : poRPCSeg->GetRPCTranslationCoeffs(
960 : dfLongOffset, dfLongScale, dfLatOffset, dfLatScale, dfHeightOffset,
961 : dfHeightScale, dfSampOffset, dfSampScale, dfLineOffset,
962 0 : dfLineScale);
963 :
964 0 : osValue.Printf("%.16g", dfLineOffset);
965 0 : GDALPamDataset::SetMetadataItem("LINE_OFF", osValue, GDAL_MDD_RPC);
966 :
967 0 : osValue.Printf("%.16g", dfLineScale);
968 0 : GDALPamDataset::SetMetadataItem("LINE_SCALE", osValue, GDAL_MDD_RPC);
969 :
970 0 : osValue.Printf("%.16g", dfSampOffset);
971 0 : GDALPamDataset::SetMetadataItem("SAMP_OFF", osValue, GDAL_MDD_RPC);
972 :
973 0 : osValue.Printf("%.16g", dfSampScale);
974 0 : GDALPamDataset::SetMetadataItem("SAMP_SCALE", osValue, GDAL_MDD_RPC);
975 :
976 0 : osValue.Printf("%.16g", dfLongOffset);
977 0 : GDALPamDataset::SetMetadataItem("LONG_OFF", osValue, GDAL_MDD_RPC);
978 :
979 0 : osValue.Printf("%.16g", dfLongScale);
980 0 : GDALPamDataset::SetMetadataItem("LONG_SCALE", osValue, GDAL_MDD_RPC);
981 :
982 0 : osValue.Printf("%.16g", dfLatOffset);
983 0 : GDALPamDataset::SetMetadataItem("LAT_OFF", osValue, GDAL_MDD_RPC);
984 :
985 0 : osValue.Printf("%.16g", dfLatScale);
986 0 : GDALPamDataset::SetMetadataItem("LAT_SCALE", osValue, GDAL_MDD_RPC);
987 :
988 0 : osValue.Printf("%.16g", dfHeightOffset);
989 0 : GDALPamDataset::SetMetadataItem("HEIGHT_OFF", osValue, GDAL_MDD_RPC);
990 :
991 0 : osValue.Printf("%.16g", dfHeightScale);
992 0 : GDALPamDataset::SetMetadataItem("HEIGHT_SCALE", osValue, GDAL_MDD_RPC);
993 :
994 0 : if (poRPCSeg->GetXNumerator().size() != 20 ||
995 0 : poRPCSeg->GetXDenominator().size() != 20 ||
996 0 : poRPCSeg->GetYNumerator().size() != 20 ||
997 0 : poRPCSeg->GetYDenominator().size() != 20)
998 : {
999 0 : GDALPamDataset::SetMetadata(nullptr, GDAL_MDD_RPC);
1000 0 : CPLError(CE_Failure, CPLE_AppDefined,
1001 : "Did not get 20 values in the RPC coefficients lists.");
1002 0 : return;
1003 : }
1004 :
1005 0 : std::vector<double> adfCoef = poRPCSeg->GetYNumerator();
1006 0 : CPLString osCoefList = "";
1007 0 : for (int i = 0; i < 20; i++)
1008 : {
1009 0 : osValue.Printf("%.16g ", adfCoef[i]);
1010 0 : osCoefList += osValue;
1011 : }
1012 0 : GDALPamDataset::SetMetadataItem("LINE_NUM_COEFF", osCoefList,
1013 : GDAL_MDD_RPC);
1014 :
1015 0 : adfCoef = poRPCSeg->GetYDenominator();
1016 0 : osCoefList = "";
1017 0 : for (int i = 0; i < 20; i++)
1018 : {
1019 0 : osValue.Printf("%.16g ", adfCoef[i]);
1020 0 : osCoefList += osValue;
1021 : }
1022 0 : GDALPamDataset::SetMetadataItem("LINE_DEN_COEFF", osCoefList,
1023 : GDAL_MDD_RPC);
1024 :
1025 0 : adfCoef = poRPCSeg->GetXNumerator();
1026 0 : osCoefList = "";
1027 0 : for (int i = 0; i < 20; i++)
1028 : {
1029 0 : osValue.Printf("%.16g ", adfCoef[i]);
1030 0 : osCoefList += osValue;
1031 : }
1032 0 : GDALPamDataset::SetMetadataItem("SAMP_NUM_COEFF", osCoefList,
1033 : GDAL_MDD_RPC);
1034 :
1035 0 : adfCoef = poRPCSeg->GetXDenominator();
1036 0 : osCoefList = "";
1037 0 : for (int i = 0; i < 20; i++)
1038 : {
1039 0 : osValue.Printf("%.16g ", adfCoef[i]);
1040 0 : osCoefList += osValue;
1041 : }
1042 0 : GDALPamDataset::SetMetadataItem("SAMP_DEN_COEFF", osCoefList,
1043 : GDAL_MDD_RPC);
1044 : }
1045 0 : catch (const PCIDSKException &ex)
1046 : {
1047 0 : GDALPamDataset::SetMetadata(nullptr, GDAL_MDD_RPC);
1048 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1049 : }
1050 : }
1051 :
1052 : /************************************************************************/
1053 : /* FlushCache() */
1054 : /************************************************************************/
1055 :
1056 257 : CPLErr PCIDSK2Dataset::FlushCache(bool bAtClosing)
1057 :
1058 : {
1059 257 : CPLErr eErr = GDALPamDataset::FlushCache(bAtClosing);
1060 :
1061 257 : if (poFile)
1062 : {
1063 : try
1064 : {
1065 257 : poFile->Synchronize();
1066 : }
1067 0 : catch (const PCIDSKException &ex)
1068 : {
1069 0 : eErr = CE_Failure;
1070 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1071 : }
1072 : }
1073 257 : return eErr;
1074 : }
1075 :
1076 : /************************************************************************/
1077 : /* SetMetadata() */
1078 : /************************************************************************/
1079 :
1080 26 : CPLErr PCIDSK2Dataset::SetMetadata(CSLConstList papszMD, const char *pszDomain)
1081 :
1082 : {
1083 : /* -------------------------------------------------------------------- */
1084 : /* PCIDSK only supports metadata in the default domain. */
1085 : /* -------------------------------------------------------------------- */
1086 26 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
1087 0 : return GDALPamDataset::SetMetadata(papszMD, pszDomain);
1088 :
1089 : /* -------------------------------------------------------------------- */
1090 : /* Set each item individually. */
1091 : /* -------------------------------------------------------------------- */
1092 26 : CSLDestroy(papszLastMDListValue);
1093 26 : papszLastMDListValue = nullptr;
1094 26 : m_oCacheMetadataItem.clear();
1095 :
1096 26 : if (GetAccess() == GA_ReadOnly)
1097 : {
1098 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1099 : "Unable to set metadata on read-only file.");
1100 0 : return CE_Failure;
1101 : }
1102 :
1103 : try
1104 : {
1105 59 : for (int iItem = 0; papszMD && papszMD[iItem]; iItem++)
1106 : {
1107 33 : char *pszItemName = nullptr;
1108 : const char *pszItemValue =
1109 33 : CPLParseNameValue(papszMD[iItem], &pszItemName);
1110 33 : if (pszItemName != nullptr)
1111 : {
1112 17 : poFile->SetMetadataValue(pszItemName, pszItemValue);
1113 17 : CPLFree(pszItemName);
1114 : }
1115 : }
1116 : }
1117 0 : catch (const PCIDSKException &ex)
1118 : {
1119 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1120 0 : return CE_Failure;
1121 : }
1122 :
1123 26 : return CE_None;
1124 : }
1125 :
1126 : /************************************************************************/
1127 : /* SetMetadataItem() */
1128 : /************************************************************************/
1129 :
1130 223 : CPLErr PCIDSK2Dataset::SetMetadataItem(const char *pszName,
1131 : const char *pszValue,
1132 : const char *pszDomain)
1133 :
1134 : {
1135 : /* -------------------------------------------------------------------- */
1136 : /* PCIDSK only supports metadata in the default domain. */
1137 : /* -------------------------------------------------------------------- */
1138 223 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
1139 218 : return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
1140 :
1141 : /* -------------------------------------------------------------------- */
1142 : /* Set on the file. */
1143 : /* -------------------------------------------------------------------- */
1144 5 : CSLDestroy(papszLastMDListValue);
1145 5 : papszLastMDListValue = nullptr;
1146 5 : m_oCacheMetadataItem.clear();
1147 :
1148 5 : if (GetAccess() == GA_ReadOnly)
1149 : {
1150 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1151 : "Unable to set metadata on read-only file.");
1152 0 : return CE_Failure;
1153 : }
1154 :
1155 : try
1156 : {
1157 5 : poFile->SetMetadataValue(pszName, pszValue);
1158 : }
1159 0 : catch (const PCIDSKException &ex)
1160 : {
1161 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1162 0 : return CE_Failure;
1163 : }
1164 :
1165 5 : return CE_None;
1166 : }
1167 :
1168 : /************************************************************************/
1169 : /* GetMetadataDomainList() */
1170 : /************************************************************************/
1171 :
1172 0 : char **PCIDSK2Dataset::GetMetadataDomainList()
1173 : {
1174 0 : return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(),
1175 0 : TRUE, "", nullptr);
1176 : }
1177 :
1178 : /************************************************************************/
1179 : /* GetMetadataItem() */
1180 : /************************************************************************/
1181 :
1182 1304 : const char *PCIDSK2Dataset::GetMetadataItem(const char *pszName,
1183 : const char *pszDomain)
1184 :
1185 : {
1186 : /* -------------------------------------------------------------------- */
1187 : /* PCIDSK only supports metadata in the default domain. */
1188 : /* -------------------------------------------------------------------- */
1189 1304 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
1190 95 : return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
1191 :
1192 : /* -------------------------------------------------------------------- */
1193 : /* Try and fetch (use cached value if available) */
1194 : /* -------------------------------------------------------------------- */
1195 1209 : auto oIter = m_oCacheMetadataItem.find(pszName);
1196 1209 : if (oIter != m_oCacheMetadataItem.end())
1197 : {
1198 1089 : return oIter->second.empty() ? nullptr : oIter->second.c_str();
1199 : }
1200 :
1201 240 : CPLString osValue;
1202 : try
1203 : {
1204 120 : osValue = poFile->GetMetadataValue(pszName);
1205 : }
1206 0 : catch (const PCIDSKException &ex)
1207 : {
1208 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1209 0 : return nullptr;
1210 : }
1211 :
1212 120 : oIter = m_oCacheMetadataItem
1213 120 : .insert(std::pair<std::string, std::string>(pszName, osValue))
1214 : .first;
1215 120 : return oIter->second.empty() ? nullptr : oIter->second.c_str();
1216 : }
1217 :
1218 : /************************************************************************/
1219 : /* GetMetadata() */
1220 : /************************************************************************/
1221 :
1222 52 : CSLConstList PCIDSK2Dataset::GetMetadata(const char *pszDomain)
1223 :
1224 : {
1225 : /* -------------------------------------------------------------------- */
1226 : /* PCIDSK only supports metadata in the default domain. */
1227 : /* -------------------------------------------------------------------- */
1228 52 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
1229 25 : return GDALPamDataset::GetMetadata(pszDomain);
1230 :
1231 : /* -------------------------------------------------------------------- */
1232 : /* If we have a cached result, just use that. */
1233 : /* -------------------------------------------------------------------- */
1234 27 : if (papszLastMDListValue != nullptr)
1235 3 : return papszLastMDListValue;
1236 :
1237 : /* -------------------------------------------------------------------- */
1238 : /* Fetch and build the list. */
1239 : /* -------------------------------------------------------------------- */
1240 : try
1241 : {
1242 48 : std::vector<std::string> aosKeys = poFile->GetMetadataKeys();
1243 :
1244 38 : for (unsigned int i = 0; i < aosKeys.size(); i++)
1245 : {
1246 14 : if (aosKeys[i].c_str()[0] == '_')
1247 2 : continue;
1248 :
1249 12 : papszLastMDListValue =
1250 12 : CSLSetNameValue(papszLastMDListValue, aosKeys[i].c_str(),
1251 24 : poFile->GetMetadataValue(aosKeys[i]).c_str());
1252 : }
1253 : }
1254 0 : catch (const PCIDSKException &ex)
1255 : {
1256 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1257 0 : return nullptr;
1258 : }
1259 :
1260 24 : return papszLastMDListValue;
1261 : }
1262 :
1263 : /************************************************************************/
1264 : /* SetGeoTransform() */
1265 : /************************************************************************/
1266 :
1267 58 : CPLErr PCIDSK2Dataset::SetGeoTransform(const GDALGeoTransform >)
1268 : {
1269 58 : PCIDSKGeoref *poGeoref = nullptr;
1270 : try
1271 : {
1272 58 : PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
1273 58 : poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
1274 : }
1275 0 : catch (const PCIDSKException &)
1276 : {
1277 : // I should really check whether this is an expected issue.
1278 : }
1279 :
1280 58 : if (poGeoref == nullptr)
1281 0 : return GDALPamDataset::SetGeoTransform(gt);
1282 :
1283 58 : if (GetAccess() == GA_ReadOnly)
1284 : {
1285 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1286 : "Unable to set GeoTransform on read-only file.");
1287 0 : return CE_Failure;
1288 : }
1289 :
1290 : try
1291 : {
1292 58 : poGeoref->WriteSimple(poGeoref->GetGeosys(), gt.xorig, gt.xscale,
1293 58 : gt.xrot, gt.yorig, gt.yrot, gt.yscale);
1294 : }
1295 0 : catch (const PCIDSKException &ex)
1296 : {
1297 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1298 0 : return CE_Failure;
1299 : }
1300 :
1301 58 : return CE_None;
1302 : }
1303 :
1304 : /************************************************************************/
1305 : /* GetGeoTransform() */
1306 : /************************************************************************/
1307 :
1308 44 : CPLErr PCIDSK2Dataset::GetGeoTransform(GDALGeoTransform >) const
1309 : {
1310 44 : PCIDSKGeoref *poGeoref = nullptr;
1311 : try
1312 : {
1313 44 : PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
1314 44 : poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
1315 : }
1316 0 : catch (const PCIDSKException &)
1317 : {
1318 : // I should really check whether this is an expected issue.
1319 : }
1320 :
1321 44 : if (poGeoref != nullptr)
1322 : {
1323 : try
1324 : {
1325 44 : poGeoref->GetTransform(gt.xorig, gt.xscale, gt.xrot, gt.yorig,
1326 44 : gt.yrot, gt.yscale);
1327 : }
1328 0 : catch (const PCIDSKException &ex)
1329 : {
1330 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1331 0 : return CE_Failure;
1332 : }
1333 :
1334 : // If we got anything non-default return it.
1335 44 : if (gt != GDALGeoTransform())
1336 41 : return CE_None;
1337 : }
1338 :
1339 : /* -------------------------------------------------------------------- */
1340 : /* Check for worldfile if we have no other georeferencing. */
1341 : /* -------------------------------------------------------------------- */
1342 3 : if (GDALReadWorldFile(GetDescription(), "pxw", gt.data()))
1343 0 : return CE_None;
1344 :
1345 3 : return GDALPamDataset::GetGeoTransform(gt);
1346 : }
1347 :
1348 : /************************************************************************/
1349 : /* SetSpatialRef() */
1350 : /************************************************************************/
1351 :
1352 58 : CPLErr PCIDSK2Dataset::SetSpatialRef(const OGRSpatialReference *poSRS)
1353 :
1354 : {
1355 58 : PCIDSKGeoref *poGeoref = nullptr;
1356 :
1357 : try
1358 : {
1359 58 : PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
1360 58 : poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
1361 : }
1362 0 : catch (const PCIDSKException &)
1363 : {
1364 : // I should really check whether this is an expected issue.
1365 : }
1366 :
1367 58 : if (poGeoref == nullptr)
1368 : {
1369 0 : return GDALPamDataset::SetSpatialRef(poSRS);
1370 : }
1371 :
1372 58 : char *pszGeosys = nullptr;
1373 58 : char *pszUnits = nullptr;
1374 58 : double *padfPrjParams = nullptr;
1375 :
1376 58 : if (poSRS == nullptr || poSRS->exportToPCI(&pszGeosys, &pszUnits,
1377 : &padfPrjParams) != OGRERR_NONE)
1378 : {
1379 0 : return GDALPamDataset::SetSpatialRef(poSRS);
1380 : }
1381 :
1382 58 : if (GetAccess() == GA_ReadOnly)
1383 : {
1384 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1385 : "Unable to set projection on read-only file.");
1386 0 : CPLFree(pszGeosys);
1387 0 : CPLFree(pszUnits);
1388 0 : CPLFree(padfPrjParams);
1389 0 : return CE_Failure;
1390 : }
1391 :
1392 : try
1393 : {
1394 58 : GDALGeoTransform gt;
1395 58 : poGeoref->GetTransform(gt.xorig, gt.xscale, gt.xrot, gt.yorig, gt.yrot,
1396 58 : gt.yscale);
1397 :
1398 58 : poGeoref->WriteSimple(pszGeosys, gt.xorig, gt.xscale, gt.xrot, gt.yorig,
1399 58 : gt.yrot, gt.yscale);
1400 :
1401 116 : std::vector<double> adfPCIParameters;
1402 1044 : for (unsigned int i = 0; i < 17; i++)
1403 986 : adfPCIParameters.push_back(padfPrjParams[i]);
1404 :
1405 58 : if (STARTS_WITH_CI(pszUnits, "FOOT"))
1406 0 : adfPCIParameters.push_back(
1407 0 : static_cast<double>(static_cast<int>(PCIDSK::UNIT_US_FOOT)));
1408 58 : else if (EQUALN(pszUnits, "INTL FOOT", 9))
1409 0 : adfPCIParameters.push_back(
1410 0 : static_cast<double>(static_cast<int>(PCIDSK::UNIT_INTL_FOOT)));
1411 58 : else if (EQUALN(pszUnits, "DEGREE", 6))
1412 50 : adfPCIParameters.push_back(
1413 50 : static_cast<double>(static_cast<int>(PCIDSK::UNIT_DEGREE)));
1414 : else
1415 8 : adfPCIParameters.push_back(
1416 8 : static_cast<double>(static_cast<int>(PCIDSK::UNIT_METER)));
1417 :
1418 58 : poGeoref->WriteParameters(adfPCIParameters);
1419 : }
1420 0 : catch (const PCIDSKException &ex)
1421 : {
1422 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1423 0 : return CE_Failure;
1424 : }
1425 :
1426 58 : CPLFree(pszGeosys);
1427 58 : CPLFree(pszUnits);
1428 58 : CPLFree(padfPrjParams);
1429 :
1430 58 : return CE_None;
1431 : }
1432 :
1433 : /************************************************************************/
1434 : /* GetSpatialRef() */
1435 : /************************************************************************/
1436 :
1437 10 : const OGRSpatialReference *PCIDSK2Dataset::GetSpatialRef() const
1438 : {
1439 10 : return GetSpatialRef(false);
1440 : }
1441 :
1442 6 : const OGRSpatialReference *PCIDSK2Dataset::GetSpatialRefRasterOnly() const
1443 : {
1444 6 : return GetSpatialRef(true);
1445 : }
1446 :
1447 : static thread_local int tlsEnableLayersInGetSpatialRefCounter = 0;
1448 :
1449 16 : const OGRSpatialReference *PCIDSK2Dataset::GetSpatialRef(bool bRasterOnly) const
1450 : {
1451 16 : if (tlsEnableLayersInGetSpatialRefCounter)
1452 3 : return nullptr;
1453 :
1454 13 : if (m_poSRS)
1455 3 : return m_poSRS;
1456 :
1457 10 : PCIDSKGeoref *poGeoref = nullptr;
1458 :
1459 : try
1460 : {
1461 10 : PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
1462 10 : poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
1463 : }
1464 0 : catch (const PCIDSKException &)
1465 : {
1466 : // I should really check whether this is an expected issue.
1467 : }
1468 :
1469 10 : if (poGeoref == nullptr)
1470 : {
1471 0 : ++tlsEnableLayersInGetSpatialRefCounter;
1472 : const OGRSpatialReference *poRet =
1473 0 : (bRasterOnly) ? GDALPamDataset::GetSpatialRefRasterOnly()
1474 0 : : GDALPamDataset::GetSpatialRef();
1475 0 : --tlsEnableLayersInGetSpatialRefCounter;
1476 0 : return poRet;
1477 : }
1478 :
1479 20 : CPLString osGeosys;
1480 10 : const char *pszUnits = nullptr;
1481 :
1482 20 : std::vector<double> adfParameters;
1483 10 : adfParameters.resize(18);
1484 :
1485 : try
1486 : {
1487 10 : osGeosys = poGeoref->GetGeosys();
1488 10 : adfParameters = poGeoref->GetParameters();
1489 : const UnitCode code =
1490 10 : static_cast<UnitCode>(static_cast<int>(adfParameters[16]));
1491 :
1492 10 : if (code == PCIDSK::UNIT_DEGREE)
1493 0 : pszUnits = "DEGREE";
1494 10 : else if (code == PCIDSK::UNIT_METER)
1495 0 : pszUnits = "METER";
1496 10 : else if (code == PCIDSK::UNIT_US_FOOT)
1497 0 : pszUnits = "FOOT";
1498 10 : else if (code == PCIDSK::UNIT_INTL_FOOT)
1499 0 : pszUnits = "INTL FOOT";
1500 : }
1501 0 : catch (const PCIDSKException &ex)
1502 : {
1503 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1504 : }
1505 :
1506 20 : OGRSpatialReference oSRS;
1507 10 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1508 10 : if (oSRS.importFromPCI(osGeosys, pszUnits, &(adfParameters[0])) ==
1509 : OGRERR_NONE)
1510 : {
1511 7 : m_poSRS = oSRS.Clone();
1512 7 : return m_poSRS;
1513 : }
1514 : else
1515 : {
1516 3 : ++tlsEnableLayersInGetSpatialRefCounter;
1517 : const OGRSpatialReference *poRet =
1518 3 : (bRasterOnly) ? GDALPamDataset::GetSpatialRefRasterOnly()
1519 0 : : GDALPamDataset::GetSpatialRef();
1520 3 : --tlsEnableLayersInGetSpatialRefCounter;
1521 3 : return poRet;
1522 : }
1523 : }
1524 :
1525 : /************************************************************************/
1526 : /* IBuildOverviews() */
1527 : /************************************************************************/
1528 :
1529 3 : CPLErr PCIDSK2Dataset::IBuildOverviews(
1530 : const char *pszResampling, int nOverviews, const int *panOverviewList,
1531 : int nListBands, const int *panBandList, GDALProgressFunc pfnProgress,
1532 : void *pProgressData, CSLConstList papszOptions)
1533 :
1534 : {
1535 : PCIDSK2Band *poBand =
1536 3 : reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[0]));
1537 :
1538 : /* -------------------------------------------------------------------- */
1539 : /* If RRD overviews requested, then invoke generic handling. */
1540 : /* -------------------------------------------------------------------- */
1541 3 : bool bUseGenericHandling = false;
1542 :
1543 3 : if (CPLTestBool(CPLGetConfigOption("USE_RRD", "NO")))
1544 : {
1545 1 : bUseGenericHandling = true;
1546 : }
1547 :
1548 : /* -------------------------------------------------------------------- */
1549 : /* If we don't have read access, then create the overviews */
1550 : /* externally. */
1551 : /* -------------------------------------------------------------------- */
1552 3 : if (GetAccess() != GA_Update)
1553 : {
1554 1 : CPLDebug("PCIDSK", "File open for read-only accessing, "
1555 : "creating overviews externally.");
1556 :
1557 1 : bUseGenericHandling = true;
1558 : }
1559 :
1560 3 : if (bUseGenericHandling)
1561 : {
1562 2 : if (poBand->GetOverviewCount() != 0)
1563 : {
1564 0 : CPLError(CE_Failure, CPLE_NotSupported,
1565 : "Cannot add external overviews when there are already "
1566 : "internal overviews");
1567 0 : return CE_Failure;
1568 : }
1569 :
1570 2 : return GDALDataset::IBuildOverviews(
1571 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
1572 2 : pfnProgress, pProgressData, papszOptions);
1573 : }
1574 :
1575 1 : if (nListBands == 0)
1576 0 : return CE_None;
1577 :
1578 : /* -------------------------------------------------------------------- */
1579 : /* Currently no support for clearing overviews. */
1580 : /* -------------------------------------------------------------------- */
1581 1 : if (nOverviews == 0)
1582 : {
1583 0 : CPLError(CE_Failure, CPLE_AppDefined,
1584 : "PCIDSK2 driver does not currently support clearing existing "
1585 : "overviews. ");
1586 0 : return CE_Failure;
1587 : }
1588 :
1589 : /* -------------------------------------------------------------------- */
1590 : /* Establish which of the overview levels we already have, and */
1591 : /* which are new. We assume that band 1 of the file is */
1592 : /* representative. */
1593 : /* -------------------------------------------------------------------- */
1594 :
1595 1 : int nNewOverviews = 0;
1596 : int *panNewOverviewList =
1597 1 : static_cast<int *>(CPLCalloc(sizeof(int), nOverviews));
1598 2 : std::vector<bool> abFoundOverviewFactor(nOverviews);
1599 2 : for (int i = 0; i < nOverviews && poBand != nullptr; i++)
1600 : {
1601 1 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
1602 : {
1603 0 : GDALRasterBand *poOverview = poBand->GetOverview(j);
1604 :
1605 : int nOvFactor =
1606 0 : GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(),
1607 : poOverview->GetYSize(), poBand->GetYSize());
1608 :
1609 0 : if (nOvFactor == panOverviewList[i] ||
1610 0 : nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
1611 : poBand->GetXSize(),
1612 : poBand->GetYSize()))
1613 0 : abFoundOverviewFactor[i] = true;
1614 : }
1615 :
1616 1 : if (!abFoundOverviewFactor[i])
1617 1 : panNewOverviewList[nNewOverviews++] = panOverviewList[i];
1618 : }
1619 :
1620 : /* -------------------------------------------------------------------- */
1621 : /* Create the overviews that are missing. */
1622 : /* -------------------------------------------------------------------- */
1623 2 : for (int i = 0; i < nNewOverviews; i++)
1624 : {
1625 : try
1626 : {
1627 : // conveniently our resampling values mostly match PCIDSK.
1628 2 : poFile->CreateOverviews(nListBands, panBandList,
1629 2 : panNewOverviewList[i], pszResampling);
1630 : }
1631 0 : catch (const PCIDSKException &ex)
1632 : {
1633 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1634 0 : CPLFree(panNewOverviewList);
1635 0 : return CE_Failure;
1636 : }
1637 : }
1638 :
1639 1 : CPLFree(panNewOverviewList);
1640 1 : panNewOverviewList = nullptr;
1641 :
1642 2 : for (int iBand = 0; iBand < nListBands; iBand++)
1643 : {
1644 : poBand =
1645 1 : reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[iBand]));
1646 1 : reinterpret_cast<PCIDSK2Band *>(poBand)->RefreshOverviewList();
1647 : }
1648 :
1649 : /* -------------------------------------------------------------------- */
1650 : /* Actually generate the overview imagery. */
1651 : /* -------------------------------------------------------------------- */
1652 1 : CPLErr eErr = CE_None;
1653 1 : std::vector<int> anRegenLevels;
1654 :
1655 : GDALRasterBand **papoOverviewBands = reinterpret_cast<GDALRasterBand **>(
1656 1 : CPLCalloc(sizeof(void *), nOverviews));
1657 :
1658 2 : for (int iBand = 0; iBand < nListBands && eErr == CE_None; iBand++)
1659 : {
1660 1 : nNewOverviews = 0;
1661 :
1662 : poBand =
1663 1 : reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[iBand]));
1664 :
1665 2 : for (int i = 0; i < nOverviews && poBand != nullptr; i++)
1666 : {
1667 1 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
1668 : {
1669 1 : GDALRasterBand *poOverview = poBand->GetOverview(j);
1670 :
1671 1 : int nOvFactor = GDALComputeOvFactor(
1672 : poOverview->GetXSize(), poBand->GetXSize(),
1673 : poOverview->GetYSize(), poBand->GetYSize());
1674 :
1675 1 : if (nOvFactor == panOverviewList[i] ||
1676 0 : nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
1677 : poBand->GetXSize(),
1678 : poBand->GetYSize()))
1679 : {
1680 1 : papoOverviewBands[nNewOverviews++] = poOverview;
1681 1 : anRegenLevels.push_back(j);
1682 1 : break;
1683 : }
1684 : }
1685 : }
1686 :
1687 1 : if (nNewOverviews > 0)
1688 : {
1689 1 : eErr = GDALRegenerateOverviewsEx(
1690 : (GDALRasterBandH)poBand, nNewOverviews,
1691 : reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
1692 : pszResampling, pfnProgress, pProgressData, papszOptions);
1693 :
1694 : // Mark the regenerated overviews as valid.
1695 2 : for (int i = 0; i < static_cast<int>(anRegenLevels.size()); i++)
1696 1 : poBand->poChannel->SetOverviewValidity(anRegenLevels[i], true);
1697 : }
1698 : }
1699 :
1700 1 : CPLFree(papoOverviewBands);
1701 :
1702 1 : return eErr;
1703 : }
1704 :
1705 : /************************************************************************/
1706 : /* PCIDSKTypeToGDAL() */
1707 : /************************************************************************/
1708 :
1709 481 : GDALDataType PCIDSK2Dataset::PCIDSKTypeToGDAL(eChanType eType)
1710 : {
1711 481 : switch (eType)
1712 : {
1713 343 : case CHN_8U:
1714 343 : return GDT_UInt8;
1715 :
1716 66 : case CHN_16U:
1717 66 : return GDT_UInt16;
1718 :
1719 18 : case CHN_16S:
1720 18 : return GDT_Int16;
1721 :
1722 18 : case CHN_32R:
1723 18 : return GDT_Float32;
1724 :
1725 0 : case CHN_BIT:
1726 0 : return GDT_UInt8;
1727 :
1728 0 : case CHN_C16U:
1729 0 : return GDT_CInt16;
1730 :
1731 18 : case CHN_C16S:
1732 18 : return GDT_CInt16;
1733 :
1734 18 : case CHN_C32R:
1735 18 : return GDT_CFloat32;
1736 :
1737 0 : default:
1738 0 : return GDT_Unknown;
1739 : }
1740 : }
1741 :
1742 : /************************************************************************/
1743 : /* Open() */
1744 : /************************************************************************/
1745 :
1746 137 : GDALDataset *PCIDSK2Dataset::Open(GDALOpenInfo *poOpenInfo)
1747 : {
1748 137 : if (!PCIDSKDriverIdentify(poOpenInfo))
1749 0 : return nullptr;
1750 :
1751 : /* -------------------------------------------------------------------- */
1752 : /* Try opening the file. */
1753 : /* -------------------------------------------------------------------- */
1754 137 : PCIDSKFile *poFile = nullptr;
1755 : const int nMaxBandCount =
1756 137 : atoi(CPLGetConfigOption("GDAL_MAX_BAND_COUNT", "65536"));
1757 : try
1758 : {
1759 278 : poFile = PCIDSK::Open(poOpenInfo->pszFilename,
1760 137 : poOpenInfo->eAccess == GA_ReadOnly ? "r" : "r+",
1761 : PCIDSK2GetInterfaces(), nMaxBandCount);
1762 136 : if (poFile == nullptr)
1763 : {
1764 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1765 : "Failed to re-open %s within PCIDSK driver.\n",
1766 : poOpenInfo->pszFilename);
1767 0 : return nullptr;
1768 : }
1769 :
1770 : const bool bValidRasterDimensions =
1771 136 : poFile->GetWidth() && poFile->GetHeight();
1772 136 : if (!bValidRasterDimensions &&
1773 0 : (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
1774 0 : (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0)
1775 : {
1776 0 : delete poFile;
1777 0 : return nullptr;
1778 : }
1779 :
1780 : /* Check if this is a vector-only PCIDSK file and that we are */
1781 : /* opened in raster-only mode */
1782 400 : if (poOpenInfo->eAccess == GA_ReadOnly &&
1783 128 : (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
1784 118 : (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0 &&
1785 267 : poFile->GetChannels() == 0 &&
1786 139 : poFile->GetSegment(PCIDSK::SEG_VEC, "") != nullptr)
1787 : {
1788 2 : CPLDebug("PCIDSK",
1789 : "This is a vector-only PCIDSK dataset, "
1790 : "but it has been opened in read-only in raster-only mode");
1791 2 : delete poFile;
1792 2 : return nullptr;
1793 : }
1794 : /* Reverse test */
1795 394 : if (poOpenInfo->eAccess == GA_ReadOnly &&
1796 126 : (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
1797 10 : (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
1798 260 : poFile->GetChannels() != 0 &&
1799 134 : poFile->GetSegment(PCIDSK::SEG_VEC, "") == nullptr)
1800 : {
1801 0 : CPLDebug("PCIDSK",
1802 : "This is a raster-only PCIDSK dataset, "
1803 : "but it has been opened in read-only in vector-only mode");
1804 0 : delete poFile;
1805 0 : return nullptr;
1806 : }
1807 :
1808 134 : return LLOpen(poOpenInfo->pszFilename, poFile, poOpenInfo->eAccess,
1809 134 : poOpenInfo->GetSiblingFiles());
1810 : }
1811 : /* -------------------------------------------------------------------- */
1812 : /* Trap exceptions. */
1813 : /* -------------------------------------------------------------------- */
1814 1 : catch (const PCIDSKException &ex)
1815 : {
1816 1 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1817 1 : delete poFile;
1818 1 : return nullptr;
1819 : }
1820 0 : catch (...)
1821 : {
1822 0 : CPLError(CE_Failure, CPLE_AppDefined,
1823 : "PCIDSK::Create() failed, unexpected exception.");
1824 0 : delete poFile;
1825 0 : return nullptr;
1826 : }
1827 : }
1828 :
1829 : /************************************************************************/
1830 : /* LLOpen() */
1831 : /* */
1832 : /* Low level variant of open that takes the preexisting */
1833 : /* PCIDSKFile. */
1834 : /************************************************************************/
1835 :
1836 245 : GDALDataset *PCIDSK2Dataset::LLOpen(const char *pszFilename,
1837 : PCIDSK::PCIDSKFile *poFile,
1838 : GDALAccess eAccessIn,
1839 : char **papszSiblingFiles)
1840 :
1841 : {
1842 245 : PCIDSK2Dataset *poDS = new PCIDSK2Dataset();
1843 : /* -------------------------------------------------------------------- */
1844 : /* Create a corresponding GDALDataset. */
1845 : /* -------------------------------------------------------------------- */
1846 245 : poDS->poFile = poFile;
1847 245 : poDS->eAccess = eAccessIn;
1848 245 : poDS->nRasterXSize = poFile->GetWidth();
1849 245 : poDS->nRasterYSize = poFile->GetHeight();
1850 :
1851 : const bool bValidRasterDimensions =
1852 245 : poFile->GetWidth() && poFile->GetHeight();
1853 245 : if (!bValidRasterDimensions)
1854 : {
1855 0 : poDS->nRasterXSize = 512;
1856 0 : poDS->nRasterYSize = 512;
1857 : }
1858 :
1859 : try
1860 : {
1861 :
1862 : /* --------------------------------------------------------------------
1863 : */
1864 : /* Are we specifically PIXEL or BAND interleaving? */
1865 : /* */
1866 : /* We don't set anything for FILE since it is harder to know if */
1867 : /* this is tiled or what the on disk interleaving is. */
1868 : /* --------------------------------------------------------------------
1869 : */
1870 245 : if (EQUAL(poFile->GetInterleaving().c_str(), "PIXEL"))
1871 0 : poDS->SetMetadataItem(GDAL_MDD_IMAGE_STRUCTURE, "PIXEL",
1872 : GDAL_MDD_IMAGE_STRUCTURE);
1873 245 : else if (EQUAL(poFile->GetInterleaving().c_str(), "BAND"))
1874 217 : poDS->SetMetadataItem(GDAL_MDD_IMAGE_STRUCTURE, "BAND",
1875 : GDAL_MDD_IMAGE_STRUCTURE);
1876 :
1877 : /* --------------------------------------------------------------------
1878 : */
1879 : /* Create band objects. */
1880 : /* --------------------------------------------------------------------
1881 : */
1882 480 : for (int iBand = 0;
1883 480 : bValidRasterDimensions && iBand < poFile->GetChannels(); iBand++)
1884 : {
1885 235 : PCIDSKChannel *poChannel = poFile->GetChannel(iBand + 1);
1886 470 : if (poChannel->GetBlockWidth() <= 0 ||
1887 235 : poChannel->GetBlockHeight() <= 0)
1888 : {
1889 0 : delete poDS;
1890 0 : return nullptr;
1891 : }
1892 :
1893 235 : if (PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType()) ==
1894 : GDT_Unknown)
1895 : {
1896 0 : continue;
1897 : }
1898 :
1899 235 : poDS->SetBand(poDS->GetRasterCount() + 1,
1900 235 : new PCIDSK2Band(poFile, poChannel));
1901 : }
1902 :
1903 : /* --------------------------------------------------------------------
1904 : */
1905 : /* Create band objects for bitmap segments. */
1906 : /* --------------------------------------------------------------------
1907 : */
1908 245 : int nLastBitmapSegment = 0;
1909 245 : PCIDSKSegment *poBitSeg = nullptr;
1910 :
1911 490 : while (bValidRasterDimensions &&
1912 490 : (poBitSeg = poFile->GetSegment(SEG_BIT, "",
1913 245 : nLastBitmapSegment)) != nullptr)
1914 : {
1915 0 : PCIDSKChannel *poChannel = dynamic_cast<PCIDSKChannel *>(poBitSeg);
1916 0 : if (poChannel == nullptr || poChannel->GetBlockWidth() <= 0 ||
1917 0 : poChannel->GetBlockHeight() <= 0)
1918 : {
1919 0 : delete poDS;
1920 0 : return nullptr;
1921 : }
1922 :
1923 0 : if (PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType()) ==
1924 : GDT_Unknown)
1925 : {
1926 0 : continue;
1927 : }
1928 :
1929 0 : poDS->SetBand(poDS->GetRasterCount() + 1,
1930 0 : new PCIDSK2Band(poChannel));
1931 :
1932 0 : nLastBitmapSegment = poBitSeg->GetSegmentNumber();
1933 : }
1934 :
1935 : /* --------------------------------------------------------------------
1936 : */
1937 : /* Create vector layers from vector segments. */
1938 : /* --------------------------------------------------------------------
1939 : */
1940 245 : PCIDSK::PCIDSKSegment *segobj = poFile->GetSegment(PCIDSK::SEG_VEC, "");
1941 340 : for (; segobj != nullptr;
1942 95 : segobj = poFile->GetSegment(PCIDSK::SEG_VEC, "",
1943 95 : segobj->GetSegmentNumber()))
1944 : {
1945 : PCIDSK::PCIDSKVectorSegment *poVecSeg =
1946 95 : dynamic_cast<PCIDSK::PCIDSKVectorSegment *>(segobj);
1947 95 : if (poVecSeg)
1948 95 : poDS->apoLayers.push_back(new OGRPCIDSKLayer(
1949 95 : poDS, segobj, poVecSeg, eAccessIn == GA_Update));
1950 : }
1951 :
1952 : /* --------------------------------------------------------------------
1953 : */
1954 : /* Process RPC segment, if there is one. */
1955 : /* --------------------------------------------------------------------
1956 : */
1957 245 : poDS->ProcessRPC();
1958 :
1959 : /* --------------------------------------------------------------------
1960 : */
1961 : /* Initialize any PAM information. */
1962 : /* --------------------------------------------------------------------
1963 : */
1964 245 : poDS->SetDescription(pszFilename);
1965 245 : poDS->TryLoadXML(papszSiblingFiles);
1966 :
1967 : /* --------------------------------------------------------------------
1968 : */
1969 : /* Open overviews. */
1970 : /* --------------------------------------------------------------------
1971 : */
1972 245 : poDS->oOvManager.Initialize(poDS, pszFilename, papszSiblingFiles);
1973 :
1974 245 : return poDS;
1975 : }
1976 :
1977 : /* -------------------------------------------------------------------- */
1978 : /* Trap exceptions. */
1979 : /* -------------------------------------------------------------------- */
1980 0 : catch (const PCIDSKException &ex)
1981 : {
1982 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1983 : }
1984 0 : catch (...)
1985 : {
1986 0 : CPLError(CE_Failure, CPLE_AppDefined,
1987 : "PCIDSK SDK Failure in Open(), unexpected exception.");
1988 : }
1989 :
1990 : /* -------------------------------------------------------------------- */
1991 : /* In case of exception, close dataset */
1992 : /* -------------------------------------------------------------------- */
1993 0 : delete poDS;
1994 :
1995 0 : return nullptr;
1996 : }
1997 :
1998 : /************************************************************************/
1999 : /* Create() */
2000 : /************************************************************************/
2001 :
2002 125 : GDALDataset *PCIDSK2Dataset::Create(const char *pszFilename, int nXSize,
2003 : int nYSize, int nBandsIn,
2004 : GDALDataType eType,
2005 : CSLConstList papszParamList)
2006 :
2007 : {
2008 : /* -------------------------------------------------------------------- */
2009 : /* Prepare channel type list. */
2010 : /* -------------------------------------------------------------------- */
2011 250 : std::vector<eChanType> aeChanTypes;
2012 :
2013 125 : if (eType == GDT_Float32)
2014 3 : aeChanTypes.resize(std::max(1, nBandsIn), CHN_32R);
2015 122 : else if (eType == GDT_Int16)
2016 3 : aeChanTypes.resize(std::max(1, nBandsIn), CHN_16S);
2017 119 : else if (eType == GDT_UInt16)
2018 11 : aeChanTypes.resize(std::max(1, nBandsIn), CHN_16U);
2019 108 : else if (eType == GDT_CInt16)
2020 3 : aeChanTypes.resize(std::max(1, nBandsIn), CHN_C16S);
2021 105 : else if (eType == GDT_CFloat32)
2022 3 : aeChanTypes.resize(std::max(1, nBandsIn), CHN_C32R);
2023 : else
2024 102 : aeChanTypes.resize(std::max(1, nBandsIn), CHN_8U);
2025 :
2026 : /* -------------------------------------------------------------------- */
2027 : /* Reformat options. Currently no support for jpeg compression */
2028 : /* quality. */
2029 : /* -------------------------------------------------------------------- */
2030 250 : CPLString osOptions;
2031 125 : const char *pszValue = CSLFetchNameValue(papszParamList, "INTERLEAVING");
2032 125 : if (pszValue == nullptr)
2033 117 : pszValue = "BAND";
2034 :
2035 125 : osOptions = pszValue;
2036 :
2037 125 : if (osOptions == "TILED")
2038 : {
2039 7 : pszValue = CSLFetchNameValue(papszParamList, "TILESIZE");
2040 7 : if (pszValue != nullptr)
2041 6 : osOptions += pszValue;
2042 :
2043 7 : pszValue = CSLFetchNameValue(papszParamList, GDALMD_COMPRESSION);
2044 7 : if (pszValue != nullptr)
2045 : {
2046 4 : osOptions += " ";
2047 4 : osOptions += pszValue;
2048 : }
2049 :
2050 7 : pszValue = CSLFetchNameValue(papszParamList, "TILEVERSION");
2051 7 : if (pszValue != nullptr)
2052 : {
2053 4 : osOptions += " TILEV";
2054 4 : osOptions += pszValue;
2055 : }
2056 : }
2057 :
2058 : /* -------------------------------------------------------------------- */
2059 : /* Try creation. */
2060 : /* -------------------------------------------------------------------- */
2061 :
2062 : try
2063 : {
2064 125 : if (nBandsIn == 0)
2065 : {
2066 43 : nXSize = 512;
2067 43 : nYSize = 512;
2068 : }
2069 278 : PCIDSKFile *poFile = PCIDSK::Create(pszFilename, nXSize, nYSize,
2070 125 : nBandsIn, &(aeChanTypes[0]),
2071 : osOptions, PCIDSK2GetInterfaces());
2072 :
2073 : /* --------------------------------------------------------------------
2074 : */
2075 : /* Apply band descriptions, if provided as creation options. */
2076 : /* --------------------------------------------------------------------
2077 : */
2078 133 : for (size_t i = 0;
2079 133 : papszParamList != nullptr && papszParamList[i] != nullptr; i++)
2080 : {
2081 22 : if (STARTS_WITH_CI(papszParamList[i], "BANDDESC"))
2082 : {
2083 0 : int nBand = atoi(papszParamList[i] + 8);
2084 0 : const char *pszDescription = strstr(papszParamList[i], "=");
2085 0 : if (pszDescription && nBand > 0 && nBand <= nBandsIn)
2086 : {
2087 0 : poFile->GetChannel(nBand)->SetDescription(pszDescription +
2088 0 : 1);
2089 : }
2090 : }
2091 : }
2092 :
2093 111 : return LLOpen(pszFilename, poFile, GA_Update);
2094 : }
2095 : /* -------------------------------------------------------------------- */
2096 : /* Trap exceptions. */
2097 : /* -------------------------------------------------------------------- */
2098 28 : catch (const PCIDSKException &ex)
2099 : {
2100 14 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
2101 : }
2102 0 : catch (...)
2103 : {
2104 0 : CPLError(CE_Failure, CPLE_AppDefined,
2105 : "PCIDSK::Create() failed, unexpected exception.");
2106 : }
2107 :
2108 14 : return nullptr;
2109 : }
2110 :
2111 : /************************************************************************/
2112 : /* TestCapability() */
2113 : /************************************************************************/
2114 :
2115 79 : int PCIDSK2Dataset::TestCapability(const char *pszCap) const
2116 :
2117 : {
2118 79 : if (EQUAL(pszCap, ODsCCreateLayer))
2119 37 : return eAccess == GA_Update;
2120 42 : if (EQUAL(pszCap, ODsCRandomLayerWrite))
2121 0 : return eAccess == GA_Update;
2122 42 : if (EQUAL(pszCap, ODsCZGeometries))
2123 12 : return TRUE;
2124 :
2125 30 : return FALSE;
2126 : }
2127 :
2128 : /************************************************************************/
2129 : /* GetLayer() */
2130 : /************************************************************************/
2131 :
2132 1655 : const OGRLayer *PCIDSK2Dataset::GetLayer(int iLayer) const
2133 :
2134 : {
2135 1655 : if (iLayer < 0 || iLayer >= static_cast<int>(apoLayers.size()))
2136 2 : return nullptr;
2137 :
2138 1653 : return apoLayers[iLayer];
2139 : }
2140 :
2141 : /************************************************************************/
2142 : /* ICreateLayer() */
2143 : /************************************************************************/
2144 :
2145 1089 : OGRLayer *PCIDSK2Dataset::ICreateLayer(const char *pszLayerName,
2146 : const OGRGeomFieldDefn *poGeomFieldDefn,
2147 : CSLConstList /*papszOptions*/)
2148 : {
2149 : /* -------------------------------------------------------------------- */
2150 : /* Verify we are in update mode. */
2151 : /* -------------------------------------------------------------------- */
2152 1089 : if (eAccess != GA_Update)
2153 : {
2154 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
2155 : "Data source %s opened read-only.\n"
2156 : "New layer %s cannot be created.\n",
2157 0 : GetDescription(), pszLayerName);
2158 0 : return nullptr;
2159 : }
2160 :
2161 1089 : const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
2162 : const auto poSRS =
2163 1089 : poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
2164 :
2165 : /* -------------------------------------------------------------------- */
2166 : /* Figure out what type of layer we need. */
2167 : /* -------------------------------------------------------------------- */
2168 2178 : std::string osLayerType;
2169 :
2170 1089 : switch (wkbFlatten(eType))
2171 : {
2172 10 : case wkbPoint:
2173 10 : osLayerType = "POINTS";
2174 10 : break;
2175 :
2176 10 : case wkbLineString:
2177 10 : osLayerType = "ARCS";
2178 10 : break;
2179 :
2180 6 : case wkbPolygon:
2181 6 : osLayerType = "WHOLE_POLYGONS";
2182 6 : break;
2183 :
2184 7 : case wkbNone:
2185 7 : osLayerType = "TABLE";
2186 7 : break;
2187 :
2188 1056 : default:
2189 1056 : break;
2190 : }
2191 :
2192 : /* -------------------------------------------------------------------- */
2193 : /* Create the segment. */
2194 : /* -------------------------------------------------------------------- */
2195 : int nSegNum;
2196 : try
2197 : {
2198 1093 : nSegNum = poFile->CreateSegment(pszLayerName, "", PCIDSK::SEG_VEC, 0L);
2199 : }
2200 1 : catch (const PCIDSKException &ex)
2201 : {
2202 1 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
2203 1 : return nullptr;
2204 : }
2205 1088 : PCIDSK::PCIDSKSegment *poSeg = poFile->GetSegment(nSegNum);
2206 : PCIDSK::PCIDSKVectorSegment *poVecSeg =
2207 1088 : dynamic_cast<PCIDSK::PCIDSKVectorSegment *>(poSeg);
2208 1088 : if (poVecSeg == nullptr)
2209 0 : return nullptr;
2210 :
2211 1088 : if (osLayerType != "")
2212 33 : poSeg->SetMetadataValue("LAYER_TYPE", osLayerType);
2213 :
2214 : /* -------------------------------------------------------------------- */
2215 : /* Do we need to apply a coordinate system? */
2216 : /* -------------------------------------------------------------------- */
2217 1088 : char *pszGeosys = nullptr;
2218 1088 : char *pszUnits = nullptr;
2219 1088 : double *padfPrjParams = nullptr;
2220 :
2221 1088 : if (poSRS != nullptr && poSRS->exportToPCI(&pszGeosys, &pszUnits,
2222 : &padfPrjParams) == OGRERR_NONE)
2223 : {
2224 : try
2225 : {
2226 6 : std::vector<double> adfPCIParameters;
2227 :
2228 108 : for (int i = 0; i < 17; i++)
2229 102 : adfPCIParameters.push_back(padfPrjParams[i]);
2230 :
2231 6 : if (STARTS_WITH_CI(pszUnits, "FOOT"))
2232 0 : adfPCIParameters.push_back(static_cast<double>(
2233 : static_cast<int>(PCIDSK::UNIT_US_FOOT)));
2234 6 : else if (STARTS_WITH_CI(pszUnits, "INTL FOOT"))
2235 0 : adfPCIParameters.push_back(static_cast<double>(
2236 : static_cast<int>(PCIDSK::UNIT_INTL_FOOT)));
2237 6 : else if (STARTS_WITH_CI(pszUnits, "DEGREE"))
2238 2 : adfPCIParameters.push_back(
2239 2 : static_cast<double>(static_cast<int>(PCIDSK::UNIT_DEGREE)));
2240 : else
2241 4 : adfPCIParameters.push_back(
2242 4 : static_cast<double>(static_cast<int>(PCIDSK::UNIT_METER)));
2243 :
2244 6 : poVecSeg->SetProjection(pszGeosys, adfPCIParameters);
2245 : }
2246 0 : catch (const PCIDSKException &ex)
2247 : {
2248 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
2249 : }
2250 :
2251 6 : CPLFree(pszGeosys);
2252 6 : CPLFree(pszUnits);
2253 6 : CPLFree(padfPrjParams);
2254 : }
2255 :
2256 : /* -------------------------------------------------------------------- */
2257 : /* Create the layer object. */
2258 : /* -------------------------------------------------------------------- */
2259 :
2260 1088 : apoLayers.push_back(new OGRPCIDSKLayer(this, poSeg, poVecSeg, TRUE));
2261 :
2262 1088 : return apoLayers.back();
2263 : }
2264 :
2265 : /************************************************************************/
2266 : /* GDALRegister_PCIDSK() */
2267 : /************************************************************************/
2268 :
2269 14 : void GDALRegister_PCIDSK()
2270 :
2271 : {
2272 14 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
2273 0 : return;
2274 :
2275 14 : GDALDriver *poDriver = new GDALDriver();
2276 14 : PCIDSKDriverSetCommonMetadata(poDriver);
2277 :
2278 14 : poDriver->pfnOpen = PCIDSK2Dataset::Open;
2279 14 : poDriver->pfnCreate = PCIDSK2Dataset::Create;
2280 :
2281 14 : GetGDALDriverManager()->RegisterDriver(poDriver);
2282 : }
|