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