LCOV - code coverage report
Current view: top level - frmts/raw - landataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 149 267 55.8 %
Date: 2025-10-21 22:35:35 Functions: 12 18 66.7 %

          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 &gt) 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 &gt) 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             : }

Generated by: LCOV version 1.14