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