Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: PCI .aux Driver
4 : * Purpose: Implementation of PAuxDataset
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2008-2010, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_string.h"
15 : #include "gdal_frmts.h"
16 : #include "gdal_priv.h"
17 : #include "ogr_spatialref.h"
18 : #include "rawdataset.h"
19 :
20 : #include <cmath>
21 :
22 : /************************************************************************/
23 : /* ==================================================================== */
24 : /* PAuxDataset */
25 : /* ==================================================================== */
26 : /************************************************************************/
27 :
28 : class PAuxRasterBand;
29 :
30 : class PAuxDataset final : public RawDataset
31 : {
32 : friend class PAuxRasterBand;
33 :
34 : VSILFILE *fpImage; // Image data file.
35 :
36 : int nGCPCount;
37 : GDAL_GCP *pasGCPList;
38 : OGRSpatialReference m_oGCPSRS{};
39 :
40 : void ScanForGCPs();
41 : static OGRSpatialReference PCI2SRS(const char *pszGeosys,
42 : const char *pszProjParams);
43 :
44 : OGRSpatialReference m_oSRS{};
45 :
46 : CPL_DISALLOW_COPY_ASSIGN(PAuxDataset)
47 :
48 : CPLErr Close() override;
49 :
50 : public:
51 : PAuxDataset();
52 : ~PAuxDataset() override;
53 :
54 : // TODO(schwehr): Why are these public?
55 : char *pszAuxFilename;
56 : char **papszAuxLines;
57 :
58 0 : const OGRSpatialReference *GetSpatialRef() const override
59 : {
60 0 : return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
61 : }
62 :
63 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
64 :
65 : int GetGCPCount() override;
66 :
67 0 : const OGRSpatialReference *GetGCPSpatialRef() const override
68 : {
69 0 : return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
70 : }
71 :
72 : const GDAL_GCP *GetGCPs() override;
73 :
74 : char **GetFileList() override;
75 :
76 : static GDALDataset *Open(GDALOpenInfo *);
77 : };
78 :
79 : /************************************************************************/
80 : /* ==================================================================== */
81 : /* PAuxRasterBand */
82 : /* ==================================================================== */
83 : /************************************************************************/
84 :
85 : class PAuxRasterBand final : public RawRasterBand
86 : {
87 : CPL_DISALLOW_COPY_ASSIGN(PAuxRasterBand)
88 :
89 : public:
90 : PAuxRasterBand(GDALDataset *poDS, int nBand, VSILFILE *fpRaw,
91 : vsi_l_offset nImgOffset, int nPixelOffset, int nLineOffset,
92 : GDALDataType eDataType, int bNativeOrder);
93 :
94 : ~PAuxRasterBand() override;
95 :
96 : double GetNoDataValue(int *pbSuccess = nullptr) override;
97 :
98 : GDALColorTable *GetColorTable() override;
99 : GDALColorInterp GetColorInterpretation() override;
100 : };
101 :
102 : /************************************************************************/
103 : /* PAuxRasterBand() */
104 : /************************************************************************/
105 :
106 8 : PAuxRasterBand::PAuxRasterBand(GDALDataset *poDSIn, int nBandIn,
107 : VSILFILE *fpRawIn, vsi_l_offset nImgOffsetIn,
108 : int nPixelOffsetIn, int nLineOffsetIn,
109 8 : GDALDataType eDataTypeIn, int bNativeOrderIn)
110 : : RawRasterBand(poDSIn, nBandIn, fpRawIn, nImgOffsetIn, nPixelOffsetIn,
111 : nLineOffsetIn, eDataTypeIn, bNativeOrderIn,
112 8 : RawRasterBand::OwnFP::NO)
113 : {
114 8 : PAuxDataset *poPDS = cpl::down_cast<PAuxDataset *>(poDS);
115 :
116 : /* -------------------------------------------------------------------- */
117 : /* Does this channel have a description? */
118 : /* -------------------------------------------------------------------- */
119 8 : char szTarget[128] = {'\0'};
120 :
121 8 : snprintf(szTarget, sizeof(szTarget), "ChanDesc-%d", nBand);
122 8 : if (CSLFetchNameValue(poPDS->papszAuxLines, szTarget) != nullptr)
123 0 : GDALRasterBand::SetDescription(
124 0 : CSLFetchNameValue(poPDS->papszAuxLines, szTarget));
125 :
126 : /* -------------------------------------------------------------------- */
127 : /* See if we have colors. Currently we must have color zero, */
128 : /* but this should not really be a limitation. */
129 : /* -------------------------------------------------------------------- */
130 8 : snprintf(szTarget, sizeof(szTarget), "METADATA_IMG_%d_Class_%d_Color",
131 : nBand, 0);
132 8 : if (CSLFetchNameValue(poPDS->papszAuxLines, szTarget) != nullptr)
133 : {
134 0 : poCT = new GDALColorTable();
135 :
136 0 : for (int i = 0; i < 256; i++)
137 : {
138 0 : snprintf(szTarget, sizeof(szTarget),
139 : "METADATA_IMG_%d_Class_%d_Color", nBand, i);
140 : const char *pszLine =
141 0 : CSLFetchNameValue(poPDS->papszAuxLines, szTarget);
142 0 : while (pszLine && *pszLine == ' ')
143 0 : pszLine++;
144 :
145 0 : int nRed = 0;
146 0 : int nGreen = 0;
147 0 : int nBlue = 0;
148 : // TODO(schwehr): Replace sscanf with something safe.
149 0 : if (pszLine != nullptr && STARTS_WITH_CI(pszLine, "(RGB:") &&
150 0 : sscanf(pszLine + 5, "%d %d %d", &nRed, &nGreen, &nBlue) == 3)
151 : {
152 0 : GDALColorEntry oColor = {static_cast<short>(nRed),
153 : static_cast<short>(nGreen),
154 0 : static_cast<short>(nBlue), 255};
155 :
156 0 : poCT->SetColorEntry(i, &oColor);
157 : }
158 : }
159 : }
160 8 : }
161 :
162 : /************************************************************************/
163 : /* ~PAuxRasterBand() */
164 : /************************************************************************/
165 :
166 16 : PAuxRasterBand::~PAuxRasterBand()
167 :
168 : {
169 16 : }
170 :
171 : /************************************************************************/
172 : /* GetNoDataValue() */
173 : /************************************************************************/
174 :
175 0 : double PAuxRasterBand::GetNoDataValue(int *pbSuccess)
176 :
177 : {
178 0 : char szTarget[128] = {'\0'};
179 0 : snprintf(szTarget, sizeof(szTarget), "METADATA_IMG_%d_NO_DATA_VALUE",
180 : nBand);
181 :
182 0 : PAuxDataset *poPDS = cpl::down_cast<PAuxDataset *>(poDS);
183 0 : const char *pszLine = CSLFetchNameValue(poPDS->papszAuxLines, szTarget);
184 :
185 0 : if (pbSuccess != nullptr)
186 0 : *pbSuccess = (pszLine != nullptr);
187 :
188 0 : if (pszLine == nullptr)
189 0 : return -1.0e8;
190 :
191 0 : return CPLAtof(pszLine);
192 : }
193 :
194 : /************************************************************************/
195 : /* GetColorTable() */
196 : /************************************************************************/
197 :
198 0 : GDALColorTable *PAuxRasterBand::GetColorTable()
199 :
200 : {
201 0 : return poCT;
202 : }
203 :
204 : /************************************************************************/
205 : /* GetColorInterpretation() */
206 : /************************************************************************/
207 :
208 0 : GDALColorInterp PAuxRasterBand::GetColorInterpretation()
209 :
210 : {
211 0 : if (poCT == nullptr)
212 0 : return GCI_Undefined;
213 :
214 0 : return GCI_PaletteIndex;
215 : }
216 :
217 : /************************************************************************/
218 : /* ==================================================================== */
219 : /* PAuxDataset */
220 : /* ==================================================================== */
221 : /************************************************************************/
222 :
223 : /************************************************************************/
224 : /* PAuxDataset() */
225 : /************************************************************************/
226 :
227 4 : PAuxDataset::PAuxDataset()
228 : : fpImage(nullptr), nGCPCount(0), pasGCPList(nullptr),
229 4 : pszAuxFilename(nullptr), papszAuxLines(nullptr)
230 : {
231 4 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
232 4 : m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
233 4 : }
234 :
235 : /************************************************************************/
236 : /* ~PAuxDataset() */
237 : /************************************************************************/
238 :
239 8 : PAuxDataset::~PAuxDataset()
240 :
241 : {
242 4 : PAuxDataset::Close();
243 8 : }
244 :
245 : /************************************************************************/
246 : /* Close() */
247 : /************************************************************************/
248 :
249 8 : CPLErr PAuxDataset::Close()
250 : {
251 8 : CPLErr eErr = CE_None;
252 8 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
253 : {
254 4 : if (PAuxDataset::FlushCache(true) != CE_None)
255 0 : eErr = CE_Failure;
256 :
257 4 : if (fpImage != nullptr)
258 : {
259 4 : if (VSIFCloseL(fpImage) != 0)
260 : {
261 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
262 0 : eErr = CE_Failure;
263 : }
264 : }
265 :
266 4 : GDALDeinitGCPs(nGCPCount, pasGCPList);
267 4 : CPLFree(pasGCPList);
268 :
269 4 : CPLFree(pszAuxFilename);
270 4 : CSLDestroy(papszAuxLines);
271 :
272 4 : if (GDALPamDataset::Close() != CE_None)
273 0 : eErr = CE_Failure;
274 : }
275 8 : return eErr;
276 : }
277 :
278 : /************************************************************************/
279 : /* GetFileList() */
280 : /************************************************************************/
281 :
282 1 : char **PAuxDataset::GetFileList()
283 :
284 : {
285 1 : char **papszFileList = RawDataset::GetFileList();
286 1 : papszFileList = CSLAddString(papszFileList, pszAuxFilename);
287 1 : return papszFileList;
288 : }
289 :
290 : /************************************************************************/
291 : /* PCI2SRS() */
292 : /* */
293 : /* Convert PCI coordinate system to WKT. For now this is very */
294 : /* incomplete, but can be filled out in the future. */
295 : /************************************************************************/
296 :
297 8 : OGRSpatialReference PAuxDataset::PCI2SRS(const char *pszGeosys,
298 : const char *pszProjParams)
299 :
300 : {
301 8 : while (*pszGeosys == ' ')
302 4 : pszGeosys++;
303 :
304 : /* -------------------------------------------------------------------- */
305 : /* Parse projection parameters array. */
306 : /* -------------------------------------------------------------------- */
307 4 : double adfProjParams[16] = {0.0};
308 :
309 4 : if (pszProjParams != nullptr)
310 : {
311 4 : char **papszTokens = CSLTokenizeString(pszProjParams);
312 :
313 4 : for (int i = 0;
314 68 : i < 16 && papszTokens != nullptr && papszTokens[i] != nullptr; i++)
315 64 : adfProjParams[i] = CPLAtof(papszTokens[i]);
316 :
317 4 : CSLDestroy(papszTokens);
318 : }
319 :
320 : /* -------------------------------------------------------------------- */
321 : /* Convert to SRS. */
322 : /* -------------------------------------------------------------------- */
323 4 : OGRSpatialReference oSRS;
324 4 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
325 4 : if (oSRS.importFromPCI(pszGeosys, nullptr, adfProjParams) != OGRERR_NONE)
326 : {
327 0 : oSRS.Clear();
328 : }
329 :
330 8 : return oSRS;
331 : }
332 :
333 : /************************************************************************/
334 : /* ScanForGCPs() */
335 : /************************************************************************/
336 :
337 4 : void PAuxDataset::ScanForGCPs()
338 :
339 : {
340 4 : const int MAX_GCP = 256;
341 :
342 4 : nGCPCount = 0;
343 4 : CPLAssert(pasGCPList == nullptr);
344 4 : pasGCPList = static_cast<GDAL_GCP *>(CPLCalloc(sizeof(GDAL_GCP), MAX_GCP));
345 :
346 : /* -------------------------------------------------------------------- */
347 : /* Get the GCP coordinate system. */
348 : /* -------------------------------------------------------------------- */
349 : const char *pszMapUnits =
350 4 : CSLFetchNameValue(papszAuxLines, "GCP_1_MapUnits");
351 : const char *pszProjParams =
352 4 : CSLFetchNameValue(papszAuxLines, "GCP_1_ProjParms");
353 :
354 4 : if (pszMapUnits != nullptr)
355 0 : m_oGCPSRS = PCI2SRS(pszMapUnits, pszProjParams);
356 :
357 : /* -------------------------------------------------------------------- */
358 : /* Collect standalone GCPs. They look like: */
359 : /* */
360 : /* GCP_1_n = row, col, x, y [,z [,"id"[, "desc"]]] */
361 : /* -------------------------------------------------------------------- */
362 4 : for (int i = 0; nGCPCount < MAX_GCP; i++)
363 : {
364 4 : char szName[50] = {'\0'};
365 4 : snprintf(szName, sizeof(szName), "GCP_1_%d", i + 1);
366 4 : if (CSLFetchNameValue(papszAuxLines, szName) == nullptr)
367 4 : break;
368 :
369 0 : char **papszTokens = CSLTokenizeStringComplex(
370 0 : CSLFetchNameValue(papszAuxLines, szName), " ", TRUE, FALSE);
371 :
372 0 : if (CSLCount(papszTokens) >= 4)
373 : {
374 0 : GDALInitGCPs(1, pasGCPList + nGCPCount);
375 :
376 0 : pasGCPList[nGCPCount].dfGCPX = CPLAtof(papszTokens[2]);
377 0 : pasGCPList[nGCPCount].dfGCPY = CPLAtof(papszTokens[3]);
378 0 : pasGCPList[nGCPCount].dfGCPPixel = CPLAtof(papszTokens[0]);
379 0 : pasGCPList[nGCPCount].dfGCPLine = CPLAtof(papszTokens[1]);
380 :
381 0 : if (CSLCount(papszTokens) > 4)
382 0 : pasGCPList[nGCPCount].dfGCPZ = CPLAtof(papszTokens[4]);
383 :
384 0 : CPLFree(pasGCPList[nGCPCount].pszId);
385 0 : if (CSLCount(papszTokens) > 5)
386 : {
387 0 : pasGCPList[nGCPCount].pszId = CPLStrdup(papszTokens[5]);
388 : }
389 : else
390 : {
391 0 : snprintf(szName, sizeof(szName), "GCP_%d", i + 1);
392 0 : pasGCPList[nGCPCount].pszId = CPLStrdup(szName);
393 : }
394 :
395 0 : if (CSLCount(papszTokens) > 6)
396 : {
397 0 : CPLFree(pasGCPList[nGCPCount].pszInfo);
398 0 : pasGCPList[nGCPCount].pszInfo = CPLStrdup(papszTokens[6]);
399 : }
400 :
401 0 : nGCPCount++;
402 : }
403 :
404 0 : CSLDestroy(papszTokens);
405 : }
406 4 : }
407 :
408 : /************************************************************************/
409 : /* GetGCPCount() */
410 : /************************************************************************/
411 :
412 0 : int PAuxDataset::GetGCPCount()
413 :
414 : {
415 0 : return nGCPCount;
416 : }
417 :
418 : /************************************************************************/
419 : /* GetGCP() */
420 : /************************************************************************/
421 :
422 0 : const GDAL_GCP *PAuxDataset::GetGCPs()
423 :
424 : {
425 0 : return pasGCPList;
426 : }
427 :
428 : /************************************************************************/
429 : /* GetGeoTransform() */
430 : /************************************************************************/
431 :
432 0 : CPLErr PAuxDataset::GetGeoTransform(GDALGeoTransform >) const
433 :
434 : {
435 0 : if (CSLFetchNameValue(papszAuxLines, "UpLeftX") == nullptr ||
436 0 : CSLFetchNameValue(papszAuxLines, "UpLeftY") == nullptr ||
437 0 : CSLFetchNameValue(papszAuxLines, "LoRightX") == nullptr ||
438 0 : CSLFetchNameValue(papszAuxLines, "LoRightY") == nullptr)
439 : {
440 0 : gt = GDALGeoTransform();
441 0 : return CE_Failure;
442 : }
443 :
444 : const double dfUpLeftX =
445 0 : CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftX"));
446 : const double dfUpLeftY =
447 0 : CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftY"));
448 : const double dfLoRightX =
449 0 : CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightX"));
450 : const double dfLoRightY =
451 0 : CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightY"));
452 :
453 0 : gt[0] = dfUpLeftX;
454 0 : gt[1] = (dfLoRightX - dfUpLeftX) / GetRasterXSize();
455 0 : gt[2] = 0.0;
456 0 : gt[3] = dfUpLeftY;
457 0 : gt[4] = 0.0;
458 0 : gt[5] = (dfLoRightY - dfUpLeftY) / GetRasterYSize();
459 :
460 0 : return CE_None;
461 : }
462 :
463 : /************************************************************************/
464 : /* Open() */
465 : /************************************************************************/
466 :
467 31613 : GDALDataset *PAuxDataset::Open(GDALOpenInfo *poOpenInfo)
468 :
469 : {
470 33122 : if (poOpenInfo->nHeaderBytes < 1 ||
471 3018 : (!poOpenInfo->IsSingleAllowedDriver("PAux") &&
472 1509 : poOpenInfo->IsExtensionEqualToCI("zarr")))
473 : {
474 30099 : return nullptr;
475 : }
476 :
477 : /* -------------------------------------------------------------------- */
478 : /* If this is an .aux file, fetch out and form the name of the */
479 : /* file it references. */
480 : /* -------------------------------------------------------------------- */
481 :
482 3023 : CPLString osTarget = poOpenInfo->pszFilename;
483 :
484 1511 : if (poOpenInfo->IsExtensionEqualToCI("aux") &&
485 2 : STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
486 : "AuxilaryTarget: "))
487 : {
488 2 : const char *pszSrc =
489 2 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader + 16);
490 :
491 2 : char szAuxTarget[1024] = {'\0'};
492 2 : for (int i = 0; i < static_cast<int>(sizeof(szAuxTarget)) - 1 &&
493 24 : pszSrc[i] != 10 && pszSrc[i] != 13 && pszSrc[i] != '\0';
494 : i++)
495 : {
496 22 : szAuxTarget[i] = pszSrc[i];
497 : }
498 2 : szAuxTarget[sizeof(szAuxTarget) - 1] = '\0';
499 :
500 2 : if (CPLHasPathTraversal(szAuxTarget))
501 : {
502 0 : CPLError(CE_Failure, CPLE_AppDefined,
503 : "Path traversal detected in %s", szAuxTarget);
504 0 : return nullptr;
505 : }
506 2 : const std::string osPath(CPLGetPathSafe(poOpenInfo->pszFilename));
507 2 : osTarget = CPLFormFilenameSafe(osPath.c_str(), szAuxTarget, nullptr);
508 : }
509 :
510 : /* -------------------------------------------------------------------- */
511 : /* Now we need to tear apart the filename to form a .aux */
512 : /* filename. */
513 : /* -------------------------------------------------------------------- */
514 3018 : CPLString osAuxFilename = CPLResetExtensionSafe(osTarget, "aux");
515 :
516 : /* -------------------------------------------------------------------- */
517 : /* Do we have a .aux file? */
518 : /* -------------------------------------------------------------------- */
519 1509 : CSLConstList papszSiblingFiles = poOpenInfo->GetSiblingFiles();
520 3010 : if (papszSiblingFiles != nullptr &&
521 1501 : CSLFindString(papszSiblingFiles, CPLGetFilename(osAuxFilename)) == -1)
522 : {
523 1497 : return nullptr;
524 : }
525 :
526 12 : VSILFILE *fp = VSIFOpenL(osAuxFilename, "r");
527 12 : if (fp == nullptr)
528 : {
529 8 : osAuxFilename = CPLResetExtensionSafe(osTarget, "AUX");
530 8 : fp = VSIFOpenL(osAuxFilename, "r");
531 : }
532 :
533 12 : if (fp == nullptr)
534 8 : return nullptr;
535 :
536 : /* -------------------------------------------------------------------- */
537 : /* Is this file a PCI .aux file? Check the first line for the */
538 : /* telltale AuxilaryTarget keyword. */
539 : /* */
540 : /* At this point we should be verifying that it refers to our */
541 : /* binary file, but that is a pretty involved test. */
542 : /* -------------------------------------------------------------------- */
543 4 : CPLPushErrorHandler(CPLQuietErrorHandler);
544 4 : const char *pszLine = CPLReadLine2L(fp, 1024, nullptr);
545 4 : CPLPopErrorHandler();
546 :
547 4 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
548 :
549 4 : if (pszLine == nullptr || (!STARTS_WITH_CI(pszLine, "AuxilaryTarget") &&
550 0 : !STARTS_WITH_CI(pszLine, "AuxiliaryTarget")))
551 : {
552 0 : CPLErrorReset();
553 0 : return nullptr;
554 : }
555 :
556 : /* -------------------------------------------------------------------- */
557 : /* Create a corresponding GDALDataset. */
558 : /* -------------------------------------------------------------------- */
559 8 : auto poDS = std::make_unique<PAuxDataset>();
560 :
561 : /* -------------------------------------------------------------------- */
562 : /* Load the .aux file into a string list suitable to be */
563 : /* searched with CSLFetchNameValue(). */
564 : /* -------------------------------------------------------------------- */
565 4 : poDS->papszAuxLines = CSLLoad2(osAuxFilename, 1024, 1024, nullptr);
566 4 : poDS->pszAuxFilename = CPLStrdup(osAuxFilename);
567 :
568 : /* -------------------------------------------------------------------- */
569 : /* Find the RawDefinition line to establish overall parameters. */
570 : /* -------------------------------------------------------------------- */
571 4 : pszLine = CSLFetchNameValue(poDS->papszAuxLines, "RawDefinition");
572 :
573 : // It seems PCI now writes out .aux files without RawDefinition in
574 : // some cases. See bug 947.
575 4 : if (pszLine == nullptr)
576 : {
577 0 : return nullptr;
578 : }
579 :
580 8 : const CPLStringList aosTokens(CSLTokenizeString(pszLine));
581 :
582 4 : if (aosTokens.size() < 3)
583 : {
584 0 : CPLError(CE_Failure, CPLE_AppDefined,
585 : "RawDefinition missing or corrupt in %s.",
586 : poOpenInfo->pszFilename);
587 0 : return nullptr;
588 : }
589 :
590 4 : poDS->nRasterXSize = atoi(aosTokens[0]);
591 4 : poDS->nRasterYSize = atoi(aosTokens[1]);
592 4 : int l_nBands = atoi(aosTokens[2]);
593 4 : poDS->eAccess = poOpenInfo->eAccess;
594 :
595 8 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
596 4 : !GDALCheckBandCount(l_nBands, FALSE))
597 : {
598 0 : return nullptr;
599 : }
600 :
601 : /* -------------------------------------------------------------------- */
602 : /* Open the file. */
603 : /* -------------------------------------------------------------------- */
604 4 : if (poOpenInfo->eAccess == GA_Update)
605 : {
606 0 : poDS->fpImage = VSIFOpenL(osTarget, "rb+");
607 :
608 0 : if (poDS->fpImage == nullptr)
609 : {
610 0 : CPLError(CE_Failure, CPLE_OpenFailed,
611 : "File %s is missing or read-only, check permissions.",
612 : osTarget.c_str());
613 0 : return nullptr;
614 : }
615 : }
616 : else
617 : {
618 4 : poDS->fpImage = VSIFOpenL(osTarget, "rb");
619 :
620 4 : if (poDS->fpImage == nullptr)
621 : {
622 0 : CPLError(CE_Failure, CPLE_OpenFailed,
623 : "File %s is missing or unreadable.", osTarget.c_str());
624 0 : return nullptr;
625 : }
626 : }
627 :
628 : /* -------------------------------------------------------------------- */
629 : /* Collect raw definitions of each channel and create */
630 : /* corresponding bands. */
631 : /* -------------------------------------------------------------------- */
632 12 : for (int i = 0; i < l_nBands; i++)
633 : {
634 8 : char szDefnName[32] = {'\0'};
635 8 : snprintf(szDefnName, sizeof(szDefnName), "ChanDefinition-%d", i + 1);
636 :
637 8 : pszLine = CSLFetchNameValue(poDS->papszAuxLines, szDefnName);
638 8 : if (pszLine == nullptr)
639 : {
640 0 : continue;
641 : }
642 :
643 8 : const CPLStringList aosTokensBand(CSLTokenizeString(pszLine));
644 8 : if (aosTokensBand.size() < 4)
645 : {
646 : // Skip the band with broken description
647 0 : continue;
648 : }
649 :
650 8 : GDALDataType eType = GDT_Unknown;
651 8 : if (EQUAL(aosTokensBand[0], "16U"))
652 8 : eType = GDT_UInt16;
653 0 : else if (EQUAL(aosTokensBand[0], "16S"))
654 0 : eType = GDT_Int16;
655 0 : else if (EQUAL(aosTokensBand[0], "32R"))
656 0 : eType = GDT_Float32;
657 : else
658 0 : eType = GDT_Byte;
659 :
660 8 : bool bNative = true;
661 8 : if (CSLCount(aosTokensBand) > 4)
662 : {
663 : #ifdef CPL_LSB
664 8 : bNative = EQUAL(aosTokensBand[4], "Swapped");
665 : #else
666 : bNative = EQUAL(aosTokensBand[4], "Unswapped");
667 : #endif
668 : }
669 :
670 8 : const vsi_l_offset nBandOffset = CPLScanUIntBig(
671 8 : aosTokensBand[1], static_cast<int>(strlen(aosTokensBand[1])));
672 8 : const int nPixelOffset = atoi(aosTokensBand[2]);
673 8 : const int nLineOffset = atoi(aosTokensBand[3]);
674 :
675 8 : if (nPixelOffset <= 0 || nLineOffset <= 0)
676 : {
677 : // Skip the band with broken offsets.
678 0 : continue;
679 : }
680 :
681 : auto poBand = std::make_unique<PAuxRasterBand>(
682 8 : poDS.get(), poDS->nBands + 1, poDS->fpImage, nBandOffset,
683 8 : nPixelOffset, nLineOffset, eType, bNative);
684 8 : if (!poBand->IsValid())
685 0 : return nullptr;
686 8 : poDS->SetBand(poDS->nBands + 1, std::move(poBand));
687 : }
688 :
689 : /* -------------------------------------------------------------------- */
690 : /* Get the projection. */
691 : /* -------------------------------------------------------------------- */
692 : const char *pszMapUnits =
693 4 : CSLFetchNameValue(poDS->papszAuxLines, "MapUnits");
694 : const char *pszProjParams =
695 4 : CSLFetchNameValue(poDS->papszAuxLines, "ProjParams");
696 :
697 4 : if (pszMapUnits != nullptr)
698 : {
699 4 : poDS->m_oSRS = PCI2SRS(pszMapUnits, pszProjParams);
700 : }
701 :
702 : /* -------------------------------------------------------------------- */
703 : /* Initialize any PAM information. */
704 : /* -------------------------------------------------------------------- */
705 4 : poDS->SetDescription(osTarget);
706 4 : poDS->TryLoadXML();
707 :
708 : /* -------------------------------------------------------------------- */
709 : /* Check for overviews. */
710 : /* -------------------------------------------------------------------- */
711 4 : poDS->oOvManager.Initialize(poDS.get(), osTarget);
712 :
713 4 : poDS->ScanForGCPs();
714 :
715 4 : return poDS.release();
716 : }
717 :
718 : /************************************************************************/
719 : /* GDALRegister_PAux() */
720 : /************************************************************************/
721 :
722 2033 : void GDALRegister_PAux()
723 :
724 : {
725 2033 : if (GDALGetDriverByName("PAux") != nullptr)
726 283 : return;
727 :
728 1750 : GDALDriver *poDriver = new GDALDriver();
729 :
730 1750 : poDriver->SetDescription("PAux");
731 1750 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
732 1750 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PCI .aux Labelled");
733 1750 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/paux.html");
734 1750 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
735 :
736 1750 : poDriver->pfnOpen = PAuxDataset::Open;
737 :
738 1750 : GetGDALDriverManager()->RegisterDriver(poDriver);
739 : }
|