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