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

Generated by: LCOV version 1.14