LCOV - code coverage report
Current view: top level - frmts/raw - landataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 155 273 56.8 %
Date: 2025-03-28 21:34:50 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 "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             : }

Generated by: LCOV version 1.14