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-07-02 23:05:47 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             :     GDALGeoTransform m_gt{};
     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(GDALGeoTransform &gt) const 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 : }
     301             : 
     302             : /************************************************************************/
     303             : /*                            ~LANDataset()                             */
     304             : /************************************************************************/
     305             : 
     306           8 : LANDataset::~LANDataset()
     307             : 
     308             : {
     309           4 :     LANDataset::Close();
     310           8 : }
     311             : 
     312             : /************************************************************************/
     313             : /*                              Close()                                 */
     314             : /************************************************************************/
     315             : 
     316           8 : CPLErr LANDataset::Close()
     317             : {
     318           8 :     CPLErr eErr = CE_None;
     319           8 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     320             :     {
     321           4 :         if (LANDataset::FlushCache(true) != CE_None)
     322           0 :             eErr = CE_Failure;
     323             : 
     324           4 :         if (fpImage)
     325             :         {
     326           4 :             if (VSIFCloseL(fpImage) != 0)
     327             :             {
     328           0 :                 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     329           0 :                 eErr = CE_Failure;
     330             :             }
     331             :         }
     332             : 
     333           4 :         if (m_poSRS)
     334           4 :             m_poSRS->Release();
     335             : 
     336           4 :         if (GDALPamDataset::Close() != CE_None)
     337           0 :             eErr = CE_Failure;
     338             :     }
     339           8 :     return eErr;
     340             : }
     341             : 
     342             : /************************************************************************/
     343             : /*                                Open()                                */
     344             : /************************************************************************/
     345             : 
     346       33377 : GDALDataset *LANDataset::Open(GDALOpenInfo *poOpenInfo)
     347             : 
     348             : {
     349             :     /* -------------------------------------------------------------------- */
     350             :     /*      We assume the user is pointing to the header (.pcb) file.       */
     351             :     /*      Does this appear to be a pcb file?                              */
     352             :     /* -------------------------------------------------------------------- */
     353       33377 :     if (poOpenInfo->nHeaderBytes < ERD_HEADER_SIZE ||
     354        3072 :         poOpenInfo->fpL == nullptr)
     355       30334 :         return nullptr;
     356             : 
     357        3043 :     if (!STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
     358        3043 :                         "HEADER") &&
     359        3043 :         !STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
     360             :                         "HEAD74"))
     361        3039 :         return nullptr;
     362             : 
     363           4 :     if (memcmp(poOpenInfo->pabyHeader + 16, "S LAT   ", 8) == 0)
     364             :     {
     365             :         // NTV1 format
     366           0 :         return nullptr;
     367             :     }
     368             : 
     369             :     /* -------------------------------------------------------------------- */
     370             :     /*      Create a corresponding GDALDataset.                             */
     371             :     /* -------------------------------------------------------------------- */
     372           8 :     auto poDS = std::make_unique<LANDataset>();
     373             : 
     374           4 :     poDS->eAccess = poOpenInfo->eAccess;
     375           4 :     std::swap(poDS->fpImage, poOpenInfo->fpL);
     376             : 
     377             :     /* -------------------------------------------------------------------- */
     378             :     /*      Do we need to byte swap the headers to local machine order?     */
     379             :     /* -------------------------------------------------------------------- */
     380           4 :     const RawRasterBand::ByteOrder eByteOrder =
     381           4 :         poOpenInfo->pabyHeader[8] == 0
     382           4 :             ? RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN
     383             :             : RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN;
     384             : 
     385           4 :     memcpy(poDS->pachHeader, poOpenInfo->pabyHeader, ERD_HEADER_SIZE);
     386             : 
     387           4 :     if (eByteOrder != RawRasterBand::NATIVE_BYTE_ORDER)
     388             :     {
     389           0 :         CPL_SWAP16PTR(poDS->pachHeader + 6);
     390           0 :         CPL_SWAP16PTR(poDS->pachHeader + 8);
     391             : 
     392           0 :         CPL_SWAP32PTR(poDS->pachHeader + 16);
     393           0 :         CPL_SWAP32PTR(poDS->pachHeader + 20);
     394           0 :         CPL_SWAP32PTR(poDS->pachHeader + 24);
     395           0 :         CPL_SWAP32PTR(poDS->pachHeader + 28);
     396             : 
     397           0 :         CPL_SWAP16PTR(poDS->pachHeader + 88);
     398           0 :         CPL_SWAP16PTR(poDS->pachHeader + 90);
     399             : 
     400           0 :         CPL_SWAP16PTR(poDS->pachHeader + 106);
     401           0 :         CPL_SWAP32PTR(poDS->pachHeader + 108);
     402           0 :         CPL_SWAP32PTR(poDS->pachHeader + 112);
     403           0 :         CPL_SWAP32PTR(poDS->pachHeader + 116);
     404           0 :         CPL_SWAP32PTR(poDS->pachHeader + 120);
     405           0 :         CPL_SWAP32PTR(poDS->pachHeader + 124);
     406             :     }
     407             : 
     408             :     /* -------------------------------------------------------------------- */
     409             :     /*      Capture some information from the file that is of interest.     */
     410             :     /* -------------------------------------------------------------------- */
     411           4 :     if (STARTS_WITH_CI(poDS->pachHeader, "HEADER"))
     412             :     {
     413           0 :         float fTmp = 0.0;
     414           0 :         memcpy(&fTmp, poDS->pachHeader + 16, 4);
     415           0 :         poDS->nRasterXSize = static_cast<int>(fTmp);
     416           0 :         memcpy(&fTmp, poDS->pachHeader + 20, 4);
     417           0 :         poDS->nRasterYSize = static_cast<int>(fTmp);
     418             :     }
     419             :     else
     420             :     {
     421           4 :         GInt32 nTmp = 0;
     422           4 :         memcpy(&nTmp, poDS->pachHeader + 16, 4);
     423           4 :         poDS->nRasterXSize = nTmp;
     424           4 :         memcpy(&nTmp, poDS->pachHeader + 20, 4);
     425           4 :         poDS->nRasterYSize = nTmp;
     426             :     }
     427             : 
     428           4 :     GInt16 nTmp16 = 0;
     429           4 :     memcpy(&nTmp16, poDS->pachHeader + 6, 2);
     430             : 
     431           4 :     int nPixelOffset = 0;
     432           4 :     GDALDataType eDataType = GDT_Unknown;
     433           4 :     if (nTmp16 == 0)
     434             :     {
     435           2 :         eDataType = GDT_Byte;
     436           2 :         nPixelOffset = 1;
     437             :     }
     438           2 :     else if (nTmp16 == 1)  // 4 bit
     439             :     {
     440           2 :         eDataType = GDT_Byte;
     441           2 :         nPixelOffset = -1;
     442             :     }
     443           0 :     else if (nTmp16 == 2)
     444             :     {
     445           0 :         nPixelOffset = 2;
     446           0 :         eDataType = GDT_Int16;
     447             :     }
     448             :     else
     449             :     {
     450           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unsupported pixel type (%d).",
     451             :                  nTmp16);
     452           0 :         return nullptr;
     453             :     }
     454             : 
     455           4 :     memcpy(&nTmp16, poDS->pachHeader + 8, 2);
     456           4 :     const int nBandCount = nTmp16;
     457             : 
     458           8 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
     459           4 :         !GDALCheckBandCount(nBandCount, FALSE))
     460             :     {
     461           0 :         return nullptr;
     462             :     }
     463             : 
     464             :     // cppcheck-suppress knownConditionTrueFalse
     465           6 :     if (nPixelOffset != -1 &&
     466           2 :         poDS->nRasterXSize > INT_MAX / (nPixelOffset * nBandCount))
     467             :     {
     468           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Int overflow occurred.");
     469           0 :         return nullptr;
     470             :     }
     471             : 
     472             :     /* -------------------------------------------------------------------- */
     473             :     /*      Create band information object.                                 */
     474             :     /* -------------------------------------------------------------------- */
     475           8 :     for (int iBand = 1; iBand <= nBandCount; iBand++)
     476             :     {
     477           4 :         if (nPixelOffset == -1) /* 4 bit case */
     478           2 :             poDS->SetBand(iBand, new LAN4BitRasterBand(poDS.get(), iBand));
     479             :         else
     480             :         {
     481             :             auto poBand = RawRasterBand::Create(
     482           4 :                 poDS.get(), iBand, poDS->fpImage,
     483           2 :                 ERD_HEADER_SIZE +
     484           4 :                     (iBand - 1) * nPixelOffset * poDS->nRasterXSize,
     485           2 :                 nPixelOffset, poDS->nRasterXSize * nPixelOffset * nBandCount,
     486           2 :                 eDataType, eByteOrder, RawRasterBand::OwnFP::NO);
     487           2 :             if (!poBand)
     488           0 :                 return nullptr;
     489           2 :             poDS->SetBand(iBand, std::move(poBand));
     490             :         }
     491             :     }
     492             : 
     493             :     /* -------------------------------------------------------------------- */
     494             :     /*      Initialize any PAM information.                                 */
     495             :     /* -------------------------------------------------------------------- */
     496           4 :     poDS->SetDescription(poOpenInfo->pszFilename);
     497           4 :     poDS->CheckForStatistics();
     498           4 :     poDS->TryLoadXML();
     499             : 
     500             :     /* -------------------------------------------------------------------- */
     501             :     /*      Check for overviews.                                            */
     502             :     /* -------------------------------------------------------------------- */
     503           4 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
     504             : 
     505             :     /* -------------------------------------------------------------------- */
     506             :     /*      Try to interpret georeferencing.                                */
     507             :     /* -------------------------------------------------------------------- */
     508           4 :     float fTmp = 0.0;
     509             : 
     510           4 :     memcpy(&fTmp, poDS->pachHeader + 112, 4);
     511           4 :     poDS->m_gt[0] = fTmp;
     512           4 :     memcpy(&fTmp, poDS->pachHeader + 120, 4);
     513           4 :     poDS->m_gt[1] = fTmp;
     514           4 :     poDS->m_gt[2] = 0.0;
     515           4 :     memcpy(&fTmp, poDS->pachHeader + 116, 4);
     516           4 :     poDS->m_gt[3] = fTmp;
     517           4 :     poDS->m_gt[4] = 0.0;
     518           4 :     memcpy(&fTmp, poDS->pachHeader + 124, 4);
     519           4 :     poDS->m_gt[5] = -fTmp;
     520             : 
     521             :     // adjust for center of pixel vs. top left corner of pixel.
     522           4 :     poDS->m_gt[0] -= poDS->m_gt[1] * 0.5;
     523           4 :     poDS->m_gt[3] -= poDS->m_gt[5] * 0.5;
     524             : 
     525             :     /* -------------------------------------------------------------------- */
     526             :     /*      If we didn't get any georeferencing, try for a worldfile.       */
     527             :     /* -------------------------------------------------------------------- */
     528           4 :     if (poDS->m_gt[1] == 0.0 || poDS->m_gt[5] == 0.0)
     529             :     {
     530           0 :         if (!GDALReadWorldFile(poOpenInfo->pszFilename, nullptr,
     531           0 :                                poDS->m_gt.data()))
     532           0 :             GDALReadWorldFile(poOpenInfo->pszFilename, ".wld",
     533           0 :                               poDS->m_gt.data());
     534             :     }
     535             : 
     536             :     /* -------------------------------------------------------------------- */
     537             :     /*      Try to come up with something for the coordinate system.        */
     538             :     /* -------------------------------------------------------------------- */
     539           4 :     memcpy(&nTmp16, poDS->pachHeader + 88, 2);
     540           4 :     int nCoordSys = nTmp16;
     541             : 
     542           4 :     poDS->m_poSRS = new OGRSpatialReference();
     543           4 :     poDS->m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     544           4 :     if (nCoordSys == 0)
     545             :     {
     546           4 :         poDS->m_poSRS->SetFromUserInput(SRS_WKT_WGS84_LAT_LONG);
     547             :     }
     548           0 :     else if (nCoordSys == 1)
     549             :     {
     550           0 :         poDS->m_poSRS->SetFromUserInput(
     551             :             "LOCAL_CS[\"UTM - Zone Unknown\",UNIT[\"Meter\",1]]");
     552             :     }
     553           0 :     else if (nCoordSys == 2)
     554             :     {
     555           0 :         poDS->m_poSRS->SetFromUserInput(
     556             :             "LOCAL_CS[\"State Plane - Zone Unknown\","
     557             :             "UNIT[\"US survey foot\",0.3048006096012192]]");
     558             :     }
     559             :     else
     560             :     {
     561           0 :         poDS->m_poSRS->SetFromUserInput(
     562             :             "LOCAL_CS[\"Unknown\",UNIT[\"Meter\",1]]");
     563             :     }
     564             : 
     565             :     /* -------------------------------------------------------------------- */
     566             :     /*      Check for a trailer file with a colormap in it.                 */
     567             :     /* -------------------------------------------------------------------- */
     568           4 :     char *pszPath = CPLStrdup(CPLGetPathSafe(poOpenInfo->pszFilename).c_str());
     569             :     char *pszBasename =
     570           4 :         CPLStrdup(CPLGetBasenameSafe(poOpenInfo->pszFilename).c_str());
     571             :     const std::string osTRLFilename =
     572           8 :         CPLFormCIFilenameSafe(pszPath, pszBasename, "trl");
     573           4 :     VSILFILE *fpTRL = VSIFOpenL(osTRLFilename.c_str(), "rb");
     574           4 :     if (fpTRL != nullptr)
     575             :     {
     576           0 :         char szTRLData[896] = {'\0'};
     577             : 
     578           0 :         CPL_IGNORE_RET_VAL(VSIFReadL(szTRLData, 1, 896, fpTRL));
     579           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpTRL));
     580             : 
     581           0 :         GDALColorTable oCT;
     582           0 :         for (int iColor = 0; iColor < 256; iColor++)
     583             :         {
     584           0 :             GDALColorEntry sEntry = {0, 0, 0, 0};
     585             : 
     586           0 :             sEntry.c2 = reinterpret_cast<GByte *>(szTRLData)[iColor + 128];
     587           0 :             sEntry.c1 =
     588           0 :                 reinterpret_cast<GByte *>(szTRLData)[iColor + 128 + 256];
     589           0 :             sEntry.c3 =
     590           0 :                 reinterpret_cast<GByte *>(szTRLData)[iColor + 128 + 512];
     591           0 :             sEntry.c4 = 255;
     592           0 :             oCT.SetColorEntry(iColor, &sEntry);
     593             : 
     594             :             // Only 16 colors in 4bit files.
     595           0 :             if (nPixelOffset == -1 && iColor == 15)
     596           0 :                 break;
     597             :         }
     598             : 
     599           0 :         poDS->GetRasterBand(1)->SetColorTable(&oCT);
     600           0 :         poDS->GetRasterBand(1)->SetColorInterpretation(GCI_PaletteIndex);
     601             :     }
     602             : 
     603           4 :     CPLFree(pszPath);
     604           4 :     CPLFree(pszBasename);
     605             : 
     606           4 :     return poDS.release();
     607             : }
     608             : 
     609             : /************************************************************************/
     610             : /*                          GetGeoTransform()                           */
     611             : /************************************************************************/
     612             : 
     613           0 : CPLErr LANDataset::GetGeoTransform(GDALGeoTransform &gt) const
     614             : 
     615             : {
     616           0 :     if (m_gt[1] != 0.0 && m_gt[5] != 0.0)
     617             :     {
     618           0 :         gt = m_gt;
     619           0 :         return CE_None;
     620             :     }
     621             : 
     622           0 :     return GDALPamDataset::GetGeoTransform(gt);
     623             : }
     624             : 
     625             : /************************************************************************/
     626             : /*                          GetSpatialRef()                             */
     627             : /*                                                                      */
     628             : /*      Use PAM coordinate system if available in preference to the     */
     629             : /*      generally poor value derived from the file itself.              */
     630             : /************************************************************************/
     631             : 
     632           0 : const OGRSpatialReference *LANDataset::GetSpatialRef() const
     633             : 
     634             : {
     635           0 :     const auto poSRS = GDALPamDataset::GetSpatialRef();
     636           0 :     if (poSRS)
     637           0 :         return poSRS;
     638             : 
     639           0 :     return m_poSRS;
     640             : }
     641             : 
     642             : /************************************************************************/
     643             : /*                            GetFileList()                             */
     644             : /************************************************************************/
     645             : 
     646           2 : char **LANDataset::GetFileList()
     647             : 
     648             : {
     649             :     // Main data file, etc.
     650           2 :     char **papszFileList = GDALPamDataset::GetFileList();
     651             : 
     652           2 :     if (!osSTAFilename.empty())
     653           0 :         papszFileList = CSLAddString(papszFileList, osSTAFilename);
     654             : 
     655           2 :     return papszFileList;
     656             : }
     657             : 
     658             : /************************************************************************/
     659             : /*                         CheckForStatistics()                         */
     660             : /************************************************************************/
     661             : 
     662           4 : void LANDataset::CheckForStatistics()
     663             : 
     664             : {
     665             :     /* -------------------------------------------------------------------- */
     666             :     /*      Do we have a statistics file?                                   */
     667             :     /* -------------------------------------------------------------------- */
     668           4 :     osSTAFilename = CPLResetExtensionSafe(GetDescription(), "sta");
     669             : 
     670           4 :     VSILFILE *fpSTA = VSIFOpenL(osSTAFilename, "r");
     671             : 
     672           4 :     if (fpSTA == nullptr && VSIIsCaseSensitiveFS(osSTAFilename))
     673             :     {
     674           4 :         osSTAFilename = CPLResetExtensionSafe(GetDescription(), "STA");
     675           4 :         fpSTA = VSIFOpenL(osSTAFilename, "r");
     676             :     }
     677             : 
     678           4 :     if (fpSTA == nullptr)
     679             :     {
     680           4 :         osSTAFilename = "";
     681           4 :         return;
     682             :     }
     683             : 
     684             :     /* -------------------------------------------------------------------- */
     685             :     /*      Read it one band at a time.                                     */
     686             :     /* -------------------------------------------------------------------- */
     687           0 :     GByte abyBandInfo[1152] = {'\0'};
     688             : 
     689           0 :     for (int iBand = 0; iBand < nBands; iBand++)
     690             :     {
     691           0 :         if (VSIFReadL(abyBandInfo, 1152, 1, fpSTA) != 1)
     692           0 :             break;
     693             : 
     694           0 :         const int nBandNumber = abyBandInfo[7];
     695           0 :         GDALRasterBand *poBand = GetRasterBand(nBandNumber);
     696           0 :         if (poBand == nullptr)
     697           0 :             break;
     698             : 
     699           0 :         GInt16 nMin = 0;
     700           0 :         GInt16 nMax = 0;
     701             : 
     702           0 :         if (poBand->GetRasterDataType() != GDT_Byte)
     703             :         {
     704           0 :             memcpy(&nMin, abyBandInfo + 28, 2);
     705           0 :             memcpy(&nMax, abyBandInfo + 30, 2);
     706           0 :             CPL_LSBPTR16(&nMin);
     707           0 :             CPL_LSBPTR16(&nMax);
     708             :         }
     709             :         else
     710             :         {
     711           0 :             nMin = abyBandInfo[9];
     712           0 :             nMax = abyBandInfo[8];
     713             :         }
     714             : 
     715           0 :         float fMean = 0.0;
     716           0 :         float fStdDev = 0.0;
     717           0 :         memcpy(&fMean, abyBandInfo + 12, 4);
     718           0 :         memcpy(&fStdDev, abyBandInfo + 24, 4);
     719           0 :         CPL_LSBPTR32(&fMean);
     720           0 :         CPL_LSBPTR32(&fStdDev);
     721             : 
     722           0 :         poBand->SetStatistics(nMin, nMax, fMean, fStdDev);
     723             :     }
     724             : 
     725           0 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fpSTA));
     726             : }
     727             : 
     728             : /************************************************************************/
     729             : /*                          GDALRegister_LAN()                          */
     730             : /************************************************************************/
     731             : 
     732        1927 : void GDALRegister_LAN()
     733             : 
     734             : {
     735        1927 :     if (GDALGetDriverByName("LAN") != nullptr)
     736         282 :         return;
     737             : 
     738        1645 :     GDALDriver *poDriver = new GDALDriver();
     739             : 
     740        1645 :     poDriver->SetDescription("LAN");
     741        1645 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     742        1645 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Erdas .LAN/.GIS");
     743        1645 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/lan.html");
     744        1645 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     745             : 
     746        1645 :     poDriver->pfnOpen = LANDataset::Open;
     747             : 
     748        1645 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     749             : }

Generated by: LCOV version 1.14