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 231 : PCIDSK2Band::PCIDSK2Band(PCIDSKFile *poFileIn, PCIDSKChannel *poChannelIn)
36 :
37 : {
38 231 : Initialize();
39 :
40 231 : poFile = poFileIn;
41 231 : poChannel = poChannelIn;
42 :
43 231 : nBlockXSize = static_cast<int>(poChannel->GetBlockWidth());
44 231 : nBlockYSize = static_cast<int>(poChannel->GetBlockHeight());
45 :
46 231 : eDataType = PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType());
47 :
48 231 : 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 231 : RefreshOverviewList();
56 231 : }
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 242 : void PCIDSK2Band::Initialize()
98 :
99 : {
100 242 : papszLastMDListValue = nullptr;
101 :
102 242 : poChannel = nullptr;
103 242 : poFile = nullptr;
104 242 : poDS = nullptr;
105 :
106 242 : bCheckedForColorTable = false;
107 242 : poColorTable = nullptr;
108 242 : nPCTSegNumber = -1;
109 :
110 242 : papszCategoryNames = nullptr;
111 242 : }
112 :
113 : /************************************************************************/
114 : /* ~PCIDSK2Band() */
115 : /************************************************************************/
116 :
117 726 : PCIDSK2Band::~PCIDSK2Band()
118 :
119 : {
120 253 : while (!apoOverviews.empty())
121 : {
122 11 : delete apoOverviews.back();
123 11 : apoOverviews.pop_back();
124 : }
125 242 : CSLDestroy(papszLastMDListValue);
126 242 : CSLDestroy(papszCategoryNames);
127 :
128 242 : delete poColorTable;
129 484 : }
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 26 : bool PCIDSK2Band::CheckForColorTable()
235 :
236 : {
237 26 : if (bCheckedForColorTable || poFile == nullptr)
238 14 : return true;
239 :
240 12 : 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 36 : poChannel->GetMetadataValue("DEFAULT_PCT_REF");
251 12 : 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 23 : if (osDefaultPCT.empty() && poDS != nullptr &&
256 11 : poDS->GetRasterCount() == 1)
257 : {
258 11 : poPCTSeg = poFile->GetSegment(SEG_PCT, "");
259 11 : if (poPCTSeg != nullptr &&
260 11 : 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 12 : 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 24 : std::vector<std::string> aosMDKeys = poChannel->GetMetadataKeys();
304 :
305 22 : 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 12 : 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 14 : GDALColorInterp PCIDSK2Band::GetColorInterpretation()
479 :
480 : {
481 14 : CheckForColorTable();
482 :
483 14 : if (poColorTable != nullptr)
484 1 : return GCI_PaletteIndex;
485 :
486 13 : return GDALPamRasterBand::GetColorInterpretation();
487 : }
488 :
489 : /************************************************************************/
490 : /* RefreshOverviewList() */
491 : /************************************************************************/
492 :
493 232 : void PCIDSK2Band::RefreshOverviewList()
494 :
495 : {
496 : /* -------------------------------------------------------------------- */
497 : /* Clear existing overviews. */
498 : /* -------------------------------------------------------------------- */
499 232 : while (!apoOverviews.empty())
500 : {
501 0 : delete apoOverviews.back();
502 0 : apoOverviews.pop_back();
503 : }
504 :
505 : /* -------------------------------------------------------------------- */
506 : /* Fetch overviews. */
507 : /* -------------------------------------------------------------------- */
508 243 : 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 232 : }
515 :
516 : /************************************************************************/
517 : /* IReadBlock() */
518 : /************************************************************************/
519 :
520 261 : CPLErr PCIDSK2Band::IReadBlock(int iBlockX, int iBlockY, void *pData)
521 :
522 : {
523 : try
524 : {
525 261 : poChannel->ReadBlock(iBlockX + iBlockY * nBlocksPerRow, pData);
526 :
527 : // Do we need to upsample 1bit to 8bit?
528 261 : 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 261 : 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 516 : CPLErr PCIDSK2Band::IWriteBlock(int iBlockX, int iBlockY, void *pData)
555 :
556 : {
557 : try
558 : {
559 516 : 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 516 : 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 1 : CPLErr PCIDSK2Band::SetMetadata(char **papszMD, const char *pszDomain)
601 :
602 : {
603 : /* -------------------------------------------------------------------- */
604 : /* PCIDSK only supports metadata in the default domain. */
605 : /* -------------------------------------------------------------------- */
606 1 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
607 0 : return GDALPamRasterBand::SetMetadata(papszMD, pszDomain);
608 :
609 : /* -------------------------------------------------------------------- */
610 : /* Set each item individually. */
611 : /* -------------------------------------------------------------------- */
612 1 : CSLDestroy(papszLastMDListValue);
613 1 : papszLastMDListValue = nullptr;
614 1 : m_oCacheMetadataItem.clear();
615 :
616 1 : 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 3 : for (int iItem = 0; papszMD && papszMD[iItem]; iItem++)
626 : {
627 2 : char *pszItemName = nullptr;
628 :
629 : const char *pszItemValue =
630 2 : CPLParseNameValue(papszMD[iItem], &pszItemName);
631 2 : if (pszItemName != nullptr)
632 : {
633 2 : poChannel->SetMetadataValue(pszItemName, pszItemValue);
634 2 : 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 1 : return CE_None;
645 : }
646 :
647 : /************************************************************************/
648 : /* SetMetadataItem() */
649 : /************************************************************************/
650 :
651 5 : 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 5 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
659 1 : return GDALPamRasterBand::SetMetadataItem(pszName, pszValue, pszDomain);
660 :
661 : /* -------------------------------------------------------------------- */
662 : /* Set on the file. */
663 : /* -------------------------------------------------------------------- */
664 4 : CSLDestroy(papszLastMDListValue);
665 4 : papszLastMDListValue = nullptr;
666 4 : m_oCacheMetadataItem.clear();
667 :
668 4 : 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 4 : if (!pszValue)
678 0 : pszValue = "";
679 4 : 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 4 : 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 : /* GetMetadataItem() */
702 : /************************************************************************/
703 :
704 34 : const char *PCIDSK2Band::GetMetadataItem(const char *pszName,
705 : const char *pszDomain)
706 :
707 : {
708 : /* -------------------------------------------------------------------- */
709 : /* PCIDSK only supports metadata in the default domain. */
710 : /* -------------------------------------------------------------------- */
711 34 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
712 23 : return GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
713 :
714 : /* -------------------------------------------------------------------- */
715 : /* Try and fetch (use cached value if available) */
716 : /* -------------------------------------------------------------------- */
717 11 : auto oIter = m_oCacheMetadataItem.find(pszName);
718 11 : if (oIter != m_oCacheMetadataItem.end())
719 : {
720 5 : return oIter->second.empty() ? nullptr : oIter->second.c_str();
721 : }
722 :
723 12 : CPLString osValue;
724 : try
725 : {
726 6 : osValue = poChannel->GetMetadataValue(pszName);
727 : }
728 0 : catch (const PCIDSKException &ex)
729 : {
730 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
731 0 : return nullptr;
732 : }
733 :
734 6 : oIter = m_oCacheMetadataItem
735 6 : .insert(std::pair<std::string, std::string>(pszName, osValue))
736 : .first;
737 6 : return oIter->second.empty() ? nullptr : oIter->second.c_str();
738 : }
739 :
740 : /************************************************************************/
741 : /* GetMetadata() */
742 : /************************************************************************/
743 :
744 6 : char **PCIDSK2Band::GetMetadata(const char *pszDomain)
745 :
746 : {
747 : /* -------------------------------------------------------------------- */
748 : /* PCIDSK only supports metadata in the default domain. */
749 : /* -------------------------------------------------------------------- */
750 6 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
751 1 : return GDALPamRasterBand::GetMetadata(pszDomain);
752 :
753 : /* -------------------------------------------------------------------- */
754 : /* If we have a cached result, just use that. */
755 : /* -------------------------------------------------------------------- */
756 5 : if (papszLastMDListValue != nullptr)
757 0 : return papszLastMDListValue;
758 :
759 : /* -------------------------------------------------------------------- */
760 : /* Fetch and build the list. */
761 : /* -------------------------------------------------------------------- */
762 : try
763 : {
764 10 : std::vector<std::string> aosKeys = poChannel->GetMetadataKeys();
765 :
766 11 : for (unsigned int i = 0; i < aosKeys.size(); i++)
767 : {
768 6 : if (aosKeys[i].c_str()[0] == '_')
769 3 : continue;
770 :
771 6 : papszLastMDListValue = CSLSetNameValue(
772 3 : papszLastMDListValue, aosKeys[i].c_str(),
773 6 : poChannel->GetMetadataValue(aosKeys[i]).c_str());
774 : }
775 : }
776 0 : catch (const PCIDSKException &ex)
777 : {
778 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
779 0 : return nullptr;
780 : }
781 :
782 5 : return papszLastMDListValue;
783 : }
784 :
785 : /************************************************************************/
786 : /* ==================================================================== */
787 : /* PCIDSK2Dataset */
788 : /* ==================================================================== */
789 : /************************************************************************/
790 :
791 : /************************************************************************/
792 : /* PCIDSK2Dataset() */
793 : /************************************************************************/
794 :
795 243 : PCIDSK2Dataset::PCIDSK2Dataset()
796 243 : : papszLastMDListValue(nullptr), poFile(nullptr)
797 : {
798 243 : }
799 :
800 : /************************************************************************/
801 : /* ~PCIDSK2Dataset() */
802 : /************************************************************************/
803 :
804 : // FIXME? is an exception can really be thrown in the destructor, then it is
805 : // very dangerous !
806 : #ifdef _MSC_VER
807 : #pragma warning(push)
808 : #pragma warning(disable : 4702) /* unreachable code */
809 : #endif
810 486 : PCIDSK2Dataset::~PCIDSK2Dataset()
811 : {
812 243 : PCIDSK2Dataset::FlushCache(true);
813 :
814 1426 : while (!apoLayers.empty())
815 : {
816 1183 : delete apoLayers.back();
817 1183 : apoLayers.pop_back();
818 : }
819 :
820 243 : if (m_poSRS)
821 7 : m_poSRS->Release();
822 :
823 : try
824 : {
825 243 : if (poFile != nullptr)
826 243 : delete poFile;
827 : }
828 :
829 : /* -------------------------------------------------------------------- */
830 : /* Trap exceptions. */
831 : /* -------------------------------------------------------------------- */
832 : catch (const PCIDSKException &ex)
833 : {
834 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
835 : }
836 : catch (...)
837 : {
838 : CPLError(CE_Failure, CPLE_AppDefined,
839 : "PCIDSK SDK Failure in Close(), unexpected exception.");
840 : }
841 :
842 243 : CSLDestroy(papszLastMDListValue);
843 486 : }
844 : #ifdef _MSC_VER
845 : #pragma warning(pop)
846 : #endif
847 :
848 : /************************************************************************/
849 : /* GetFileList() */
850 : /************************************************************************/
851 :
852 57 : char **PCIDSK2Dataset::GetFileList()
853 :
854 : {
855 57 : char **papszFileList = GDALPamDataset::GetFileList();
856 114 : CPLString osBaseDir = CPLGetPathSafe(GetDescription());
857 :
858 : try
859 : {
860 77 : for (int nChan = 1; nChan <= poFile->GetChannels(); nChan++)
861 : {
862 20 : PCIDSKChannel *poChannel = poFile->GetChannel(nChan);
863 40 : CPLString osChanFilename;
864 : uint64 image_offset, pixel_offset, line_offset;
865 : bool little_endian;
866 :
867 20 : poChannel->GetChanInfo(osChanFilename, image_offset, pixel_offset,
868 20 : line_offset, little_endian);
869 :
870 20 : if (osChanFilename != "")
871 : {
872 1 : papszFileList = CSLAddString(
873 : papszFileList,
874 2 : CPLProjectRelativeFilenameSafe(osBaseDir, osChanFilename)
875 : .c_str());
876 : }
877 : }
878 :
879 57 : return papszFileList;
880 : }
881 0 : catch (const PCIDSKException &ex)
882 : {
883 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
884 0 : return papszFileList;
885 : }
886 : }
887 :
888 : /************************************************************************/
889 : /* ProcessRPC() */
890 : /************************************************************************/
891 :
892 243 : void PCIDSK2Dataset::ProcessRPC()
893 :
894 : {
895 : /* -------------------------------------------------------------------- */
896 : /* Search all BIN segments looking for an RPC segment. */
897 : /* -------------------------------------------------------------------- */
898 243 : PCIDSKSegment *poSeg = poFile->GetSegment(SEG_BIN, "");
899 243 : PCIDSKRPCSegment *poRPCSeg = nullptr;
900 :
901 243 : while (poSeg != nullptr &&
902 0 : (poRPCSeg = dynamic_cast<PCIDSKRPCSegment *>(poSeg)) == nullptr)
903 :
904 : {
905 0 : poSeg = poFile->GetSegment(SEG_BIN, "", poSeg->GetSegmentNumber());
906 : }
907 :
908 243 : if (poRPCSeg == nullptr)
909 243 : return;
910 :
911 : /* -------------------------------------------------------------------- */
912 : /* Turn RPC segment into GDAL RFC 22 style metadata. */
913 : /* -------------------------------------------------------------------- */
914 : try
915 : {
916 0 : CPLString osValue;
917 : double dfLineOffset, dfLineScale, dfSampOffset, dfSampScale;
918 : double dfLatOffset, dfLatScale, dfLongOffset, dfLongScale,
919 : dfHeightOffset, dfHeightScale;
920 :
921 0 : poRPCSeg->GetRPCTranslationCoeffs(
922 : dfLongOffset, dfLongScale, dfLatOffset, dfLatScale, dfHeightOffset,
923 : dfHeightScale, dfSampOffset, dfSampScale, dfLineOffset,
924 0 : dfLineScale);
925 :
926 0 : osValue.Printf("%.16g", dfLineOffset);
927 0 : GDALPamDataset::SetMetadataItem("LINE_OFF", osValue, "RPC");
928 :
929 0 : osValue.Printf("%.16g", dfLineScale);
930 0 : GDALPamDataset::SetMetadataItem("LINE_SCALE", osValue, "RPC");
931 :
932 0 : osValue.Printf("%.16g", dfSampOffset);
933 0 : GDALPamDataset::SetMetadataItem("SAMP_OFF", osValue, "RPC");
934 :
935 0 : osValue.Printf("%.16g", dfSampScale);
936 0 : GDALPamDataset::SetMetadataItem("SAMP_SCALE", osValue, "RPC");
937 :
938 0 : osValue.Printf("%.16g", dfLongOffset);
939 0 : GDALPamDataset::SetMetadataItem("LONG_OFF", osValue, "RPC");
940 :
941 0 : osValue.Printf("%.16g", dfLongScale);
942 0 : GDALPamDataset::SetMetadataItem("LONG_SCALE", osValue, "RPC");
943 :
944 0 : osValue.Printf("%.16g", dfLatOffset);
945 0 : GDALPamDataset::SetMetadataItem("LAT_OFF", osValue, "RPC");
946 :
947 0 : osValue.Printf("%.16g", dfLatScale);
948 0 : GDALPamDataset::SetMetadataItem("LAT_SCALE", osValue, "RPC");
949 :
950 0 : osValue.Printf("%.16g", dfHeightOffset);
951 0 : GDALPamDataset::SetMetadataItem("HEIGHT_OFF", osValue, "RPC");
952 :
953 0 : osValue.Printf("%.16g", dfHeightScale);
954 0 : GDALPamDataset::SetMetadataItem("HEIGHT_SCALE", osValue, "RPC");
955 :
956 0 : if (poRPCSeg->GetXNumerator().size() != 20 ||
957 0 : poRPCSeg->GetXDenominator().size() != 20 ||
958 0 : poRPCSeg->GetYNumerator().size() != 20 ||
959 0 : poRPCSeg->GetYDenominator().size() != 20)
960 : {
961 0 : GDALPamDataset::SetMetadata(nullptr, "RPC");
962 0 : CPLError(CE_Failure, CPLE_AppDefined,
963 : "Did not get 20 values in the RPC coefficients lists.");
964 0 : return;
965 : }
966 :
967 0 : std::vector<double> adfCoef = poRPCSeg->GetYNumerator();
968 0 : CPLString osCoefList = "";
969 0 : for (int i = 0; i < 20; i++)
970 : {
971 0 : osValue.Printf("%.16g ", adfCoef[i]);
972 0 : osCoefList += osValue;
973 : }
974 0 : GDALPamDataset::SetMetadataItem("LINE_NUM_COEFF", osCoefList, "RPC");
975 :
976 0 : adfCoef = poRPCSeg->GetYDenominator();
977 0 : osCoefList = "";
978 0 : for (int i = 0; i < 20; i++)
979 : {
980 0 : osValue.Printf("%.16g ", adfCoef[i]);
981 0 : osCoefList += osValue;
982 : }
983 0 : GDALPamDataset::SetMetadataItem("LINE_DEN_COEFF", osCoefList, "RPC");
984 :
985 0 : adfCoef = poRPCSeg->GetXNumerator();
986 0 : osCoefList = "";
987 0 : for (int i = 0; i < 20; i++)
988 : {
989 0 : osValue.Printf("%.16g ", adfCoef[i]);
990 0 : osCoefList += osValue;
991 : }
992 0 : GDALPamDataset::SetMetadataItem("SAMP_NUM_COEFF", osCoefList, "RPC");
993 :
994 0 : adfCoef = poRPCSeg->GetXDenominator();
995 0 : osCoefList = "";
996 0 : for (int i = 0; i < 20; i++)
997 : {
998 0 : osValue.Printf("%.16g ", adfCoef[i]);
999 0 : osCoefList += osValue;
1000 : }
1001 0 : GDALPamDataset::SetMetadataItem("SAMP_DEN_COEFF", osCoefList, "RPC");
1002 : }
1003 0 : catch (const PCIDSKException &ex)
1004 : {
1005 0 : GDALPamDataset::SetMetadata(nullptr, "RPC");
1006 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1007 : }
1008 : }
1009 :
1010 : /************************************************************************/
1011 : /* FlushCache() */
1012 : /************************************************************************/
1013 :
1014 254 : CPLErr PCIDSK2Dataset::FlushCache(bool bAtClosing)
1015 :
1016 : {
1017 254 : CPLErr eErr = GDALPamDataset::FlushCache(bAtClosing);
1018 :
1019 254 : if (poFile)
1020 : {
1021 : try
1022 : {
1023 254 : poFile->Synchronize();
1024 : }
1025 0 : catch (const PCIDSKException &ex)
1026 : {
1027 0 : eErr = CE_Failure;
1028 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1029 : }
1030 : }
1031 254 : return eErr;
1032 : }
1033 :
1034 : /************************************************************************/
1035 : /* SetMetadata() */
1036 : /************************************************************************/
1037 :
1038 25 : CPLErr PCIDSK2Dataset::SetMetadata(char **papszMD, const char *pszDomain)
1039 :
1040 : {
1041 : /* -------------------------------------------------------------------- */
1042 : /* PCIDSK only supports metadata in the default domain. */
1043 : /* -------------------------------------------------------------------- */
1044 25 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
1045 0 : return GDALPamDataset::SetMetadata(papszMD, pszDomain);
1046 :
1047 : /* -------------------------------------------------------------------- */
1048 : /* Set each item individually. */
1049 : /* -------------------------------------------------------------------- */
1050 25 : CSLDestroy(papszLastMDListValue);
1051 25 : papszLastMDListValue = nullptr;
1052 25 : m_oCacheMetadataItem.clear();
1053 :
1054 25 : if (GetAccess() == GA_ReadOnly)
1055 : {
1056 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1057 : "Unable to set metadata on read-only file.");
1058 0 : return CE_Failure;
1059 : }
1060 :
1061 : try
1062 : {
1063 57 : for (int iItem = 0; papszMD && papszMD[iItem]; iItem++)
1064 : {
1065 32 : char *pszItemName = nullptr;
1066 : const char *pszItemValue =
1067 32 : CPLParseNameValue(papszMD[iItem], &pszItemName);
1068 32 : if (pszItemName != nullptr)
1069 : {
1070 16 : poFile->SetMetadataValue(pszItemName, pszItemValue);
1071 16 : CPLFree(pszItemName);
1072 : }
1073 : }
1074 : }
1075 0 : catch (const PCIDSKException &ex)
1076 : {
1077 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1078 0 : return CE_Failure;
1079 : }
1080 :
1081 25 : return CE_None;
1082 : }
1083 :
1084 : /************************************************************************/
1085 : /* SetMetadataItem() */
1086 : /************************************************************************/
1087 :
1088 220 : CPLErr PCIDSK2Dataset::SetMetadataItem(const char *pszName,
1089 : const char *pszValue,
1090 : const char *pszDomain)
1091 :
1092 : {
1093 : /* -------------------------------------------------------------------- */
1094 : /* PCIDSK only supports metadata in the default domain. */
1095 : /* -------------------------------------------------------------------- */
1096 220 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
1097 216 : return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
1098 :
1099 : /* -------------------------------------------------------------------- */
1100 : /* Set on the file. */
1101 : /* -------------------------------------------------------------------- */
1102 4 : CSLDestroy(papszLastMDListValue);
1103 4 : papszLastMDListValue = nullptr;
1104 4 : m_oCacheMetadataItem.clear();
1105 :
1106 4 : if (GetAccess() == GA_ReadOnly)
1107 : {
1108 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1109 : "Unable to set metadata on read-only file.");
1110 0 : return CE_Failure;
1111 : }
1112 :
1113 : try
1114 : {
1115 4 : poFile->SetMetadataValue(pszName, pszValue);
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 4 : return CE_None;
1124 : }
1125 :
1126 : /************************************************************************/
1127 : /* GetMetadataDomainList() */
1128 : /************************************************************************/
1129 :
1130 0 : char **PCIDSK2Dataset::GetMetadataDomainList()
1131 : {
1132 0 : return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(),
1133 0 : TRUE, "", nullptr);
1134 : }
1135 :
1136 : /************************************************************************/
1137 : /* GetMetadataItem() */
1138 : /************************************************************************/
1139 :
1140 1239 : const char *PCIDSK2Dataset::GetMetadataItem(const char *pszName,
1141 : const char *pszDomain)
1142 :
1143 : {
1144 : /* -------------------------------------------------------------------- */
1145 : /* PCIDSK only supports metadata in the default domain. */
1146 : /* -------------------------------------------------------------------- */
1147 1239 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
1148 96 : return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
1149 :
1150 : /* -------------------------------------------------------------------- */
1151 : /* Try and fetch (use cached value if available) */
1152 : /* -------------------------------------------------------------------- */
1153 1143 : auto oIter = m_oCacheMetadataItem.find(pszName);
1154 1143 : if (oIter != m_oCacheMetadataItem.end())
1155 : {
1156 1054 : return oIter->second.empty() ? nullptr : oIter->second.c_str();
1157 : }
1158 :
1159 178 : CPLString osValue;
1160 : try
1161 : {
1162 89 : osValue = poFile->GetMetadataValue(pszName);
1163 : }
1164 0 : catch (const PCIDSKException &ex)
1165 : {
1166 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1167 0 : return nullptr;
1168 : }
1169 :
1170 89 : oIter = m_oCacheMetadataItem
1171 89 : .insert(std::pair<std::string, std::string>(pszName, osValue))
1172 : .first;
1173 89 : return oIter->second.empty() ? nullptr : oIter->second.c_str();
1174 : }
1175 :
1176 : /************************************************************************/
1177 : /* GetMetadata() */
1178 : /************************************************************************/
1179 :
1180 52 : char **PCIDSK2Dataset::GetMetadata(const char *pszDomain)
1181 :
1182 : {
1183 : /* -------------------------------------------------------------------- */
1184 : /* PCIDSK only supports metadata in the default domain. */
1185 : /* -------------------------------------------------------------------- */
1186 52 : if (pszDomain != nullptr && strlen(pszDomain) > 0)
1187 25 : return GDALPamDataset::GetMetadata(pszDomain);
1188 :
1189 : /* -------------------------------------------------------------------- */
1190 : /* If we have a cached result, just use that. */
1191 : /* -------------------------------------------------------------------- */
1192 27 : if (papszLastMDListValue != nullptr)
1193 3 : return papszLastMDListValue;
1194 :
1195 : /* -------------------------------------------------------------------- */
1196 : /* Fetch and build the list. */
1197 : /* -------------------------------------------------------------------- */
1198 : try
1199 : {
1200 48 : std::vector<std::string> aosKeys = poFile->GetMetadataKeys();
1201 :
1202 38 : for (unsigned int i = 0; i < aosKeys.size(); i++)
1203 : {
1204 14 : if (aosKeys[i].c_str()[0] == '_')
1205 2 : continue;
1206 :
1207 12 : papszLastMDListValue =
1208 12 : CSLSetNameValue(papszLastMDListValue, aosKeys[i].c_str(),
1209 24 : poFile->GetMetadataValue(aosKeys[i]).c_str());
1210 : }
1211 : }
1212 0 : catch (const PCIDSKException &ex)
1213 : {
1214 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1215 0 : return nullptr;
1216 : }
1217 :
1218 24 : return papszLastMDListValue;
1219 : }
1220 :
1221 : /************************************************************************/
1222 : /* SetGeoTransform() */
1223 : /************************************************************************/
1224 :
1225 56 : CPLErr PCIDSK2Dataset::SetGeoTransform(double *padfTransform)
1226 : {
1227 56 : PCIDSKGeoref *poGeoref = nullptr;
1228 : try
1229 : {
1230 56 : PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
1231 56 : poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
1232 : }
1233 0 : catch (const PCIDSKException &)
1234 : {
1235 : // I should really check whether this is an expected issue.
1236 : }
1237 :
1238 56 : if (poGeoref == nullptr)
1239 0 : return GDALPamDataset::SetGeoTransform(padfTransform);
1240 :
1241 56 : if (GetAccess() == GA_ReadOnly)
1242 : {
1243 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1244 : "Unable to set GeoTransform on read-only file.");
1245 0 : return CE_Failure;
1246 : }
1247 :
1248 : try
1249 : {
1250 56 : poGeoref->WriteSimple(poGeoref->GetGeosys(), padfTransform[0],
1251 56 : padfTransform[1], padfTransform[2],
1252 56 : padfTransform[3], padfTransform[4],
1253 56 : padfTransform[5]);
1254 : }
1255 0 : catch (const PCIDSKException &ex)
1256 : {
1257 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1258 0 : return CE_Failure;
1259 : }
1260 :
1261 56 : return CE_None;
1262 : }
1263 :
1264 : /************************************************************************/
1265 : /* GetGeoTransform() */
1266 : /************************************************************************/
1267 :
1268 44 : CPLErr PCIDSK2Dataset::GetGeoTransform(double *padfTransform)
1269 : {
1270 44 : PCIDSKGeoref *poGeoref = nullptr;
1271 : try
1272 : {
1273 44 : PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
1274 44 : poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
1275 : }
1276 0 : catch (const PCIDSKException &)
1277 : {
1278 : // I should really check whether this is an expected issue.
1279 : }
1280 :
1281 44 : if (poGeoref != nullptr)
1282 : {
1283 : try
1284 : {
1285 44 : poGeoref->GetTransform(padfTransform[0], padfTransform[1],
1286 44 : padfTransform[2], padfTransform[3],
1287 44 : padfTransform[4], padfTransform[5]);
1288 : }
1289 0 : catch (const PCIDSKException &ex)
1290 : {
1291 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1292 0 : return CE_Failure;
1293 : }
1294 :
1295 : // If we got anything non-default return it.
1296 44 : if (padfTransform[0] != 0.0 || padfTransform[1] != 1.0 ||
1297 3 : padfTransform[2] != 0.0 || padfTransform[3] != 0.0 ||
1298 3 : padfTransform[4] != 0.0 || padfTransform[5] != 1.0)
1299 41 : return CE_None;
1300 : }
1301 :
1302 : /* -------------------------------------------------------------------- */
1303 : /* Check for worldfile if we have no other georeferencing. */
1304 : /* -------------------------------------------------------------------- */
1305 3 : if (GDALReadWorldFile(GetDescription(), "pxw", padfTransform))
1306 0 : return CE_None;
1307 :
1308 3 : return GDALPamDataset::GetGeoTransform(padfTransform);
1309 : }
1310 :
1311 : /************************************************************************/
1312 : /* SetSpatialRef() */
1313 : /************************************************************************/
1314 :
1315 56 : CPLErr PCIDSK2Dataset::SetSpatialRef(const OGRSpatialReference *poSRS)
1316 :
1317 : {
1318 56 : PCIDSKGeoref *poGeoref = nullptr;
1319 :
1320 : try
1321 : {
1322 56 : PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
1323 56 : poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
1324 : }
1325 0 : catch (const PCIDSKException &)
1326 : {
1327 : // I should really check whether this is an expected issue.
1328 : }
1329 :
1330 56 : if (poGeoref == nullptr)
1331 : {
1332 0 : return GDALPamDataset::SetSpatialRef(poSRS);
1333 : }
1334 :
1335 56 : char *pszGeosys = nullptr;
1336 56 : char *pszUnits = nullptr;
1337 56 : double *padfPrjParams = nullptr;
1338 :
1339 56 : if (poSRS == nullptr || poSRS->exportToPCI(&pszGeosys, &pszUnits,
1340 : &padfPrjParams) != OGRERR_NONE)
1341 : {
1342 0 : return GDALPamDataset::SetSpatialRef(poSRS);
1343 : }
1344 :
1345 56 : if (GetAccess() == GA_ReadOnly)
1346 : {
1347 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1348 : "Unable to set projection on read-only file.");
1349 0 : CPLFree(pszGeosys);
1350 0 : CPLFree(pszUnits);
1351 0 : CPLFree(padfPrjParams);
1352 0 : return CE_Failure;
1353 : }
1354 :
1355 : try
1356 : {
1357 : double adfGT[6];
1358 56 : poGeoref->GetTransform(adfGT[0], adfGT[1], adfGT[2], adfGT[3], adfGT[4],
1359 56 : adfGT[5]);
1360 :
1361 56 : poGeoref->WriteSimple(pszGeosys, adfGT[0], adfGT[1], adfGT[2], adfGT[3],
1362 56 : adfGT[4], adfGT[5]);
1363 :
1364 112 : std::vector<double> adfPCIParameters;
1365 1008 : for (unsigned int i = 0; i < 17; i++)
1366 952 : adfPCIParameters.push_back(padfPrjParams[i]);
1367 :
1368 56 : if (STARTS_WITH_CI(pszUnits, "FOOT"))
1369 0 : adfPCIParameters.push_back(
1370 0 : static_cast<double>(static_cast<int>(PCIDSK::UNIT_US_FOOT)));
1371 56 : else if (EQUALN(pszUnits, "INTL FOOT", 9))
1372 0 : adfPCIParameters.push_back(
1373 0 : static_cast<double>(static_cast<int>(PCIDSK::UNIT_INTL_FOOT)));
1374 56 : else if (EQUALN(pszUnits, "DEGREE", 6))
1375 48 : adfPCIParameters.push_back(
1376 48 : static_cast<double>(static_cast<int>(PCIDSK::UNIT_DEGREE)));
1377 : else
1378 8 : adfPCIParameters.push_back(
1379 8 : static_cast<double>(static_cast<int>(PCIDSK::UNIT_METER)));
1380 :
1381 56 : poGeoref->WriteParameters(adfPCIParameters);
1382 : }
1383 0 : catch (const PCIDSKException &ex)
1384 : {
1385 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1386 0 : return CE_Failure;
1387 : }
1388 :
1389 56 : CPLFree(pszGeosys);
1390 56 : CPLFree(pszUnits);
1391 56 : CPLFree(padfPrjParams);
1392 :
1393 56 : return CE_None;
1394 : }
1395 :
1396 : /************************************************************************/
1397 : /* GetSpatialRef() */
1398 : /************************************************************************/
1399 :
1400 13 : const OGRSpatialReference *PCIDSK2Dataset::GetSpatialRef() const
1401 : {
1402 13 : if (m_poSRS)
1403 3 : return m_poSRS;
1404 :
1405 10 : PCIDSKGeoref *poGeoref = nullptr;
1406 :
1407 : try
1408 : {
1409 10 : PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
1410 10 : poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
1411 : }
1412 0 : catch (const PCIDSKException &)
1413 : {
1414 : // I should really check whether this is an expected issue.
1415 : }
1416 :
1417 10 : if (poGeoref == nullptr)
1418 : {
1419 0 : return GDALPamDataset::GetSpatialRef();
1420 : }
1421 :
1422 20 : CPLString osGeosys;
1423 10 : const char *pszUnits = nullptr;
1424 :
1425 20 : std::vector<double> adfParameters;
1426 10 : adfParameters.resize(18);
1427 :
1428 : try
1429 : {
1430 10 : osGeosys = poGeoref->GetGeosys();
1431 10 : adfParameters = poGeoref->GetParameters();
1432 : const UnitCode code =
1433 10 : static_cast<UnitCode>(static_cast<int>(adfParameters[16]));
1434 :
1435 10 : if (code == PCIDSK::UNIT_DEGREE)
1436 0 : pszUnits = "DEGREE";
1437 10 : else if (code == PCIDSK::UNIT_METER)
1438 0 : pszUnits = "METER";
1439 10 : else if (code == PCIDSK::UNIT_US_FOOT)
1440 0 : pszUnits = "FOOT";
1441 10 : else if (code == PCIDSK::UNIT_INTL_FOOT)
1442 0 : pszUnits = "INTL FOOT";
1443 : }
1444 0 : catch (const PCIDSKException &ex)
1445 : {
1446 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1447 : }
1448 :
1449 20 : OGRSpatialReference oSRS;
1450 10 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1451 10 : if (oSRS.importFromPCI(osGeosys, pszUnits, &(adfParameters[0])) ==
1452 : OGRERR_NONE)
1453 : {
1454 7 : m_poSRS = oSRS.Clone();
1455 7 : return m_poSRS;
1456 : }
1457 : else
1458 : {
1459 3 : return GDALPamDataset::GetSpatialRef();
1460 : }
1461 : }
1462 :
1463 : /************************************************************************/
1464 : /* IBuildOverviews() */
1465 : /************************************************************************/
1466 :
1467 3 : CPLErr PCIDSK2Dataset::IBuildOverviews(
1468 : const char *pszResampling, int nOverviews, const int *panOverviewList,
1469 : int nListBands, const int *panBandList, GDALProgressFunc pfnProgress,
1470 : void *pProgressData, CSLConstList papszOptions)
1471 :
1472 : {
1473 : PCIDSK2Band *poBand =
1474 3 : reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[0]));
1475 :
1476 : /* -------------------------------------------------------------------- */
1477 : /* If RRD overviews requested, then invoke generic handling. */
1478 : /* -------------------------------------------------------------------- */
1479 3 : bool bUseGenericHandling = false;
1480 :
1481 3 : if (CPLTestBool(CPLGetConfigOption("USE_RRD", "NO")))
1482 : {
1483 1 : bUseGenericHandling = true;
1484 : }
1485 :
1486 : /* -------------------------------------------------------------------- */
1487 : /* If we don't have read access, then create the overviews */
1488 : /* externally. */
1489 : /* -------------------------------------------------------------------- */
1490 3 : if (GetAccess() != GA_Update)
1491 : {
1492 1 : CPLDebug("PCIDSK", "File open for read-only accessing, "
1493 : "creating overviews externally.");
1494 :
1495 1 : bUseGenericHandling = true;
1496 : }
1497 :
1498 3 : if (bUseGenericHandling)
1499 : {
1500 2 : if (poBand->GetOverviewCount() != 0)
1501 : {
1502 0 : CPLError(CE_Failure, CPLE_NotSupported,
1503 : "Cannot add external overviews when there are already "
1504 : "internal overviews");
1505 0 : return CE_Failure;
1506 : }
1507 :
1508 2 : return GDALDataset::IBuildOverviews(
1509 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
1510 2 : pfnProgress, pProgressData, papszOptions);
1511 : }
1512 :
1513 1 : if (nListBands == 0)
1514 0 : return CE_None;
1515 :
1516 : /* -------------------------------------------------------------------- */
1517 : /* Currently no support for clearing overviews. */
1518 : /* -------------------------------------------------------------------- */
1519 1 : if (nOverviews == 0)
1520 : {
1521 0 : CPLError(CE_Failure, CPLE_AppDefined,
1522 : "PCIDSK2 driver does not currently support clearing existing "
1523 : "overviews. ");
1524 0 : return CE_Failure;
1525 : }
1526 :
1527 : /* -------------------------------------------------------------------- */
1528 : /* Establish which of the overview levels we already have, and */
1529 : /* which are new. We assume that band 1 of the file is */
1530 : /* representative. */
1531 : /* -------------------------------------------------------------------- */
1532 :
1533 1 : int nNewOverviews = 0;
1534 : int *panNewOverviewList =
1535 1 : reinterpret_cast<int *>(CPLCalloc(sizeof(int), nOverviews));
1536 2 : std::vector<bool> abFoundOverviewFactor(nOverviews);
1537 2 : for (int i = 0; i < nOverviews && poBand != nullptr; i++)
1538 : {
1539 1 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
1540 : {
1541 0 : GDALRasterBand *poOverview = poBand->GetOverview(j);
1542 :
1543 : int nOvFactor =
1544 0 : GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(),
1545 : poOverview->GetYSize(), poBand->GetYSize());
1546 :
1547 0 : if (nOvFactor == panOverviewList[i] ||
1548 0 : nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
1549 : poBand->GetXSize(),
1550 : poBand->GetYSize()))
1551 0 : abFoundOverviewFactor[i] = true;
1552 : }
1553 :
1554 1 : if (!abFoundOverviewFactor[i])
1555 1 : panNewOverviewList[nNewOverviews++] = panOverviewList[i];
1556 : }
1557 :
1558 : /* -------------------------------------------------------------------- */
1559 : /* Create the overviews that are missing. */
1560 : /* -------------------------------------------------------------------- */
1561 2 : for (int i = 0; i < nNewOverviews; i++)
1562 : {
1563 : try
1564 : {
1565 : // conveniently our resampling values mostly match PCIDSK.
1566 2 : poFile->CreateOverviews(nListBands, panBandList,
1567 2 : panNewOverviewList[i], pszResampling);
1568 : }
1569 0 : catch (const PCIDSKException &ex)
1570 : {
1571 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1572 0 : CPLFree(panNewOverviewList);
1573 0 : return CE_Failure;
1574 : }
1575 : }
1576 :
1577 1 : CPLFree(panNewOverviewList);
1578 1 : panNewOverviewList = nullptr;
1579 :
1580 2 : for (int iBand = 0; iBand < nListBands; iBand++)
1581 : {
1582 : poBand =
1583 1 : reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[iBand]));
1584 1 : reinterpret_cast<PCIDSK2Band *>(poBand)->RefreshOverviewList();
1585 : }
1586 :
1587 : /* -------------------------------------------------------------------- */
1588 : /* Actually generate the overview imagery. */
1589 : /* -------------------------------------------------------------------- */
1590 1 : CPLErr eErr = CE_None;
1591 1 : std::vector<int> anRegenLevels;
1592 :
1593 : GDALRasterBand **papoOverviewBands = reinterpret_cast<GDALRasterBand **>(
1594 1 : CPLCalloc(sizeof(void *), nOverviews));
1595 :
1596 2 : for (int iBand = 0; iBand < nListBands && eErr == CE_None; iBand++)
1597 : {
1598 1 : nNewOverviews = 0;
1599 :
1600 : poBand =
1601 1 : reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[iBand]));
1602 :
1603 2 : for (int i = 0; i < nOverviews && poBand != nullptr; i++)
1604 : {
1605 1 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
1606 : {
1607 1 : GDALRasterBand *poOverview = poBand->GetOverview(j);
1608 :
1609 1 : int nOvFactor = GDALComputeOvFactor(
1610 : poOverview->GetXSize(), poBand->GetXSize(),
1611 : poOverview->GetYSize(), poBand->GetYSize());
1612 :
1613 1 : if (nOvFactor == panOverviewList[i] ||
1614 0 : nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
1615 : poBand->GetXSize(),
1616 : poBand->GetYSize()))
1617 : {
1618 1 : papoOverviewBands[nNewOverviews++] = poOverview;
1619 1 : anRegenLevels.push_back(j);
1620 1 : break;
1621 : }
1622 : }
1623 : }
1624 :
1625 1 : if (nNewOverviews > 0)
1626 : {
1627 1 : eErr = GDALRegenerateOverviewsEx(
1628 : (GDALRasterBandH)poBand, nNewOverviews,
1629 : reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
1630 : pszResampling, pfnProgress, pProgressData, papszOptions);
1631 :
1632 : // Mark the regenerated overviews as valid.
1633 2 : for (int i = 0; i < static_cast<int>(anRegenLevels.size()); i++)
1634 1 : poBand->poChannel->SetOverviewValidity(anRegenLevels[i], true);
1635 : }
1636 : }
1637 :
1638 1 : CPLFree(papoOverviewBands);
1639 :
1640 1 : return eErr;
1641 : }
1642 :
1643 : /************************************************************************/
1644 : /* PCIDSKTypeToGDAL() */
1645 : /************************************************************************/
1646 :
1647 473 : GDALDataType PCIDSK2Dataset::PCIDSKTypeToGDAL(eChanType eType)
1648 : {
1649 473 : switch (eType)
1650 : {
1651 335 : case CHN_8U:
1652 335 : return GDT_Byte;
1653 :
1654 66 : case CHN_16U:
1655 66 : return GDT_UInt16;
1656 :
1657 18 : case CHN_16S:
1658 18 : return GDT_Int16;
1659 :
1660 18 : case CHN_32R:
1661 18 : return GDT_Float32;
1662 :
1663 0 : case CHN_BIT:
1664 0 : return GDT_Byte;
1665 :
1666 0 : case CHN_C16U:
1667 0 : return GDT_CInt16;
1668 :
1669 18 : case CHN_C16S:
1670 18 : return GDT_CInt16;
1671 :
1672 18 : case CHN_C32R:
1673 18 : return GDT_CFloat32;
1674 :
1675 0 : default:
1676 0 : return GDT_Unknown;
1677 : }
1678 : }
1679 :
1680 : /************************************************************************/
1681 : /* Open() */
1682 : /************************************************************************/
1683 :
1684 137 : GDALDataset *PCIDSK2Dataset::Open(GDALOpenInfo *poOpenInfo)
1685 : {
1686 137 : if (!PCIDSKDriverIdentify(poOpenInfo))
1687 0 : return nullptr;
1688 :
1689 : /* -------------------------------------------------------------------- */
1690 : /* Try opening the file. */
1691 : /* -------------------------------------------------------------------- */
1692 137 : PCIDSKFile *poFile = nullptr;
1693 : const int nMaxBandCount =
1694 137 : atoi(CPLGetConfigOption("GDAL_MAX_BAND_COUNT", "65536"));
1695 : try
1696 : {
1697 278 : poFile = PCIDSK::Open(poOpenInfo->pszFilename,
1698 137 : poOpenInfo->eAccess == GA_ReadOnly ? "r" : "r+",
1699 : PCIDSK2GetInterfaces(), nMaxBandCount);
1700 136 : if (poFile == nullptr)
1701 : {
1702 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1703 : "Failed to re-open %s within PCIDSK driver.\n",
1704 : poOpenInfo->pszFilename);
1705 0 : return nullptr;
1706 : }
1707 :
1708 : const bool bValidRasterDimensions =
1709 136 : poFile->GetWidth() && poFile->GetHeight();
1710 136 : if (!bValidRasterDimensions &&
1711 0 : (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
1712 0 : (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0)
1713 : {
1714 0 : delete poFile;
1715 0 : return nullptr;
1716 : }
1717 :
1718 : /* Check if this is a vector-only PCIDSK file and that we are */
1719 : /* opened in raster-only mode */
1720 402 : if (poOpenInfo->eAccess == GA_ReadOnly &&
1721 130 : (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
1722 120 : (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0 &&
1723 269 : poFile->GetChannels() == 0 &&
1724 139 : poFile->GetSegment(PCIDSK::SEG_VEC, "") != nullptr)
1725 : {
1726 2 : CPLDebug("PCIDSK",
1727 : "This is a vector-only PCIDSK dataset, "
1728 : "but it has been opened in read-only in raster-only mode");
1729 2 : delete poFile;
1730 2 : return nullptr;
1731 : }
1732 : /* Reverse test */
1733 396 : if (poOpenInfo->eAccess == GA_ReadOnly &&
1734 128 : (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
1735 10 : (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
1736 262 : poFile->GetChannels() != 0 &&
1737 134 : poFile->GetSegment(PCIDSK::SEG_VEC, "") == nullptr)
1738 : {
1739 0 : CPLDebug("PCIDSK",
1740 : "This is a raster-only PCIDSK dataset, "
1741 : "but it has been opened in read-only in vector-only mode");
1742 0 : delete poFile;
1743 0 : return nullptr;
1744 : }
1745 :
1746 134 : return LLOpen(poOpenInfo->pszFilename, poFile, poOpenInfo->eAccess,
1747 134 : poOpenInfo->GetSiblingFiles());
1748 : }
1749 : /* -------------------------------------------------------------------- */
1750 : /* Trap exceptions. */
1751 : /* -------------------------------------------------------------------- */
1752 1 : catch (const PCIDSKException &ex)
1753 : {
1754 1 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1755 1 : delete poFile;
1756 1 : return nullptr;
1757 : }
1758 0 : catch (...)
1759 : {
1760 0 : CPLError(CE_Failure, CPLE_AppDefined,
1761 : "PCIDSK::Create() failed, unexpected exception.");
1762 0 : delete poFile;
1763 0 : return nullptr;
1764 : }
1765 : }
1766 :
1767 : /************************************************************************/
1768 : /* LLOpen() */
1769 : /* */
1770 : /* Low level variant of open that takes the preexisting */
1771 : /* PCIDSKFile. */
1772 : /************************************************************************/
1773 :
1774 243 : GDALDataset *PCIDSK2Dataset::LLOpen(const char *pszFilename,
1775 : PCIDSK::PCIDSKFile *poFile,
1776 : GDALAccess eAccessIn,
1777 : char **papszSiblingFiles)
1778 :
1779 : {
1780 243 : PCIDSK2Dataset *poDS = new PCIDSK2Dataset();
1781 : /* -------------------------------------------------------------------- */
1782 : /* Create a corresponding GDALDataset. */
1783 : /* -------------------------------------------------------------------- */
1784 243 : poDS->poFile = poFile;
1785 243 : poDS->eAccess = eAccessIn;
1786 243 : poDS->nRasterXSize = poFile->GetWidth();
1787 243 : poDS->nRasterYSize = poFile->GetHeight();
1788 :
1789 : const bool bValidRasterDimensions =
1790 243 : poFile->GetWidth() && poFile->GetHeight();
1791 243 : if (!bValidRasterDimensions)
1792 : {
1793 0 : poDS->nRasterXSize = 512;
1794 0 : poDS->nRasterYSize = 512;
1795 : }
1796 :
1797 : try
1798 : {
1799 :
1800 : /* --------------------------------------------------------------------
1801 : */
1802 : /* Are we specifically PIXEL or BAND interleaving? */
1803 : /* */
1804 : /* We don't set anything for FILE since it is harder to know if */
1805 : /* this is tiled or what the on disk interleaving is. */
1806 : /* --------------------------------------------------------------------
1807 : */
1808 243 : if (EQUAL(poFile->GetInterleaving().c_str(), "PIXEL"))
1809 0 : poDS->SetMetadataItem("IMAGE_STRUCTURE", "PIXEL",
1810 : "IMAGE_STRUCTURE");
1811 243 : else if (EQUAL(poFile->GetInterleaving().c_str(), "BAND"))
1812 215 : poDS->SetMetadataItem("IMAGE_STRUCTURE", "BAND", "IMAGE_STRUCTURE");
1813 :
1814 : /* --------------------------------------------------------------------
1815 : */
1816 : /* Create band objects. */
1817 : /* --------------------------------------------------------------------
1818 : */
1819 474 : for (int iBand = 0;
1820 474 : bValidRasterDimensions && iBand < poFile->GetChannels(); iBand++)
1821 : {
1822 231 : PCIDSKChannel *poChannel = poFile->GetChannel(iBand + 1);
1823 462 : if (poChannel->GetBlockWidth() <= 0 ||
1824 231 : poChannel->GetBlockHeight() <= 0)
1825 : {
1826 0 : delete poDS;
1827 0 : return nullptr;
1828 : }
1829 :
1830 231 : if (PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType()) ==
1831 : GDT_Unknown)
1832 : {
1833 0 : continue;
1834 : }
1835 :
1836 231 : poDS->SetBand(poDS->GetRasterCount() + 1,
1837 231 : new PCIDSK2Band(poFile, poChannel));
1838 : }
1839 :
1840 : /* --------------------------------------------------------------------
1841 : */
1842 : /* Create band objects for bitmap segments. */
1843 : /* --------------------------------------------------------------------
1844 : */
1845 243 : int nLastBitmapSegment = 0;
1846 243 : PCIDSKSegment *poBitSeg = nullptr;
1847 :
1848 486 : while (bValidRasterDimensions &&
1849 486 : (poBitSeg = poFile->GetSegment(SEG_BIT, "",
1850 243 : nLastBitmapSegment)) != nullptr)
1851 : {
1852 0 : PCIDSKChannel *poChannel = dynamic_cast<PCIDSKChannel *>(poBitSeg);
1853 0 : if (poChannel == nullptr || poChannel->GetBlockWidth() <= 0 ||
1854 0 : poChannel->GetBlockHeight() <= 0)
1855 : {
1856 0 : delete poDS;
1857 0 : return nullptr;
1858 : }
1859 :
1860 0 : if (PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType()) ==
1861 : GDT_Unknown)
1862 : {
1863 0 : continue;
1864 : }
1865 :
1866 0 : poDS->SetBand(poDS->GetRasterCount() + 1,
1867 0 : new PCIDSK2Band(poChannel));
1868 :
1869 0 : nLastBitmapSegment = poBitSeg->GetSegmentNumber();
1870 : }
1871 :
1872 : /* --------------------------------------------------------------------
1873 : */
1874 : /* Create vector layers from vector segments. */
1875 : /* --------------------------------------------------------------------
1876 : */
1877 243 : PCIDSK::PCIDSKSegment *segobj = poFile->GetSegment(PCIDSK::SEG_VEC, "");
1878 338 : for (; segobj != nullptr;
1879 95 : segobj = poFile->GetSegment(PCIDSK::SEG_VEC, "",
1880 95 : segobj->GetSegmentNumber()))
1881 : {
1882 : PCIDSK::PCIDSKVectorSegment *poVecSeg =
1883 95 : dynamic_cast<PCIDSK::PCIDSKVectorSegment *>(segobj);
1884 95 : if (poVecSeg)
1885 95 : poDS->apoLayers.push_back(new OGRPCIDSKLayer(
1886 95 : poDS, segobj, poVecSeg, eAccessIn == GA_Update));
1887 : }
1888 :
1889 : /* --------------------------------------------------------------------
1890 : */
1891 : /* Process RPC segment, if there is one. */
1892 : /* --------------------------------------------------------------------
1893 : */
1894 243 : poDS->ProcessRPC();
1895 :
1896 : /* --------------------------------------------------------------------
1897 : */
1898 : /* Initialize any PAM information. */
1899 : /* --------------------------------------------------------------------
1900 : */
1901 243 : poDS->SetDescription(pszFilename);
1902 243 : poDS->TryLoadXML(papszSiblingFiles);
1903 :
1904 : /* --------------------------------------------------------------------
1905 : */
1906 : /* Open overviews. */
1907 : /* --------------------------------------------------------------------
1908 : */
1909 243 : poDS->oOvManager.Initialize(poDS, pszFilename, papszSiblingFiles);
1910 :
1911 243 : return poDS;
1912 : }
1913 :
1914 : /* -------------------------------------------------------------------- */
1915 : /* Trap exceptions. */
1916 : /* -------------------------------------------------------------------- */
1917 0 : catch (const PCIDSKException &ex)
1918 : {
1919 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
1920 : }
1921 0 : catch (...)
1922 : {
1923 0 : CPLError(CE_Failure, CPLE_AppDefined,
1924 : "PCIDSK SDK Failure in Open(), unexpected exception.");
1925 : }
1926 :
1927 : /* -------------------------------------------------------------------- */
1928 : /* In case of exception, close dataset */
1929 : /* -------------------------------------------------------------------- */
1930 0 : delete poDS;
1931 :
1932 0 : return nullptr;
1933 : }
1934 :
1935 : /************************************************************************/
1936 : /* Create() */
1937 : /************************************************************************/
1938 :
1939 123 : GDALDataset *PCIDSK2Dataset::Create(const char *pszFilename, int nXSize,
1940 : int nYSize, int nBandsIn,
1941 : GDALDataType eType, char **papszParamList)
1942 :
1943 : {
1944 : /* -------------------------------------------------------------------- */
1945 : /* Prepare channel type list. */
1946 : /* -------------------------------------------------------------------- */
1947 246 : std::vector<eChanType> aeChanTypes;
1948 :
1949 123 : if (eType == GDT_Float32)
1950 3 : aeChanTypes.resize(std::max(1, nBandsIn), CHN_32R);
1951 120 : else if (eType == GDT_Int16)
1952 3 : aeChanTypes.resize(std::max(1, nBandsIn), CHN_16S);
1953 117 : else if (eType == GDT_UInt16)
1954 11 : aeChanTypes.resize(std::max(1, nBandsIn), CHN_16U);
1955 106 : else if (eType == GDT_CInt16)
1956 3 : aeChanTypes.resize(std::max(1, nBandsIn), CHN_C16S);
1957 103 : else if (eType == GDT_CFloat32)
1958 3 : aeChanTypes.resize(std::max(1, nBandsIn), CHN_C32R);
1959 : else
1960 100 : aeChanTypes.resize(std::max(1, nBandsIn), CHN_8U);
1961 :
1962 : /* -------------------------------------------------------------------- */
1963 : /* Reformat options. Currently no support for jpeg compression */
1964 : /* quality. */
1965 : /* -------------------------------------------------------------------- */
1966 246 : CPLString osOptions;
1967 123 : const char *pszValue = CSLFetchNameValue(papszParamList, "INTERLEAVING");
1968 123 : if (pszValue == nullptr)
1969 115 : pszValue = "BAND";
1970 :
1971 123 : osOptions = pszValue;
1972 :
1973 123 : if (osOptions == "TILED")
1974 : {
1975 7 : pszValue = CSLFetchNameValue(papszParamList, "TILESIZE");
1976 7 : if (pszValue != nullptr)
1977 6 : osOptions += pszValue;
1978 :
1979 7 : pszValue = CSLFetchNameValue(papszParamList, "COMPRESSION");
1980 7 : if (pszValue != nullptr)
1981 : {
1982 4 : osOptions += " ";
1983 4 : osOptions += pszValue;
1984 : }
1985 :
1986 7 : pszValue = CSLFetchNameValue(papszParamList, "TILEVERSION");
1987 7 : if (pszValue != nullptr)
1988 : {
1989 4 : osOptions += " TILEV";
1990 4 : osOptions += pszValue;
1991 : }
1992 : }
1993 :
1994 : /* -------------------------------------------------------------------- */
1995 : /* Try creation. */
1996 : /* -------------------------------------------------------------------- */
1997 :
1998 : try
1999 : {
2000 123 : if (nBandsIn == 0)
2001 : {
2002 43 : nXSize = 512;
2003 43 : nYSize = 512;
2004 : }
2005 274 : PCIDSKFile *poFile = PCIDSK::Create(pszFilename, nXSize, nYSize,
2006 123 : nBandsIn, &(aeChanTypes[0]),
2007 : osOptions, PCIDSK2GetInterfaces());
2008 :
2009 : /* --------------------------------------------------------------------
2010 : */
2011 : /* Apply band descriptions, if provided as creation options. */
2012 : /* --------------------------------------------------------------------
2013 : */
2014 131 : for (size_t i = 0;
2015 131 : papszParamList != nullptr && papszParamList[i] != nullptr; i++)
2016 : {
2017 22 : if (STARTS_WITH_CI(papszParamList[i], "BANDDESC"))
2018 : {
2019 0 : int nBand = atoi(papszParamList[i] + 8);
2020 0 : const char *pszDescription = strstr(papszParamList[i], "=");
2021 0 : if (pszDescription && nBand > 0 && nBand <= nBandsIn)
2022 : {
2023 0 : poFile->GetChannel(nBand)->SetDescription(pszDescription +
2024 0 : 1);
2025 : }
2026 : }
2027 : }
2028 :
2029 109 : return LLOpen(pszFilename, poFile, GA_Update);
2030 : }
2031 : /* -------------------------------------------------------------------- */
2032 : /* Trap exceptions. */
2033 : /* -------------------------------------------------------------------- */
2034 28 : catch (const PCIDSKException &ex)
2035 : {
2036 14 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
2037 : }
2038 0 : catch (...)
2039 : {
2040 0 : CPLError(CE_Failure, CPLE_AppDefined,
2041 : "PCIDSK::Create() failed, unexpected exception.");
2042 : }
2043 :
2044 14 : return nullptr;
2045 : }
2046 :
2047 : /************************************************************************/
2048 : /* TestCapability() */
2049 : /************************************************************************/
2050 :
2051 79 : int PCIDSK2Dataset::TestCapability(const char *pszCap)
2052 :
2053 : {
2054 79 : if (EQUAL(pszCap, ODsCCreateLayer))
2055 37 : return eAccess == GA_Update;
2056 42 : if (EQUAL(pszCap, ODsCRandomLayerWrite))
2057 0 : return eAccess == GA_Update;
2058 42 : if (EQUAL(pszCap, ODsCZGeometries))
2059 12 : return TRUE;
2060 :
2061 30 : return FALSE;
2062 : }
2063 :
2064 : /************************************************************************/
2065 : /* GetLayer() */
2066 : /************************************************************************/
2067 :
2068 1655 : OGRLayer *PCIDSK2Dataset::GetLayer(int iLayer)
2069 :
2070 : {
2071 1655 : if (iLayer < 0 || iLayer >= static_cast<int>(apoLayers.size()))
2072 2 : return nullptr;
2073 :
2074 1653 : return apoLayers[iLayer];
2075 : }
2076 :
2077 : /************************************************************************/
2078 : /* ICreateLayer() */
2079 : /************************************************************************/
2080 :
2081 1089 : OGRLayer *PCIDSK2Dataset::ICreateLayer(const char *pszLayerName,
2082 : const OGRGeomFieldDefn *poGeomFieldDefn,
2083 : CSLConstList /*papszOptions*/)
2084 : {
2085 : /* -------------------------------------------------------------------- */
2086 : /* Verify we are in update mode. */
2087 : /* -------------------------------------------------------------------- */
2088 1089 : if (eAccess != GA_Update)
2089 : {
2090 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
2091 : "Data source %s opened read-only.\n"
2092 : "New layer %s cannot be created.\n",
2093 0 : GetDescription(), pszLayerName);
2094 0 : return nullptr;
2095 : }
2096 :
2097 1089 : const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
2098 : const auto poSRS =
2099 1089 : poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
2100 :
2101 : /* -------------------------------------------------------------------- */
2102 : /* Figure out what type of layer we need. */
2103 : /* -------------------------------------------------------------------- */
2104 2178 : std::string osLayerType;
2105 :
2106 1089 : switch (wkbFlatten(eType))
2107 : {
2108 10 : case wkbPoint:
2109 10 : osLayerType = "POINTS";
2110 10 : break;
2111 :
2112 10 : case wkbLineString:
2113 10 : osLayerType = "ARCS";
2114 10 : break;
2115 :
2116 6 : case wkbPolygon:
2117 6 : osLayerType = "WHOLE_POLYGONS";
2118 6 : break;
2119 :
2120 7 : case wkbNone:
2121 7 : osLayerType = "TABLE";
2122 7 : break;
2123 :
2124 1056 : default:
2125 1056 : break;
2126 : }
2127 :
2128 : /* -------------------------------------------------------------------- */
2129 : /* Create the segment. */
2130 : /* -------------------------------------------------------------------- */
2131 : int nSegNum;
2132 : try
2133 : {
2134 1093 : nSegNum = poFile->CreateSegment(pszLayerName, "", PCIDSK::SEG_VEC, 0L);
2135 : }
2136 1 : catch (const PCIDSKException &ex)
2137 : {
2138 1 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
2139 1 : return nullptr;
2140 : }
2141 1088 : PCIDSK::PCIDSKSegment *poSeg = poFile->GetSegment(nSegNum);
2142 : PCIDSK::PCIDSKVectorSegment *poVecSeg =
2143 1088 : dynamic_cast<PCIDSK::PCIDSKVectorSegment *>(poSeg);
2144 1088 : if (poVecSeg == nullptr)
2145 0 : return nullptr;
2146 :
2147 1088 : if (osLayerType != "")
2148 33 : poSeg->SetMetadataValue("LAYER_TYPE", osLayerType);
2149 :
2150 : /* -------------------------------------------------------------------- */
2151 : /* Do we need to apply a coordinate system? */
2152 : /* -------------------------------------------------------------------- */
2153 1088 : char *pszGeosys = nullptr;
2154 1088 : char *pszUnits = nullptr;
2155 1088 : double *padfPrjParams = nullptr;
2156 :
2157 1088 : if (poSRS != nullptr && poSRS->exportToPCI(&pszGeosys, &pszUnits,
2158 : &padfPrjParams) == OGRERR_NONE)
2159 : {
2160 : try
2161 : {
2162 6 : std::vector<double> adfPCIParameters;
2163 :
2164 108 : for (int i = 0; i < 17; i++)
2165 102 : adfPCIParameters.push_back(padfPrjParams[i]);
2166 :
2167 6 : if (STARTS_WITH_CI(pszUnits, "FOOT"))
2168 0 : adfPCIParameters.push_back(static_cast<double>(
2169 : static_cast<int>(PCIDSK::UNIT_US_FOOT)));
2170 6 : else if (STARTS_WITH_CI(pszUnits, "INTL FOOT"))
2171 0 : adfPCIParameters.push_back(static_cast<double>(
2172 : static_cast<int>(PCIDSK::UNIT_INTL_FOOT)));
2173 6 : else if (STARTS_WITH_CI(pszUnits, "DEGREE"))
2174 2 : adfPCIParameters.push_back(
2175 2 : static_cast<double>(static_cast<int>(PCIDSK::UNIT_DEGREE)));
2176 : else
2177 4 : adfPCIParameters.push_back(
2178 4 : static_cast<double>(static_cast<int>(PCIDSK::UNIT_METER)));
2179 :
2180 6 : poVecSeg->SetProjection(pszGeosys, adfPCIParameters);
2181 : }
2182 0 : catch (const PCIDSKException &ex)
2183 : {
2184 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
2185 : }
2186 :
2187 6 : CPLFree(pszGeosys);
2188 6 : CPLFree(pszUnits);
2189 6 : CPLFree(padfPrjParams);
2190 : }
2191 :
2192 : /* -------------------------------------------------------------------- */
2193 : /* Create the layer object. */
2194 : /* -------------------------------------------------------------------- */
2195 :
2196 1088 : apoLayers.push_back(new OGRPCIDSKLayer(this, poSeg, poVecSeg, TRUE));
2197 :
2198 1088 : return apoLayers.back();
2199 : }
2200 :
2201 : /************************************************************************/
2202 : /* GDALRegister_PCIDSK() */
2203 : /************************************************************************/
2204 :
2205 13 : void GDALRegister_PCIDSK()
2206 :
2207 : {
2208 13 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
2209 0 : return;
2210 :
2211 13 : GDALDriver *poDriver = new GDALDriver();
2212 13 : PCIDSKDriverSetCommonMetadata(poDriver);
2213 :
2214 13 : poDriver->pfnOpen = PCIDSK2Dataset::Open;
2215 13 : poDriver->pfnCreate = PCIDSK2Dataset::Create;
2216 :
2217 13 : GetGDALDriverManager()->RegisterDriver(poDriver);
2218 : }
|