LCOV - code coverage report
Current view: top level - frmts/elas - elasdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 215 247 87.0 %
Date: 2024-11-21 22:18:42 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  ELAS Translator
       4             :  * Purpose:  Complete implementation of ELAS translator module for GDAL.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, 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 "gdal_frmts.h"
      15             : #include "gdal_pam.h"
      16             : 
      17             : #include <cmath>
      18             : #include <algorithm>
      19             : #include <limits>
      20             : 
      21             : using std::fill;
      22             : 
      23             : typedef struct ELASHeader
      24             : {
      25             :     ELASHeader();
      26             : 
      27             :     GInt32 NBIH;     /* bytes in header, normally 1024 */
      28             :     GInt32 NBPR;     /* bytes per data record (all bands of scanline) */
      29             :     GInt32 IL;       /* initial line - normally 1 */
      30             :     GInt32 LL;       /* last line */
      31             :     GInt32 IE;       /* initial element (pixel), normally 1 */
      32             :     GInt32 LE;       /* last element (pixel) */
      33             :     GInt32 NC;       /* number of channels (bands) */
      34             :     GUInt32 H4321;   /* header record identifier - always 4321. */
      35             :     char YLabel[4];  /* Should be "NOR" for UTM */
      36             :     GInt32 YOffset;  /* topleft pixel center northing */
      37             :     char XLabel[4];  /* Should be "EAS" for UTM */
      38             :     GInt32 XOffset;  /* topleft pixel center easting */
      39             :     float YPixSize;  /* height of pixel in georef units */
      40             :     float XPixSize;  /* width of pixel in georef units */
      41             :     float Matrix[4]; /* 2x2 transformation matrix.  Should be
      42             :                         1,0,0,1 for pixel/line, or
      43             :                         1,0,0,-1 for UTM */
      44             :     GByte IH19[4];   /* data type, and size flags */
      45             :     GInt32 IH20;     /* number of secondary headers */
      46             :     char unused1[8];
      47             :     GInt32 LABL; /* used by LABL module */
      48             :     char HEAD;   /* used by HEAD module */
      49             :     char Comment1[64];
      50             :     char Comment2[64];
      51             :     char Comment3[64];
      52             :     char Comment4[64];
      53             :     char Comment5[64];
      54             :     char Comment6[64];
      55             :     GUInt16 ColorTable[256]; /* RGB packed with 4 bits each */
      56             :     char unused2[32];
      57             : } _ELASHeader;
      58             : 
      59          48 : ELASHeader::ELASHeader()
      60             :     : NBIH(0), NBPR(0), IL(0), LL(0), IE(0), LE(0), NC(0), H4321(0), YOffset(0),
      61          48 :       XOffset(0), YPixSize(0.0), XPixSize(0.0), IH20(0), LABL(0), HEAD(0)
      62             : {
      63          48 :     fill(YLabel, YLabel + CPL_ARRAYSIZE(YLabel), static_cast<char>(0));
      64          48 :     fill(XLabel, XLabel + CPL_ARRAYSIZE(XLabel), static_cast<char>(0));
      65          48 :     fill(Matrix, Matrix + CPL_ARRAYSIZE(Matrix), 0.f);
      66          48 :     fill(IH19, IH19 + CPL_ARRAYSIZE(IH19), static_cast<GByte>(0));
      67          48 :     fill(unused1, unused1 + CPL_ARRAYSIZE(unused1), static_cast<char>(0));
      68          48 :     fill(Comment1, Comment1 + CPL_ARRAYSIZE(Comment1), static_cast<char>(0));
      69          48 :     fill(Comment2, Comment2 + CPL_ARRAYSIZE(Comment2), static_cast<char>(0));
      70          48 :     fill(Comment3, Comment3 + CPL_ARRAYSIZE(Comment3), static_cast<char>(0));
      71          48 :     fill(Comment4, Comment4 + CPL_ARRAYSIZE(Comment4), static_cast<char>(0));
      72          48 :     fill(Comment5, Comment5 + CPL_ARRAYSIZE(Comment5), static_cast<char>(0));
      73          48 :     fill(Comment6, Comment6 + CPL_ARRAYSIZE(Comment6), static_cast<char>(0));
      74          48 :     fill(ColorTable, ColorTable + CPL_ARRAYSIZE(ColorTable),
      75          48 :          static_cast<GUInt16>(0));
      76          48 :     fill(unused2, unused2 + CPL_ARRAYSIZE(unused2), static_cast<char>(0));
      77          48 : }
      78             : 
      79             : /************************************************************************/
      80             : /* ==================================================================== */
      81             : /*                              ELASDataset                             */
      82             : /* ==================================================================== */
      83             : /************************************************************************/
      84             : 
      85             : class ELASRasterBand;
      86             : 
      87             : class ELASDataset final : public GDALPamDataset
      88             : {
      89             :     friend class ELASRasterBand;
      90             : 
      91             :     VSILFILE *fp;
      92             : 
      93             :     ELASHeader sHeader;
      94             :     int bHeaderModified;
      95             : 
      96             :     GDALDataType eRasterDataType;
      97             : 
      98             :     int nLineOffset;
      99             :     int nBandOffset;  // Within a line.
     100             : 
     101             :     double adfGeoTransform[6];
     102             : 
     103             :   public:
     104             :     ELASDataset();
     105             :     ~ELASDataset() override;
     106             : 
     107             :     CPLErr GetGeoTransform(double *) override;
     108             :     CPLErr SetGeoTransform(double *) override;
     109             : 
     110             :     static GDALDataset *Open(GDALOpenInfo *);
     111             :     static int Identify(GDALOpenInfo *);
     112             :     static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
     113             :                                int nBandsIn, GDALDataType eType,
     114             :                                char **papszParamList);
     115             : 
     116             :     CPLErr FlushCache(bool bAtClosing) override;
     117             : };
     118             : 
     119             : /************************************************************************/
     120             : /* ==================================================================== */
     121             : /*                            ELASRasterBand                             */
     122             : /* ==================================================================== */
     123             : /************************************************************************/
     124             : 
     125             : class ELASRasterBand final : public GDALPamRasterBand
     126             : {
     127             :     friend class ELASDataset;
     128             : 
     129             :   public:
     130             :     ELASRasterBand(ELASDataset *, int);
     131             : 
     132             :     // should override RasterIO eventually.
     133             : 
     134             :     CPLErr IReadBlock(int, int, void *) override;
     135             :     CPLErr IWriteBlock(int, int, void *) override;
     136             : };
     137             : 
     138             : /************************************************************************/
     139             : /*                           ELASRasterBand()                            */
     140             : /************************************************************************/
     141             : 
     142          69 : ELASRasterBand::ELASRasterBand(ELASDataset *poDSIn, int nBandIn)
     143             : 
     144             : {
     145          69 :     poDS = poDSIn;
     146          69 :     nBand = nBandIn;
     147             : 
     148          69 :     eAccess = poDSIn->eAccess;
     149             : 
     150          69 :     eDataType = poDSIn->eRasterDataType;
     151             : 
     152          69 :     nBlockXSize = poDS->GetRasterXSize();
     153          69 :     nBlockYSize = 1;
     154          69 : }
     155             : 
     156             : /************************************************************************/
     157             : /*                             IReadBlock()                             */
     158             : /************************************************************************/
     159             : 
     160          60 : CPLErr ELASRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     161             :                                   void *pImage)
     162             : {
     163          60 :     CPLAssert(nBlockXOff == 0);
     164             : 
     165          60 :     ELASDataset *poGDS = (ELASDataset *)poDS;
     166             : 
     167             :     int nDataSize =
     168          60 :         GDALGetDataTypeSizeBytes(eDataType) * poGDS->GetRasterXSize();
     169          60 :     long nOffset =
     170          60 :         poGDS->nLineOffset * nBlockYOff + 1024 + (nBand - 1) * nDataSize;
     171             : 
     172             :     /* -------------------------------------------------------------------- */
     173             :     /*      If we can't seek to the data, we will assume this is a newly    */
     174             :     /*      created file, and that the file hasn't been extended yet.       */
     175             :     /*      Just read as zeros.                                             */
     176             :     /* -------------------------------------------------------------------- */
     177         120 :     if (VSIFSeekL(poGDS->fp, nOffset, SEEK_SET) != 0 ||
     178          60 :         VSIFReadL(pImage, 1, nDataSize, poGDS->fp) != (size_t)nDataSize)
     179             :     {
     180           0 :         CPLError(CE_Failure, CPLE_FileIO,
     181             :                  "Seek or read of %d bytes at %ld failed.\n", nDataSize,
     182             :                  nOffset);
     183           0 :         return CE_Failure;
     184             :     }
     185             : 
     186          60 :     return CE_None;
     187             : }
     188             : 
     189             : /************************************************************************/
     190             : /*                            IWriteBlock()                             */
     191             : /************************************************************************/
     192             : 
     193         190 : CPLErr ELASRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     194             :                                    void *pImage)
     195             : {
     196         190 :     CPLAssert(nBlockXOff == 0);
     197         190 :     CPLAssert(eAccess == GA_Update);
     198             : 
     199         190 :     ELASDataset *poGDS = (ELASDataset *)poDS;
     200             : 
     201             :     int nDataSize =
     202         190 :         GDALGetDataTypeSizeBytes(eDataType) * poGDS->GetRasterXSize();
     203         190 :     long nOffset =
     204         190 :         poGDS->nLineOffset * nBlockYOff + 1024 + (nBand - 1) * nDataSize;
     205             : 
     206         380 :     if (VSIFSeekL(poGDS->fp, nOffset, SEEK_SET) != 0 ||
     207         190 :         VSIFWriteL(pImage, 1, nDataSize, poGDS->fp) != (size_t)nDataSize)
     208             :     {
     209           0 :         CPLError(CE_Failure, CPLE_FileIO,
     210             :                  "Seek or write of %d bytes at %ld failed.\n", nDataSize,
     211             :                  nOffset);
     212           0 :         return CE_Failure;
     213             :     }
     214             : 
     215         190 :     return CE_None;
     216             : }
     217             : 
     218             : /************************************************************************/
     219             : /* ==================================================================== */
     220             : /*      ELASDataset                                                     */
     221             : /* ==================================================================== */
     222             : /************************************************************************/
     223             : 
     224             : /************************************************************************/
     225             : /*                            ELASDataset()                             */
     226             : /************************************************************************/
     227             : 
     228          31 : ELASDataset::ELASDataset()
     229             :     : fp(nullptr), bHeaderModified(0), eRasterDataType(GDT_Unknown),
     230          31 :       nLineOffset(0), nBandOffset(0)
     231             : {
     232          31 :     adfGeoTransform[0] = 0.0;
     233          31 :     adfGeoTransform[1] = 1.0;
     234          31 :     adfGeoTransform[2] = 0.0;
     235          31 :     adfGeoTransform[3] = 0.0;
     236          31 :     adfGeoTransform[4] = 0.0;
     237          31 :     adfGeoTransform[5] = 1.0;
     238          31 : }
     239             : 
     240             : /************************************************************************/
     241             : /*                            ~ELASDataset()                            */
     242             : /************************************************************************/
     243             : 
     244          62 : ELASDataset::~ELASDataset()
     245             : 
     246             : {
     247          31 :     ELASDataset::FlushCache(true);
     248             : 
     249          31 :     if (fp != nullptr)
     250             :     {
     251          31 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     252             :     }
     253          62 : }
     254             : 
     255             : /************************************************************************/
     256             : /*                             FlushCache()                             */
     257             : /*                                                                      */
     258             : /*      We also write out the header, if it is modified.                */
     259             : /************************************************************************/
     260             : 
     261          32 : CPLErr ELASDataset::FlushCache(bool bAtClosing)
     262             : 
     263             : {
     264          32 :     CPLErr eErr = GDALDataset::FlushCache(bAtClosing);
     265             : 
     266          32 :     if (bHeaderModified)
     267             :     {
     268          32 :         if (VSIFSeekL(fp, 0, SEEK_SET) != 0 ||
     269          16 :             VSIFWriteL(&sHeader, 1024, 1, fp) != 1)
     270             :         {
     271           0 :             eErr = CE_Failure;
     272             :         }
     273          16 :         bHeaderModified = FALSE;
     274             :     }
     275          32 :     return eErr;
     276             : }
     277             : 
     278             : /************************************************************************/
     279             : /*                              Identify()                               */
     280             : /************************************************************************/
     281             : 
     282       57089 : int ELASDataset::Identify(GDALOpenInfo *poOpenInfo)
     283             : 
     284             : {
     285             :     /* -------------------------------------------------------------------- */
     286             :     /*  First we check to see if the file has the expected header           */
     287             :     /*  bytes.                                                               */
     288             :     /* -------------------------------------------------------------------- */
     289       57089 :     if (poOpenInfo->nHeaderBytes < 256)
     290       50607 :         return FALSE;
     291             : 
     292        6482 :     if (CPL_MSBWORD32(*((GInt32 *)(poOpenInfo->pabyHeader + 0))) != 1024 ||
     293          62 :         CPL_MSBWORD32(*((GInt32 *)(poOpenInfo->pabyHeader + 28))) != 4321)
     294             :     {
     295        6420 :         return FALSE;
     296             :     }
     297             : 
     298          62 :     return TRUE;
     299             : }
     300             : 
     301             : /************************************************************************/
     302             : /*                                Open()                                */
     303             : /************************************************************************/
     304             : 
     305          31 : GDALDataset *ELASDataset::Open(GDALOpenInfo *poOpenInfo)
     306             : 
     307             : {
     308          31 :     if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
     309           0 :         return nullptr;
     310             : 
     311             :     /* -------------------------------------------------------------------- */
     312             :     /*      Create a corresponding GDALDataset.                             */
     313             :     /* -------------------------------------------------------------------- */
     314             : 
     315          31 :     ELASDataset *poDS = new ELASDataset();
     316          31 :     poDS->eAccess = poOpenInfo->eAccess;
     317          31 :     poDS->fp = poOpenInfo->fpL;
     318          31 :     poOpenInfo->fpL = nullptr;
     319             : 
     320             :     /* -------------------------------------------------------------------- */
     321             :     /*      Read the header information.                                    */
     322             :     /* -------------------------------------------------------------------- */
     323          31 :     poDS->bHeaderModified = FALSE;
     324          31 :     if (VSIFReadL(&(poDS->sHeader), 1024, 1, poDS->fp) != 1)
     325             :     {
     326           0 :         CPLError(CE_Failure, CPLE_FileIO,
     327             :                  "Attempt to read 1024 byte header filed on file %s\n",
     328             :                  poOpenInfo->pszFilename);
     329           0 :         delete poDS;
     330           0 :         return nullptr;
     331             :     }
     332             : 
     333             :     /* -------------------------------------------------------------------- */
     334             :     /*      Extract information of interest from the header.                */
     335             :     /* -------------------------------------------------------------------- */
     336          31 :     poDS->nLineOffset = CPL_MSBWORD32(poDS->sHeader.NBPR);
     337             : 
     338          31 :     int nStart = CPL_MSBWORD32(poDS->sHeader.IL);
     339          31 :     int nEnd = CPL_MSBWORD32(poDS->sHeader.LL);
     340          31 :     GIntBig nDiff = static_cast<GIntBig>(nEnd) - nStart + 1;
     341             : 
     342          31 :     if (nDiff <= 0 || nDiff > std::numeric_limits<int>::max())
     343             :     {
     344           0 :         delete poDS;
     345           0 :         return nullptr;
     346             :     }
     347          31 :     poDS->nRasterYSize = static_cast<int>(nDiff);
     348             : 
     349          31 :     nStart = CPL_MSBWORD32(poDS->sHeader.IE);
     350          31 :     nEnd = CPL_MSBWORD32(poDS->sHeader.LE);
     351          31 :     nDiff = static_cast<GIntBig>(nEnd) - nStart + 1;
     352          31 :     if (nDiff <= 0 || nDiff > std::numeric_limits<int>::max())
     353             :     {
     354           0 :         delete poDS;
     355           0 :         return nullptr;
     356             :     }
     357          31 :     poDS->nRasterXSize = static_cast<int>(nDiff);
     358             : 
     359          31 :     poDS->nBands = CPL_MSBWORD32(poDS->sHeader.NC);
     360             : 
     361          62 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
     362          31 :         !GDALCheckBandCount(poDS->nBands, FALSE))
     363             :     {
     364           0 :         delete poDS;
     365           0 :         return nullptr;
     366             :     }
     367             : 
     368          31 :     const int nELASDataType = (poDS->sHeader.IH19[2] & 0x7e) >> 2;
     369          31 :     const int nBytesPerSample = poDS->sHeader.IH19[3];
     370             : 
     371          31 :     if (nELASDataType == 0 && nBytesPerSample == 1)
     372           0 :         poDS->eRasterDataType = GDT_Byte;
     373          31 :     else if (nELASDataType == 1 && nBytesPerSample == 1)
     374          21 :         poDS->eRasterDataType = GDT_Byte;
     375          10 :     else if (nELASDataType == 16 && nBytesPerSample == 4)
     376           5 :         poDS->eRasterDataType = GDT_Float32;
     377           5 :     else if (nELASDataType == 17 && nBytesPerSample == 8)
     378           5 :         poDS->eRasterDataType = GDT_Float64;
     379             :     else
     380             :     {
     381           0 :         delete poDS;
     382           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     383             :                  "Unrecognized image data type %d, with BytesPerSample=%d.\n",
     384             :                  nELASDataType, nBytesPerSample);
     385           0 :         return nullptr;
     386             :     }
     387             : 
     388             :     /* -------------------------------------------------------------------- */
     389             :     /*      Band offsets are always multiples of 256 within a multi-band    */
     390             :     /*      scanline of data.                                               */
     391             :     /* -------------------------------------------------------------------- */
     392          31 :     if (GDALGetDataTypeSizeBytes(poDS->eRasterDataType) >
     393          31 :         (std::numeric_limits<int>::max() - 256) / poDS->nRasterXSize)
     394             :     {
     395           0 :         delete poDS;
     396           0 :         return nullptr;
     397             :     }
     398          31 :     poDS->nBandOffset =
     399          31 :         (poDS->nRasterXSize * GDALGetDataTypeSizeBytes(poDS->eRasterDataType));
     400             : 
     401          31 :     if (poDS->nBandOffset > 1000000)
     402             :     {
     403           0 :         VSIFSeekL(poDS->fp, 0, SEEK_END);
     404           0 :         if (VSIFTellL(poDS->fp) < static_cast<vsi_l_offset>(poDS->nBandOffset))
     405             :         {
     406           0 :             CPLError(CE_Failure, CPLE_FileIO, "File too short");
     407           0 :             delete poDS;
     408           0 :             return nullptr;
     409             :         }
     410             :     }
     411             : 
     412          31 :     if (poDS->nBandOffset % 256 != 0)
     413             :     {
     414          31 :         poDS->nBandOffset = poDS->nBandOffset - (poDS->nBandOffset % 256) + 256;
     415             :     }
     416             : 
     417             :     /* -------------------------------------------------------------------- */
     418             :     /*      Create band information objects.                                */
     419             :     /* -------------------------------------------------------------------- */
     420             :     /* coverity[tainted_data] */
     421         100 :     for (int iBand = 0; iBand < poDS->nBands; iBand++)
     422             :     {
     423          69 :         poDS->SetBand(iBand + 1, new ELASRasterBand(poDS, iBand + 1));
     424             :     }
     425             : 
     426             :     /* -------------------------------------------------------------------- */
     427             :     /*      Extract the projection coordinates, if present.                 */
     428             :     /* -------------------------------------------------------------------- */
     429          31 :     if (poDS->sHeader.XOffset != 0)
     430             :     {
     431          12 :         CPL_MSBPTR32(&(poDS->sHeader.XPixSize));
     432          12 :         CPL_MSBPTR32(&(poDS->sHeader.YPixSize));
     433             : 
     434          12 :         poDS->adfGeoTransform[0] = (GInt32)CPL_MSBWORD32(poDS->sHeader.XOffset);
     435          12 :         poDS->adfGeoTransform[1] = poDS->sHeader.XPixSize;
     436          12 :         poDS->adfGeoTransform[2] = 0.0;
     437          12 :         poDS->adfGeoTransform[3] = (GInt32)CPL_MSBWORD32(poDS->sHeader.YOffset);
     438          12 :         poDS->adfGeoTransform[4] = 0.0;
     439          12 :         poDS->adfGeoTransform[5] = -1.0 * std::abs(poDS->sHeader.YPixSize);
     440             : 
     441          12 :         CPL_MSBPTR32(&(poDS->sHeader.XPixSize));
     442          12 :         CPL_MSBPTR32(&(poDS->sHeader.YPixSize));
     443             : 
     444          12 :         poDS->adfGeoTransform[0] -= poDS->adfGeoTransform[1] * 0.5;
     445          12 :         poDS->adfGeoTransform[3] -= poDS->adfGeoTransform[5] * 0.5;
     446             :     }
     447             :     else
     448             :     {
     449          19 :         poDS->adfGeoTransform[0] = 0.0;
     450          19 :         poDS->adfGeoTransform[1] = 1.0;
     451          19 :         poDS->adfGeoTransform[2] = 0.0;
     452          19 :         poDS->adfGeoTransform[3] = 0.0;
     453          19 :         poDS->adfGeoTransform[4] = 0.0;
     454          19 :         poDS->adfGeoTransform[5] = 1.0;
     455             :     }
     456             : 
     457             :     /* -------------------------------------------------------------------- */
     458             :     /*      Initialize any PAM information.                                 */
     459             :     /* -------------------------------------------------------------------- */
     460          31 :     poDS->SetDescription(poOpenInfo->pszFilename);
     461          31 :     poDS->TryLoadXML();
     462             : 
     463             :     /* -------------------------------------------------------------------- */
     464             :     /*      Check for external overviews.                                   */
     465             :     /* -------------------------------------------------------------------- */
     466          62 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
     467          31 :                                 poOpenInfo->GetSiblingFiles());
     468             : 
     469          31 :     return poDS;
     470             : }
     471             : 
     472             : /************************************************************************/
     473             : /*                               Create()                               */
     474             : /*                                                                      */
     475             : /*      Create a new GeoTIFF or TIFF file.                              */
     476             : /************************************************************************/
     477             : 
     478          61 : GDALDataset *ELASDataset::Create(const char *pszFilename, int nXSize,
     479             :                                  int nYSize, int nBandsIn, GDALDataType eType,
     480             :                                  char ** /* notdef: papszParamList */)
     481             : 
     482             : {
     483             :     /* -------------------------------------------------------------------- */
     484             :     /*      Verify input options.                                           */
     485             :     /* -------------------------------------------------------------------- */
     486          61 :     if (nBandsIn <= 0)
     487             :     {
     488           1 :         CPLError(CE_Failure, CPLE_NotSupported,
     489             :                  "ELAS driver does not support %d bands.\n", nBandsIn);
     490           1 :         return nullptr;
     491             :     }
     492             : 
     493          60 :     if (eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_Float64)
     494             :     {
     495          30 :         CPLError(CE_Failure, CPLE_AppDefined,
     496             :                  "Attempt to create an ELAS dataset with an illegal\n"
     497             :                  "data type (%d).\n",
     498             :                  eType);
     499             : 
     500          30 :         return nullptr;
     501             :     }
     502             : 
     503             :     /* -------------------------------------------------------------------- */
     504             :     /*      Try to create the file.                                         */
     505             :     /* -------------------------------------------------------------------- */
     506          30 :     FILE *fp = VSIFOpen(pszFilename, "w");
     507             : 
     508          30 :     if (fp == nullptr)
     509             :     {
     510          13 :         CPLError(CE_Failure, CPLE_OpenFailed,
     511             :                  "Attempt to create file `%s' failed.\n", pszFilename);
     512          13 :         return nullptr;
     513             :     }
     514             : 
     515             :     /* -------------------------------------------------------------------- */
     516             :     /*      How long will each band of a scanline be?                       */
     517             :     /* -------------------------------------------------------------------- */
     518          17 :     int nBandOffset = nXSize * GDALGetDataTypeSizeBytes(eType);
     519             : 
     520          17 :     if (nBandOffset % 256 != 0)
     521             :     {
     522          17 :         nBandOffset = nBandOffset - (nBandOffset % 256) + 256;
     523             :     }
     524             : 
     525             :     /* -------------------------------------------------------------------- */
     526             :     /*      Setup header data block.                                        */
     527             :     /*                                                                      */
     528             :     /*      Note that CPL_MSBWORD32() will swap little endian words to      */
     529             :     /*      big endian on little endian platforms.                          */
     530             :     /* -------------------------------------------------------------------- */
     531          17 :     ELASHeader sHeader;
     532             : 
     533          17 :     sHeader.NBIH = CPL_MSBWORD32(1024);
     534             : 
     535          17 :     sHeader.NBPR = CPL_MSBWORD32(nBandsIn * nBandOffset);
     536             : 
     537          17 :     sHeader.IL = CPL_MSBWORD32(1);
     538          17 :     sHeader.LL = CPL_MSBWORD32(nYSize);
     539             : 
     540          17 :     sHeader.IE = CPL_MSBWORD32(1);
     541          17 :     sHeader.LE = CPL_MSBWORD32(nXSize);
     542             : 
     543          17 :     sHeader.NC = CPL_MSBWORD32(nBandsIn);
     544             : 
     545          17 :     sHeader.H4321 = CPL_MSBWORD32(4321);
     546             : 
     547          17 :     sHeader.IH19[0] = 0x04;
     548          17 :     sHeader.IH19[1] = 0xd2;
     549          17 :     sHeader.IH19[3] = (GByte)(GDALGetDataTypeSizeBytes(eType));
     550             : 
     551          17 :     if (eType == GDT_Byte)
     552          11 :         sHeader.IH19[2] = 1 << 2;
     553           6 :     else if (eType == GDT_Float32)
     554           3 :         sHeader.IH19[2] = 16 << 2;
     555           3 :     else if (eType == GDT_Float64)
     556           3 :         sHeader.IH19[2] = 17 << 2;
     557             : 
     558             :     /* -------------------------------------------------------------------- */
     559             :     /*      Write the header data.                                          */
     560             :     /* -------------------------------------------------------------------- */
     561          17 :     CPL_IGNORE_RET_VAL(VSIFWrite(&sHeader, 1024, 1, fp));
     562             : 
     563             :     /* -------------------------------------------------------------------- */
     564             :     /*      Now write out zero data for all the imagery.  This is           */
     565             :     /*      inefficient, but simplifies IReadBlock() / IWriteBlock() logic. */
     566             :     /* -------------------------------------------------------------------- */
     567          17 :     GByte *pabyLine = (GByte *)CPLCalloc(nBandOffset, nBandsIn);
     568        1007 :     for (int iLine = 0; iLine < nYSize; iLine++)
     569             :     {
     570         990 :         if (VSIFWrite(pabyLine, 1, nBandOffset, fp) != (size_t)nBandOffset)
     571             :         {
     572           0 :             CPLError(CE_Failure, CPLE_FileIO,
     573             :                      "Error writing ELAS image data ... likely insufficient"
     574             :                      " disk space.\n");
     575           0 :             VSIFClose(fp);
     576           0 :             CPLFree(pabyLine);
     577           0 :             return nullptr;
     578             :         }
     579             :     }
     580             : 
     581          17 :     CPLFree(pabyLine);
     582             : 
     583          17 :     VSIFClose(fp);
     584             : 
     585             :     /* -------------------------------------------------------------------- */
     586             :     /*      Try to return a regular handle on the file.                     */
     587             :     /* -------------------------------------------------------------------- */
     588          17 :     return (GDALDataset *)GDALOpen(pszFilename, GA_Update);
     589             : }
     590             : 
     591             : /************************************************************************/
     592             : /*                          GetGeoTransform()                           */
     593             : /************************************************************************/
     594             : 
     595           9 : CPLErr ELASDataset::GetGeoTransform(double *padfTransform)
     596             : 
     597             : {
     598           9 :     memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
     599             : 
     600           9 :     return CE_None;
     601             : }
     602             : 
     603             : /************************************************************************/
     604             : /*                          SetGeoTransform()                           */
     605             : /************************************************************************/
     606             : 
     607          16 : CPLErr ELASDataset::SetGeoTransform(double *padfTransform)
     608             : 
     609             : {
     610             :     /* -------------------------------------------------------------------- */
     611             :     /*      I don't think it supports rotation, but perhaps it is possible  */
     612             :     /*      for us to use the 2x2 transform matrix to accomplish some       */
     613             :     /*      sort of rotation.                                               */
     614             :     /* -------------------------------------------------------------------- */
     615          16 :     if (padfTransform[2] != 0.0 || padfTransform[4] != 0.0)
     616             :     {
     617           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     618             :                  "Attempt to set rotated geotransform on ELAS file.\n"
     619             :                  "ELAS does not support rotation.\n");
     620             : 
     621           0 :         return CE_Failure;
     622             :     }
     623             : 
     624             :     /* -------------------------------------------------------------------- */
     625             :     /*      Remember the new transform, and update the header.              */
     626             :     /* -------------------------------------------------------------------- */
     627          16 :     memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6);
     628             : 
     629          16 :     bHeaderModified = TRUE;
     630             : 
     631          16 :     const int nXOff = (int)(adfGeoTransform[0] + adfGeoTransform[1] * 0.5);
     632          16 :     const int nYOff = (int)(adfGeoTransform[3] + adfGeoTransform[5] * 0.5);
     633             : 
     634          16 :     sHeader.XOffset = CPL_MSBWORD32(nXOff);
     635          16 :     sHeader.YOffset = CPL_MSBWORD32(nYOff);
     636             : 
     637          16 :     sHeader.XPixSize = static_cast<float>(std::abs(adfGeoTransform[1]));
     638          16 :     sHeader.YPixSize = static_cast<float>(std::abs(adfGeoTransform[5]));
     639             : 
     640          16 :     CPL_MSBPTR32(&(sHeader.XPixSize));
     641          16 :     CPL_MSBPTR32(&(sHeader.YPixSize));
     642             : 
     643          16 :     memcpy(sHeader.YLabel, "NOR ", 4);
     644          16 :     memcpy(sHeader.XLabel, "EAS ", 4);
     645             : 
     646          16 :     sHeader.Matrix[0] = 1.0;
     647          16 :     sHeader.Matrix[1] = 0.0;
     648          16 :     sHeader.Matrix[2] = 0.0;
     649          16 :     sHeader.Matrix[3] = -1.0;
     650             : 
     651          16 :     CPL_MSBPTR32(&(sHeader.Matrix[0]));
     652          16 :     CPL_MSBPTR32(&(sHeader.Matrix[1]));
     653          16 :     CPL_MSBPTR32(&(sHeader.Matrix[2]));
     654          16 :     CPL_MSBPTR32(&(sHeader.Matrix[3]));
     655             : 
     656          16 :     return CE_None;
     657             : }
     658             : 
     659             : /************************************************************************/
     660             : /*                          GDALRegister_ELAS()                         */
     661             : /************************************************************************/
     662             : 
     663        1595 : void GDALRegister_ELAS()
     664             : 
     665             : {
     666        1595 :     if (GDALGetDriverByName("ELAS") != nullptr)
     667         302 :         return;
     668             : 
     669        1293 :     GDALDriver *poDriver = new GDALDriver();
     670             : 
     671        1293 :     poDriver->SetDescription("ELAS");
     672        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     673        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ELAS");
     674        1293 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
     675        1293 :                               "Byte Float32 Float64");
     676             : 
     677        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     678             : 
     679        1293 :     poDriver->pfnOpen = ELASDataset::Open;
     680        1293 :     poDriver->pfnIdentify = ELASDataset::Identify;
     681        1293 :     poDriver->pfnCreate = ELASDataset::Create;
     682             : 
     683        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     684             : }

Generated by: LCOV version 1.14