Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: eCognition
4 : * Purpose: Implementation of Erdas .LAN / .GIS format.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2004, Frank Warmerdam
9 : * Copyright (c) 2008-2011, 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 : #include <algorithm>
23 :
24 : /**
25 :
26 : Erdas Header format: "HEAD74"
27 :
28 : Offset Size Type Description
29 : ------ ---- ---- -----------
30 : 0 6 char magic cookie / version (i.e. HEAD74).
31 : 6 2 Int16 Pixel type, 0=8bit, 1=4bit, 2=16bit
32 : 8 2 Int16 Number of Bands.
33 : 10 6 char Unknown.
34 : 16 4 Int32 Width
35 : 20 4 Int32 Height
36 : 24 4 Int32 X Start (offset in original file?)
37 : 28 4 Int32 Y Start (offset in original file?)
38 : 32 56 char Unknown.
39 : 88 2 Int16 0=LAT, 1=UTM, 2=StatePlane, 3- are projections?
40 : 90 2 Int16 Classes in coverage.
41 : 92 14 char Unknown.
42 : 106 2 Int16 Area Unit (0=none, 1=Acre, 2=Hectare, 3=Other)
43 : 108 4 Float32 Pixel area.
44 : 112 4 Float32 Upper Left corner X (center of pixel?)
45 : 116 4 Float32 Upper Left corner Y (center of pixel?)
46 : 120 4 Float32 Width of a pixel.
47 : 124 4 Float32 Height of a pixel.
48 :
49 : Erdas Header format: "HEADER"
50 :
51 : Offset Size Type Description
52 : ------ ---- ---- -----------
53 : 0 6 char magic cookie / version (i.e. HEAD74).
54 : 6 2 Int16 Pixel type, 0=8bit, 1=4bit, 2=16bit
55 : 8 2 Int16 Number of Bands.
56 : 10 6 char Unknown.
57 : 16 4 Float32 Width
58 : 20 4 Float32 Height
59 : 24 4 Int32 X Start (offset in original file?)
60 : 28 4 Int32 Y Start (offset in original file?)
61 : 32 56 char Unknown.
62 : 88 2 Int16 0=LAT, 1=UTM, 2=StatePlane, 3- are projections?
63 : 90 2 Int16 Classes in coverage.
64 : 92 14 char Unknown.
65 : 106 2 Int16 Area Unit (0=none, 1=Acre, 2=Hectare, 3=Other)
66 : 108 4 Float32 Pixel area.
67 : 112 4 Float32 Upper Left corner X (center of pixel?)
68 : 116 4 Float32 Upper Left corner Y (center of pixel?)
69 : 120 4 Float32 Width of a pixel.
70 : 124 4 Float32 Height of a pixel.
71 :
72 : All binary fields are in the same byte order but it may be big endian or
73 : little endian depending on what platform the file was written on. Usually
74 : this can be checked against the number of bands though this test won't work
75 : if there are more than 255 bands.
76 :
77 : There is also some information on .STA and .TRL files at:
78 :
79 : http://www.pcigeomatics.com/cgi-bin/pcihlp/ERDASWR%7CTRAILER+FORMAT
80 :
81 : **/
82 :
83 : constexpr int ERD_HEADER_SIZE = 128;
84 :
85 : /************************************************************************/
86 : /* ==================================================================== */
87 : /* LAN4BitRasterBand */
88 : /* ==================================================================== */
89 : /************************************************************************/
90 :
91 : class LANDataset;
92 :
93 : class LAN4BitRasterBand final : public GDALPamRasterBand
94 : {
95 : GDALColorTable *poCT;
96 : GDALColorInterp eInterp;
97 :
98 : CPL_DISALLOW_COPY_ASSIGN(LAN4BitRasterBand)
99 :
100 : public:
101 : LAN4BitRasterBand(LANDataset *, int);
102 : ~LAN4BitRasterBand() override;
103 :
104 : GDALColorTable *GetColorTable() override;
105 : GDALColorInterp GetColorInterpretation() override;
106 : CPLErr SetColorTable(GDALColorTable *) override;
107 : CPLErr SetColorInterpretation(GDALColorInterp) override;
108 :
109 : CPLErr IReadBlock(int, int, void *) override;
110 : };
111 :
112 : /************************************************************************/
113 : /* ==================================================================== */
114 : /* LANDataset */
115 : /* ==================================================================== */
116 : /************************************************************************/
117 :
118 : class LANDataset final : public RawDataset
119 : {
120 : CPL_DISALLOW_COPY_ASSIGN(LANDataset)
121 :
122 : public:
123 : VSILFILE *fpImage; // Image data file.
124 :
125 : char pachHeader[ERD_HEADER_SIZE];
126 :
127 : OGRSpatialReference *m_poSRS = nullptr;
128 :
129 : GDALGeoTransform m_gt{};
130 :
131 : CPLString osSTAFilename{};
132 : void CheckForStatistics(void);
133 :
134 : char **GetFileList() override;
135 :
136 : CPLErr Close() override;
137 :
138 : public:
139 : LANDataset();
140 : ~LANDataset() override;
141 :
142 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
143 :
144 : const OGRSpatialReference *GetSpatialRef() const override;
145 :
146 : static GDALDataset *Open(GDALOpenInfo *);
147 : };
148 :
149 : /************************************************************************/
150 : /* ==================================================================== */
151 : /* LAN4BitRasterBand */
152 : /* ==================================================================== */
153 : /************************************************************************/
154 :
155 : /************************************************************************/
156 : /* LAN4BitRasterBand() */
157 : /************************************************************************/
158 :
159 2 : LAN4BitRasterBand::LAN4BitRasterBand(LANDataset *poDSIn, int nBandIn)
160 2 : : poCT(nullptr), eInterp(GCI_Undefined)
161 : {
162 2 : poDS = poDSIn;
163 2 : nBand = nBandIn;
164 2 : eDataType = GDT_Byte;
165 :
166 2 : nBlockXSize = poDSIn->GetRasterXSize();
167 2 : nBlockYSize = 1;
168 2 : }
169 :
170 : /************************************************************************/
171 : /* ~LAN4BitRasterBand() */
172 : /************************************************************************/
173 :
174 4 : LAN4BitRasterBand::~LAN4BitRasterBand()
175 :
176 : {
177 2 : if (poCT)
178 0 : delete poCT;
179 4 : }
180 :
181 : /************************************************************************/
182 : /* IReadBlock() */
183 : /************************************************************************/
184 :
185 2 : CPLErr LAN4BitRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
186 : void *pImage)
187 :
188 : {
189 2 : LANDataset *poLAN_DS = cpl::down_cast<LANDataset *>(poDS);
190 2 : CPLAssert(nBlockXOff == 0);
191 :
192 : /* -------------------------------------------------------------------- */
193 : /* Seek to profile. */
194 : /* -------------------------------------------------------------------- */
195 : const vsi_l_offset nOffset =
196 : ERD_HEADER_SIZE +
197 4 : (static_cast<vsi_l_offset>(nBlockYOff) * nRasterXSize *
198 2 : poLAN_DS->GetRasterCount()) /
199 2 : 2 +
200 2 : (static_cast<vsi_l_offset>(nBand - 1) * nRasterXSize) / 2;
201 :
202 2 : if (VSIFSeekL(poLAN_DS->fpImage, nOffset, SEEK_SET) != 0)
203 : {
204 0 : CPLError(CE_Failure, CPLE_FileIO, "LAN Seek failed:%s",
205 0 : VSIStrerror(errno));
206 0 : return CE_Failure;
207 : }
208 :
209 : /* -------------------------------------------------------------------- */
210 : /* Read the profile. */
211 : /* -------------------------------------------------------------------- */
212 2 : if (VSIFReadL(pImage, 1, nRasterXSize / 2, poLAN_DS->fpImage) !=
213 2 : static_cast<size_t>(nRasterXSize) / 2)
214 : {
215 0 : CPLError(CE_Failure, CPLE_FileIO, "LAN Read failed:%s",
216 0 : VSIStrerror(errno));
217 0 : return CE_Failure;
218 : }
219 :
220 : /* -------------------------------------------------------------------- */
221 : /* Convert 4bit to 8bit. */
222 : /* -------------------------------------------------------------------- */
223 6 : for (int i = nRasterXSize - 1; i >= 0; i--)
224 : {
225 4 : if ((i & 0x01) != 0)
226 2 : reinterpret_cast<GByte *>(pImage)[i] =
227 2 : reinterpret_cast<GByte *>(pImage)[i / 2] & 0x0f;
228 : else
229 2 : reinterpret_cast<GByte *>(pImage)[i] =
230 2 : (reinterpret_cast<GByte *>(pImage)[i / 2] & 0xf0) / 16;
231 : }
232 :
233 2 : return CE_None;
234 : }
235 :
236 : /************************************************************************/
237 : /* SetColorTable() */
238 : /************************************************************************/
239 :
240 0 : CPLErr LAN4BitRasterBand::SetColorTable(GDALColorTable *poNewCT)
241 :
242 : {
243 0 : if (poCT)
244 0 : delete poCT;
245 0 : if (poNewCT == nullptr)
246 0 : poCT = nullptr;
247 : else
248 0 : poCT = poNewCT->Clone();
249 :
250 0 : return CE_None;
251 : }
252 :
253 : /************************************************************************/
254 : /* GetColorTable() */
255 : /************************************************************************/
256 :
257 0 : GDALColorTable *LAN4BitRasterBand::GetColorTable()
258 :
259 : {
260 0 : if (poCT != nullptr)
261 0 : return poCT;
262 :
263 0 : return GDALPamRasterBand::GetColorTable();
264 : }
265 :
266 : /************************************************************************/
267 : /* SetColorInterpretation() */
268 : /************************************************************************/
269 :
270 0 : CPLErr LAN4BitRasterBand::SetColorInterpretation(GDALColorInterp eNewInterp)
271 :
272 : {
273 0 : eInterp = eNewInterp;
274 :
275 0 : return CE_None;
276 : }
277 :
278 : /************************************************************************/
279 : /* GetColorInterpretation() */
280 : /************************************************************************/
281 :
282 0 : GDALColorInterp LAN4BitRasterBand::GetColorInterpretation()
283 :
284 : {
285 0 : return eInterp;
286 : }
287 :
288 : /************************************************************************/
289 : /* ==================================================================== */
290 : /* LANDataset */
291 : /* ==================================================================== */
292 : /************************************************************************/
293 :
294 : /************************************************************************/
295 : /* LANDataset() */
296 : /************************************************************************/
297 :
298 4 : LANDataset::LANDataset() : fpImage(nullptr)
299 : {
300 4 : memset(pachHeader, 0, sizeof(pachHeader));
301 4 : }
302 :
303 : /************************************************************************/
304 : /* ~LANDataset() */
305 : /************************************************************************/
306 :
307 8 : LANDataset::~LANDataset()
308 :
309 : {
310 4 : LANDataset::Close();
311 8 : }
312 :
313 : /************************************************************************/
314 : /* Close() */
315 : /************************************************************************/
316 :
317 8 : CPLErr LANDataset::Close()
318 : {
319 8 : CPLErr eErr = CE_None;
320 8 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
321 : {
322 4 : if (LANDataset::FlushCache(true) != CE_None)
323 0 : eErr = CE_Failure;
324 :
325 4 : if (fpImage)
326 : {
327 4 : if (VSIFCloseL(fpImage) != 0)
328 : {
329 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
330 0 : eErr = CE_Failure;
331 : }
332 : }
333 :
334 4 : if (m_poSRS)
335 4 : m_poSRS->Release();
336 :
337 4 : if (GDALPamDataset::Close() != CE_None)
338 0 : eErr = CE_Failure;
339 : }
340 8 : return eErr;
341 : }
342 :
343 : /************************************************************************/
344 : /* Open() */
345 : /************************************************************************/
346 :
347 34377 : GDALDataset *LANDataset::Open(GDALOpenInfo *poOpenInfo)
348 :
349 : {
350 : /* -------------------------------------------------------------------- */
351 : /* We assume the user is pointing to the header (.pcb) file. */
352 : /* Does this appear to be a pcb file? */
353 : /* -------------------------------------------------------------------- */
354 34377 : if (poOpenInfo->nHeaderBytes < ERD_HEADER_SIZE ||
355 3205 : poOpenInfo->fpL == nullptr)
356 31201 : return nullptr;
357 :
358 3176 : if (!STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
359 3176 : "HEADER") &&
360 3176 : !STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
361 : "HEAD74"))
362 3172 : return nullptr;
363 :
364 4 : if (memcmp(poOpenInfo->pabyHeader + 16, "S LAT ", 8) == 0)
365 : {
366 : // NTV1 format
367 0 : return nullptr;
368 : }
369 :
370 : /* -------------------------------------------------------------------- */
371 : /* Create a corresponding GDALDataset. */
372 : /* -------------------------------------------------------------------- */
373 8 : auto poDS = std::make_unique<LANDataset>();
374 :
375 4 : poDS->eAccess = poOpenInfo->eAccess;
376 4 : std::swap(poDS->fpImage, poOpenInfo->fpL);
377 :
378 : /* -------------------------------------------------------------------- */
379 : /* Do we need to byte swap the headers to local machine order? */
380 : /* -------------------------------------------------------------------- */
381 4 : const RawRasterBand::ByteOrder eByteOrder =
382 4 : poOpenInfo->pabyHeader[8] == 0
383 4 : ? RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN
384 : : RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN;
385 :
386 4 : memcpy(poDS->pachHeader, poOpenInfo->pabyHeader, ERD_HEADER_SIZE);
387 :
388 4 : if (eByteOrder != RawRasterBand::NATIVE_BYTE_ORDER)
389 : {
390 0 : CPL_SWAP16PTR(poDS->pachHeader + 6);
391 0 : CPL_SWAP16PTR(poDS->pachHeader + 8);
392 :
393 0 : CPL_SWAP32PTR(poDS->pachHeader + 16);
394 0 : CPL_SWAP32PTR(poDS->pachHeader + 20);
395 0 : CPL_SWAP32PTR(poDS->pachHeader + 24);
396 0 : CPL_SWAP32PTR(poDS->pachHeader + 28);
397 :
398 0 : CPL_SWAP16PTR(poDS->pachHeader + 88);
399 0 : CPL_SWAP16PTR(poDS->pachHeader + 90);
400 :
401 0 : CPL_SWAP16PTR(poDS->pachHeader + 106);
402 0 : CPL_SWAP32PTR(poDS->pachHeader + 108);
403 0 : CPL_SWAP32PTR(poDS->pachHeader + 112);
404 0 : CPL_SWAP32PTR(poDS->pachHeader + 116);
405 0 : CPL_SWAP32PTR(poDS->pachHeader + 120);
406 0 : CPL_SWAP32PTR(poDS->pachHeader + 124);
407 : }
408 :
409 : /* -------------------------------------------------------------------- */
410 : /* Capture some information from the file that is of interest. */
411 : /* -------------------------------------------------------------------- */
412 4 : if (STARTS_WITH_CI(poDS->pachHeader, "HEADER"))
413 : {
414 0 : float fTmp = 0.0;
415 0 : memcpy(&fTmp, poDS->pachHeader + 16, 4);
416 0 : poDS->nRasterXSize = static_cast<int>(fTmp);
417 0 : memcpy(&fTmp, poDS->pachHeader + 20, 4);
418 0 : poDS->nRasterYSize = static_cast<int>(fTmp);
419 : }
420 : else
421 : {
422 4 : GInt32 nTmp = 0;
423 4 : memcpy(&nTmp, poDS->pachHeader + 16, 4);
424 4 : poDS->nRasterXSize = nTmp;
425 4 : memcpy(&nTmp, poDS->pachHeader + 20, 4);
426 4 : poDS->nRasterYSize = nTmp;
427 : }
428 :
429 4 : GInt16 nTmp16 = 0;
430 4 : memcpy(&nTmp16, poDS->pachHeader + 6, 2);
431 :
432 4 : int nPixelOffset = 0;
433 4 : GDALDataType eDataType = GDT_Unknown;
434 4 : if (nTmp16 == 0)
435 : {
436 2 : eDataType = GDT_Byte;
437 2 : nPixelOffset = 1;
438 : }
439 2 : else if (nTmp16 == 1) // 4 bit
440 : {
441 2 : eDataType = GDT_Byte;
442 2 : nPixelOffset = -1;
443 : }
444 0 : else if (nTmp16 == 2)
445 : {
446 0 : nPixelOffset = 2;
447 0 : eDataType = GDT_Int16;
448 : }
449 : else
450 : {
451 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unsupported pixel type (%d).",
452 : nTmp16);
453 0 : return nullptr;
454 : }
455 :
456 4 : memcpy(&nTmp16, poDS->pachHeader + 8, 2);
457 4 : const int nBandCount = nTmp16;
458 :
459 8 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
460 4 : !GDALCheckBandCount(nBandCount, FALSE))
461 : {
462 0 : return nullptr;
463 : }
464 :
465 : // cppcheck-suppress knownConditionTrueFalse
466 6 : if (nPixelOffset != -1 &&
467 2 : poDS->nRasterXSize > INT_MAX / (nPixelOffset * nBandCount))
468 : {
469 0 : CPLError(CE_Failure, CPLE_AppDefined, "Int overflow occurred.");
470 0 : return nullptr;
471 : }
472 :
473 : /* -------------------------------------------------------------------- */
474 : /* Create band information object. */
475 : /* -------------------------------------------------------------------- */
476 8 : for (int iBand = 1; iBand <= nBandCount; iBand++)
477 : {
478 4 : if (nPixelOffset == -1) /* 4 bit case */
479 2 : poDS->SetBand(iBand, new LAN4BitRasterBand(poDS.get(), iBand));
480 : else
481 : {
482 : auto poBand = RawRasterBand::Create(
483 4 : poDS.get(), iBand, poDS->fpImage,
484 2 : ERD_HEADER_SIZE +
485 4 : (iBand - 1) * nPixelOffset * poDS->nRasterXSize,
486 2 : nPixelOffset, poDS->nRasterXSize * nPixelOffset * nBandCount,
487 2 : eDataType, eByteOrder, RawRasterBand::OwnFP::NO);
488 2 : if (!poBand)
489 0 : return nullptr;
490 2 : poDS->SetBand(iBand, std::move(poBand));
491 : }
492 : }
493 :
494 : /* -------------------------------------------------------------------- */
495 : /* Initialize any PAM information. */
496 : /* -------------------------------------------------------------------- */
497 4 : poDS->SetDescription(poOpenInfo->pszFilename);
498 4 : poDS->CheckForStatistics();
499 4 : poDS->TryLoadXML();
500 :
501 : /* -------------------------------------------------------------------- */
502 : /* Check for overviews. */
503 : /* -------------------------------------------------------------------- */
504 4 : poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
505 :
506 : /* -------------------------------------------------------------------- */
507 : /* Try to interpret georeferencing. */
508 : /* -------------------------------------------------------------------- */
509 4 : float fTmp = 0.0;
510 :
511 4 : memcpy(&fTmp, poDS->pachHeader + 112, 4);
512 4 : poDS->m_gt[0] = fTmp;
513 4 : memcpy(&fTmp, poDS->pachHeader + 120, 4);
514 4 : poDS->m_gt[1] = fTmp;
515 4 : poDS->m_gt[2] = 0.0;
516 4 : memcpy(&fTmp, poDS->pachHeader + 116, 4);
517 4 : poDS->m_gt[3] = fTmp;
518 4 : poDS->m_gt[4] = 0.0;
519 4 : memcpy(&fTmp, poDS->pachHeader + 124, 4);
520 4 : poDS->m_gt[5] = -fTmp;
521 :
522 : // adjust for center of pixel vs. top left corner of pixel.
523 4 : poDS->m_gt[0] -= poDS->m_gt[1] * 0.5;
524 4 : poDS->m_gt[3] -= poDS->m_gt[5] * 0.5;
525 :
526 : /* -------------------------------------------------------------------- */
527 : /* If we didn't get any georeferencing, try for a worldfile. */
528 : /* -------------------------------------------------------------------- */
529 4 : if (poDS->m_gt[1] == 0.0 || poDS->m_gt[5] == 0.0)
530 : {
531 0 : if (!GDALReadWorldFile(poOpenInfo->pszFilename, nullptr,
532 0 : poDS->m_gt.data()))
533 0 : GDALReadWorldFile(poOpenInfo->pszFilename, ".wld",
534 0 : poDS->m_gt.data());
535 : }
536 :
537 : /* -------------------------------------------------------------------- */
538 : /* Try to come up with something for the coordinate system. */
539 : /* -------------------------------------------------------------------- */
540 4 : memcpy(&nTmp16, poDS->pachHeader + 88, 2);
541 4 : int nCoordSys = nTmp16;
542 :
543 4 : poDS->m_poSRS = new OGRSpatialReference();
544 4 : poDS->m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
545 4 : if (nCoordSys == 0)
546 : {
547 4 : poDS->m_poSRS->SetFromUserInput(SRS_WKT_WGS84_LAT_LONG);
548 : }
549 0 : else if (nCoordSys == 1)
550 : {
551 0 : poDS->m_poSRS->SetFromUserInput(
552 : "LOCAL_CS[\"UTM - Zone Unknown\",UNIT[\"Meter\",1]]");
553 : }
554 0 : else if (nCoordSys == 2)
555 : {
556 0 : poDS->m_poSRS->SetFromUserInput(
557 : "LOCAL_CS[\"State Plane - Zone Unknown\","
558 : "UNIT[\"US survey foot\",0.3048006096012192]]");
559 : }
560 : else
561 : {
562 0 : poDS->m_poSRS->SetFromUserInput(
563 : "LOCAL_CS[\"Unknown\",UNIT[\"Meter\",1]]");
564 : }
565 :
566 : /* -------------------------------------------------------------------- */
567 : /* Check for a trailer file with a colormap in it. */
568 : /* -------------------------------------------------------------------- */
569 4 : char *pszPath = CPLStrdup(CPLGetPathSafe(poOpenInfo->pszFilename).c_str());
570 : char *pszBasename =
571 4 : CPLStrdup(CPLGetBasenameSafe(poOpenInfo->pszFilename).c_str());
572 : const std::string osTRLFilename =
573 8 : CPLFormCIFilenameSafe(pszPath, pszBasename, "trl");
574 4 : VSILFILE *fpTRL = VSIFOpenL(osTRLFilename.c_str(), "rb");
575 4 : if (fpTRL != nullptr)
576 : {
577 0 : char szTRLData[896] = {'\0'};
578 :
579 0 : CPL_IGNORE_RET_VAL(VSIFReadL(szTRLData, 1, 896, fpTRL));
580 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTRL));
581 :
582 0 : GDALColorTable oCT;
583 0 : for (int iColor = 0; iColor < 256; iColor++)
584 : {
585 0 : GDALColorEntry sEntry = {0, 0, 0, 0};
586 :
587 0 : sEntry.c2 = reinterpret_cast<GByte *>(szTRLData)[iColor + 128];
588 0 : sEntry.c1 =
589 0 : reinterpret_cast<GByte *>(szTRLData)[iColor + 128 + 256];
590 0 : sEntry.c3 =
591 0 : reinterpret_cast<GByte *>(szTRLData)[iColor + 128 + 512];
592 0 : sEntry.c4 = 255;
593 0 : oCT.SetColorEntry(iColor, &sEntry);
594 :
595 : // Only 16 colors in 4bit files.
596 0 : if (nPixelOffset == -1 && iColor == 15)
597 0 : break;
598 : }
599 :
600 0 : poDS->GetRasterBand(1)->SetColorTable(&oCT);
601 0 : poDS->GetRasterBand(1)->SetColorInterpretation(GCI_PaletteIndex);
602 : }
603 :
604 4 : CPLFree(pszPath);
605 4 : CPLFree(pszBasename);
606 :
607 4 : return poDS.release();
608 : }
609 :
610 : /************************************************************************/
611 : /* GetGeoTransform() */
612 : /************************************************************************/
613 :
614 0 : CPLErr LANDataset::GetGeoTransform(GDALGeoTransform >) const
615 :
616 : {
617 0 : if (m_gt[1] != 0.0 && m_gt[5] != 0.0)
618 : {
619 0 : gt = m_gt;
620 0 : return CE_None;
621 : }
622 :
623 0 : return GDALPamDataset::GetGeoTransform(gt);
624 : }
625 :
626 : /************************************************************************/
627 : /* GetSpatialRef() */
628 : /* */
629 : /* Use PAM coordinate system if available in preference to the */
630 : /* generally poor value derived from the file itself. */
631 : /************************************************************************/
632 :
633 0 : const OGRSpatialReference *LANDataset::GetSpatialRef() const
634 :
635 : {
636 0 : const auto poSRS = GDALPamDataset::GetSpatialRef();
637 0 : if (poSRS)
638 0 : return poSRS;
639 :
640 0 : return m_poSRS;
641 : }
642 :
643 : /************************************************************************/
644 : /* GetFileList() */
645 : /************************************************************************/
646 :
647 2 : char **LANDataset::GetFileList()
648 :
649 : {
650 : // Main data file, etc.
651 2 : char **papszFileList = GDALPamDataset::GetFileList();
652 :
653 2 : if (!osSTAFilename.empty())
654 0 : papszFileList = CSLAddString(papszFileList, osSTAFilename);
655 :
656 2 : return papszFileList;
657 : }
658 :
659 : /************************************************************************/
660 : /* CheckForStatistics() */
661 : /************************************************************************/
662 :
663 4 : void LANDataset::CheckForStatistics()
664 :
665 : {
666 : /* -------------------------------------------------------------------- */
667 : /* Do we have a statistics file? */
668 : /* -------------------------------------------------------------------- */
669 4 : osSTAFilename = CPLResetExtensionSafe(GetDescription(), "sta");
670 :
671 4 : VSILFILE *fpSTA = VSIFOpenL(osSTAFilename, "r");
672 :
673 4 : if (fpSTA == nullptr && VSIIsCaseSensitiveFS(osSTAFilename))
674 : {
675 4 : osSTAFilename = CPLResetExtensionSafe(GetDescription(), "STA");
676 4 : fpSTA = VSIFOpenL(osSTAFilename, "r");
677 : }
678 :
679 4 : if (fpSTA == nullptr)
680 : {
681 4 : osSTAFilename = "";
682 4 : return;
683 : }
684 :
685 : /* -------------------------------------------------------------------- */
686 : /* Read it one band at a time. */
687 : /* -------------------------------------------------------------------- */
688 0 : GByte abyBandInfo[1152] = {'\0'};
689 :
690 0 : for (int iBand = 0; iBand < nBands; iBand++)
691 : {
692 0 : if (VSIFReadL(abyBandInfo, 1152, 1, fpSTA) != 1)
693 0 : break;
694 :
695 0 : const int nBandNumber = abyBandInfo[7];
696 0 : GDALRasterBand *poBand = GetRasterBand(nBandNumber);
697 0 : if (poBand == nullptr)
698 0 : break;
699 :
700 0 : GInt16 nMin = 0;
701 0 : GInt16 nMax = 0;
702 :
703 0 : if (poBand->GetRasterDataType() != GDT_Byte)
704 : {
705 0 : memcpy(&nMin, abyBandInfo + 28, 2);
706 0 : memcpy(&nMax, abyBandInfo + 30, 2);
707 0 : CPL_LSBPTR16(&nMin);
708 0 : CPL_LSBPTR16(&nMax);
709 : }
710 : else
711 : {
712 0 : nMin = abyBandInfo[9];
713 0 : nMax = abyBandInfo[8];
714 : }
715 :
716 0 : float fMean = 0.0;
717 0 : float fStdDev = 0.0;
718 0 : memcpy(&fMean, abyBandInfo + 12, 4);
719 0 : memcpy(&fStdDev, abyBandInfo + 24, 4);
720 0 : CPL_LSBPTR32(&fMean);
721 0 : CPL_LSBPTR32(&fStdDev);
722 :
723 0 : poBand->SetStatistics(nMin, nMax, fMean, fStdDev);
724 : }
725 :
726 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpSTA));
727 : }
728 :
729 : /************************************************************************/
730 : /* GDALRegister_LAN() */
731 : /************************************************************************/
732 :
733 2038 : void GDALRegister_LAN()
734 :
735 : {
736 2038 : if (GDALGetDriverByName("LAN") != nullptr)
737 283 : return;
738 :
739 1755 : GDALDriver *poDriver = new GDALDriver();
740 :
741 1755 : poDriver->SetDescription("LAN");
742 1755 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
743 1755 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Erdas .LAN/.GIS");
744 1755 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/lan.html");
745 1755 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
746 :
747 1755 : poDriver->pfnOpen = LANDataset::Open;
748 :
749 1755 : GetGDALDriverManager()->RegisterDriver(poDriver);
750 : }
|