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