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