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 = reinterpret_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 = reinterpret_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 =
344 4 : reinterpret_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 33551 : GDALDataset *PAuxDataset::Open(GDALOpenInfo *poOpenInfo)
468 :
469 : {
470 33551 : if (poOpenInfo->nHeaderBytes < 1)
471 30071 : return nullptr;
472 :
473 : /* -------------------------------------------------------------------- */
474 : /* If this is an .aux file, fetch out and form the name of the */
475 : /* file it references. */
476 : /* -------------------------------------------------------------------- */
477 :
478 6960 : CPLString osTarget = poOpenInfo->pszFilename;
479 :
480 3482 : if (poOpenInfo->IsExtensionEqualToCI("aux") &&
481 2 : STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
482 : "AuxilaryTarget: "))
483 : {
484 2 : const char *pszSrc =
485 2 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader + 16);
486 :
487 2 : char szAuxTarget[1024] = {'\0'};
488 2 : for (int i = 0; i < static_cast<int>(sizeof(szAuxTarget)) - 1 &&
489 24 : pszSrc[i] != 10 && pszSrc[i] != 13 && pszSrc[i] != '\0';
490 : i++)
491 : {
492 22 : szAuxTarget[i] = pszSrc[i];
493 : }
494 2 : szAuxTarget[sizeof(szAuxTarget) - 1] = '\0';
495 :
496 2 : const std::string osPath(CPLGetPathSafe(poOpenInfo->pszFilename));
497 2 : osTarget = CPLFormFilenameSafe(osPath.c_str(), szAuxTarget, nullptr);
498 : }
499 :
500 : /* -------------------------------------------------------------------- */
501 : /* Now we need to tear apart the filename to form a .aux */
502 : /* filename. */
503 : /* -------------------------------------------------------------------- */
504 6960 : CPLString osAuxFilename = CPLResetExtensionSafe(osTarget, "aux");
505 :
506 : /* -------------------------------------------------------------------- */
507 : /* Do we have a .aux file? */
508 : /* -------------------------------------------------------------------- */
509 3480 : char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
510 6924 : if (papszSiblingFiles != nullptr &&
511 3444 : CSLFindString(papszSiblingFiles, CPLGetFilename(osAuxFilename)) == -1)
512 : {
513 3440 : return nullptr;
514 : }
515 :
516 40 : VSILFILE *fp = VSIFOpenL(osAuxFilename, "r");
517 40 : if (fp == nullptr)
518 : {
519 36 : osAuxFilename = CPLResetExtensionSafe(osTarget, "AUX");
520 36 : fp = VSIFOpenL(osAuxFilename, "r");
521 : }
522 :
523 40 : if (fp == nullptr)
524 36 : return nullptr;
525 :
526 : /* -------------------------------------------------------------------- */
527 : /* Is this file a PCI .aux file? Check the first line for the */
528 : /* telltale AuxilaryTarget keyword. */
529 : /* */
530 : /* At this point we should be verifying that it refers to our */
531 : /* binary file, but that is a pretty involved test. */
532 : /* -------------------------------------------------------------------- */
533 4 : CPLPushErrorHandler(CPLQuietErrorHandler);
534 4 : const char *pszLine = CPLReadLine2L(fp, 1024, nullptr);
535 4 : CPLPopErrorHandler();
536 :
537 4 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
538 :
539 4 : if (pszLine == nullptr || (!STARTS_WITH_CI(pszLine, "AuxilaryTarget") &&
540 0 : !STARTS_WITH_CI(pszLine, "AuxiliaryTarget")))
541 : {
542 0 : CPLErrorReset();
543 0 : return nullptr;
544 : }
545 :
546 : /* -------------------------------------------------------------------- */
547 : /* Create a corresponding GDALDataset. */
548 : /* -------------------------------------------------------------------- */
549 8 : auto poDS = std::make_unique<PAuxDataset>();
550 :
551 : /* -------------------------------------------------------------------- */
552 : /* Load the .aux file into a string list suitable to be */
553 : /* searched with CSLFetchNameValue(). */
554 : /* -------------------------------------------------------------------- */
555 4 : poDS->papszAuxLines = CSLLoad2(osAuxFilename, 1024, 1024, nullptr);
556 4 : poDS->pszAuxFilename = CPLStrdup(osAuxFilename);
557 :
558 : /* -------------------------------------------------------------------- */
559 : /* Find the RawDefinition line to establish overall parameters. */
560 : /* -------------------------------------------------------------------- */
561 4 : pszLine = CSLFetchNameValue(poDS->papszAuxLines, "RawDefinition");
562 :
563 : // It seems PCI now writes out .aux files without RawDefinition in
564 : // some cases. See bug 947.
565 4 : if (pszLine == nullptr)
566 : {
567 0 : return nullptr;
568 : }
569 :
570 8 : const CPLStringList aosTokens(CSLTokenizeString(pszLine));
571 :
572 4 : if (aosTokens.size() < 3)
573 : {
574 0 : CPLError(CE_Failure, CPLE_AppDefined,
575 : "RawDefinition missing or corrupt in %s.",
576 : poOpenInfo->pszFilename);
577 0 : return nullptr;
578 : }
579 :
580 4 : poDS->nRasterXSize = atoi(aosTokens[0]);
581 4 : poDS->nRasterYSize = atoi(aosTokens[1]);
582 4 : int l_nBands = atoi(aosTokens[2]);
583 4 : poDS->eAccess = poOpenInfo->eAccess;
584 :
585 8 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
586 4 : !GDALCheckBandCount(l_nBands, FALSE))
587 : {
588 0 : return nullptr;
589 : }
590 :
591 : /* -------------------------------------------------------------------- */
592 : /* Open the file. */
593 : /* -------------------------------------------------------------------- */
594 4 : if (poOpenInfo->eAccess == GA_Update)
595 : {
596 0 : poDS->fpImage = VSIFOpenL(osTarget, "rb+");
597 :
598 0 : if (poDS->fpImage == nullptr)
599 : {
600 0 : CPLError(CE_Failure, CPLE_OpenFailed,
601 : "File %s is missing or read-only, check permissions.",
602 : osTarget.c_str());
603 0 : return nullptr;
604 : }
605 : }
606 : else
607 : {
608 4 : poDS->fpImage = VSIFOpenL(osTarget, "rb");
609 :
610 4 : if (poDS->fpImage == nullptr)
611 : {
612 0 : CPLError(CE_Failure, CPLE_OpenFailed,
613 : "File %s is missing or unreadable.", osTarget.c_str());
614 0 : return nullptr;
615 : }
616 : }
617 :
618 : /* -------------------------------------------------------------------- */
619 : /* Collect raw definitions of each channel and create */
620 : /* corresponding bands. */
621 : /* -------------------------------------------------------------------- */
622 12 : for (int i = 0; i < l_nBands; i++)
623 : {
624 8 : char szDefnName[32] = {'\0'};
625 8 : snprintf(szDefnName, sizeof(szDefnName), "ChanDefinition-%d", i + 1);
626 :
627 8 : pszLine = CSLFetchNameValue(poDS->papszAuxLines, szDefnName);
628 8 : if (pszLine == nullptr)
629 : {
630 0 : continue;
631 : }
632 :
633 8 : const CPLStringList aosTokensBand(CSLTokenizeString(pszLine));
634 8 : if (aosTokensBand.size() < 4)
635 : {
636 : // Skip the band with broken description
637 0 : continue;
638 : }
639 :
640 8 : GDALDataType eType = GDT_Unknown;
641 8 : if (EQUAL(aosTokensBand[0], "16U"))
642 8 : eType = GDT_UInt16;
643 0 : else if (EQUAL(aosTokensBand[0], "16S"))
644 0 : eType = GDT_Int16;
645 0 : else if (EQUAL(aosTokensBand[0], "32R"))
646 0 : eType = GDT_Float32;
647 : else
648 0 : eType = GDT_Byte;
649 :
650 8 : bool bNative = true;
651 8 : if (CSLCount(aosTokensBand) > 4)
652 : {
653 : #ifdef CPL_LSB
654 8 : bNative = EQUAL(aosTokensBand[4], "Swapped");
655 : #else
656 : bNative = EQUAL(aosTokensBand[4], "Unswapped");
657 : #endif
658 : }
659 :
660 8 : const vsi_l_offset nBandOffset = CPLScanUIntBig(
661 8 : aosTokensBand[1], static_cast<int>(strlen(aosTokensBand[1])));
662 8 : const int nPixelOffset = atoi(aosTokensBand[2]);
663 8 : const int nLineOffset = atoi(aosTokensBand[3]);
664 :
665 8 : if (nPixelOffset <= 0 || nLineOffset <= 0)
666 : {
667 : // Skip the band with broken offsets.
668 0 : continue;
669 : }
670 :
671 : auto poBand = std::make_unique<PAuxRasterBand>(
672 8 : poDS.get(), poDS->nBands + 1, poDS->fpImage, nBandOffset,
673 8 : nPixelOffset, nLineOffset, eType, bNative);
674 8 : if (!poBand->IsValid())
675 0 : return nullptr;
676 8 : poDS->SetBand(poDS->nBands + 1, std::move(poBand));
677 : }
678 :
679 : /* -------------------------------------------------------------------- */
680 : /* Get the projection. */
681 : /* -------------------------------------------------------------------- */
682 : const char *pszMapUnits =
683 4 : CSLFetchNameValue(poDS->papszAuxLines, "MapUnits");
684 : const char *pszProjParams =
685 4 : CSLFetchNameValue(poDS->papszAuxLines, "ProjParams");
686 :
687 4 : if (pszMapUnits != nullptr)
688 : {
689 4 : poDS->m_oSRS = PCI2SRS(pszMapUnits, pszProjParams);
690 : }
691 :
692 : /* -------------------------------------------------------------------- */
693 : /* Initialize any PAM information. */
694 : /* -------------------------------------------------------------------- */
695 4 : poDS->SetDescription(osTarget);
696 4 : poDS->TryLoadXML();
697 :
698 : /* -------------------------------------------------------------------- */
699 : /* Check for overviews. */
700 : /* -------------------------------------------------------------------- */
701 4 : poDS->oOvManager.Initialize(poDS.get(), osTarget);
702 :
703 4 : poDS->ScanForGCPs();
704 :
705 4 : return poDS.release();
706 : }
707 :
708 : /************************************************************************/
709 : /* GDALRegister_PAux() */
710 : /************************************************************************/
711 :
712 1935 : void GDALRegister_PAux()
713 :
714 : {
715 1935 : if (GDALGetDriverByName("PAux") != nullptr)
716 282 : return;
717 :
718 1653 : GDALDriver *poDriver = new GDALDriver();
719 :
720 1653 : poDriver->SetDescription("PAux");
721 1653 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
722 1653 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PCI .aux Labelled");
723 1653 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/paux.html");
724 1653 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
725 :
726 1653 : poDriver->pfnOpen = PAuxDataset::Open;
727 :
728 1653 : GetGDALDriverManager()->RegisterDriver(poDriver);
729 : }
|