LCOV - code coverage report
Current view: top level - frmts/raw - dipxdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 91 121 75.2 %
Date: 2024-05-03 15:49:35 Functions: 5 7 71.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Implementation for ELAS DIPEx format variant.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2006, 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 "cpl_string.h"
      31             : #include "gdal_frmts.h"
      32             : #include "ogr_spatialref.h"
      33             : #include "rawdataset.h"
      34             : 
      35             : #include <cmath>
      36             : #include <algorithm>
      37             : 
      38             : using std::fill;
      39             : 
      40             : /************************************************************************/
      41             : /* ==================================================================== */
      42             : /*                              DIPExDataset                            */
      43             : /* ==================================================================== */
      44             : /************************************************************************/
      45             : 
      46             : class DIPExDataset final : public GDALPamDataset
      47             : {
      48             :     struct DIPExHeader
      49             :     {
      50             :         GInt32 NBIH = {0};  /* bytes in header, normally 1024 */
      51             :         GInt32 NBPR = {0};  /* bytes per data record (all bands of scanline) */
      52             :         GInt32 IL = {0};    /* initial line - normally 1 */
      53             :         GInt32 LL = {0};    /* last line */
      54             :         GInt32 IE = {0};    /* initial element (pixel), normally 1 */
      55             :         GInt32 LE = {0};    /* last element (pixel) */
      56             :         GInt32 NC = {0};    /* number of channels (bands) */
      57             :         GInt32 H4322 = {0}; /* header record identifier - always 4322. */
      58             :         char unused1[40] = {0};
      59             :         GByte IH19[4] = {0}; /* data type, and size flags */
      60             :         GInt32 IH20 = {0};   /* number of secondary headers */
      61             :         GInt32 SRID = {0};
      62             :         char unused2[12] = {0};
      63             :         double YOffset = {0};
      64             :         double XOffset = {0};
      65             :         double YPixSize = {0};
      66             :         double XPixSize = {0};
      67             :         double Matrix[4] = {0};
      68             :         char unused3[344] = {0};
      69             :         GUInt16 ColorTable[256] = {0}; /* RGB packed with 4 bits each */
      70             :         char unused4[32] = {0};
      71             :     };
      72             : 
      73             :     VSILFILE *fp;
      74             :     OGRSpatialReference m_oSRS{};
      75             : 
      76             :     DIPExHeader sHeader{};
      77             : 
      78             :     GDALDataType eRasterDataType;
      79             : 
      80             :     double adfGeoTransform[6];
      81             : 
      82             :     CPL_DISALLOW_COPY_ASSIGN(DIPExDataset)
      83             : 
      84             :   public:
      85             :     DIPExDataset();
      86             :     ~DIPExDataset() override;
      87             : 
      88             :     CPLErr GetGeoTransform(double *) override;
      89             : 
      90           0 :     const OGRSpatialReference *GetSpatialRef() const override
      91             :     {
      92           0 :         return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
      93             :     }
      94             : 
      95             :     static GDALDataset *Open(GDALOpenInfo *);
      96             : };
      97             : 
      98             : /************************************************************************/
      99             : /* ==================================================================== */
     100             : /*                             DIPExDataset                              */
     101             : /* ==================================================================== */
     102             : /************************************************************************/
     103             : 
     104             : /************************************************************************/
     105             : /*                            DIPExDataset()                             */
     106             : /************************************************************************/
     107             : 
     108           2 : DIPExDataset::DIPExDataset() : fp(nullptr), eRasterDataType(GDT_Unknown)
     109             : {
     110           2 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     111           2 :     adfGeoTransform[0] = 0.0;
     112           2 :     adfGeoTransform[1] = 1.0;
     113           2 :     adfGeoTransform[2] = 0.0;
     114           2 :     adfGeoTransform[3] = 0.0;
     115           2 :     adfGeoTransform[4] = 0.0;
     116           2 :     adfGeoTransform[5] = 1.0;
     117           2 : }
     118             : 
     119             : /************************************************************************/
     120             : /*                            ~DIPExDataset()                            */
     121             : /************************************************************************/
     122             : 
     123           4 : DIPExDataset::~DIPExDataset()
     124             : 
     125             : {
     126           2 :     if (fp)
     127           2 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     128           2 :     fp = nullptr;
     129           4 : }
     130             : 
     131             : /************************************************************************/
     132             : /*                                Open()                                */
     133             : /************************************************************************/
     134             : 
     135       29118 : GDALDataset *DIPExDataset::Open(GDALOpenInfo *poOpenInfo)
     136             : 
     137             : {
     138             :     /* -------------------------------------------------------------------- */
     139             :     /*      First we check to see if the file has the expected header       */
     140             :     /*      bytes.                                                          */
     141             :     /* -------------------------------------------------------------------- */
     142       29118 :     if (poOpenInfo->nHeaderBytes < 256 || poOpenInfo->fpL == nullptr)
     143       26470 :         return nullptr;
     144             : 
     145        2648 :     if (CPL_LSBWORD32(
     146             :             *(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader + 0))) != 1024)
     147        2646 :         return nullptr;
     148             : 
     149           2 :     if (CPL_LSBWORD32(
     150             :             *(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader + 28))) != 4322)
     151           0 :         return nullptr;
     152             : 
     153             :     /* -------------------------------------------------------------------- */
     154             :     /*      Create a corresponding GDALDataset.                             */
     155             :     /* -------------------------------------------------------------------- */
     156           4 :     auto poDS = std::make_unique<DIPExDataset>();
     157             : 
     158           2 :     poDS->eAccess = poOpenInfo->eAccess;
     159           2 :     poDS->fp = poOpenInfo->fpL;
     160           2 :     poOpenInfo->fpL = nullptr;
     161             : 
     162             :     /* -------------------------------------------------------------------- */
     163             :     /*      Read the header information.                                    */
     164             :     /* -------------------------------------------------------------------- */
     165           2 :     if (VSIFReadL(&(poDS->sHeader), 1024, 1, poDS->fp) != 1)
     166             :     {
     167           0 :         CPLError(CE_Failure, CPLE_FileIO,
     168             :                  "Attempt to read 1024 byte header filed on file %s\n",
     169             :                  poOpenInfo->pszFilename);
     170           0 :         return nullptr;
     171             :     }
     172             : 
     173             :     // To avoid cppcheck warnings about unused members
     174           2 :     CPL_IGNORE_RET_VAL(poDS->sHeader.NBIH);
     175           2 :     CPL_IGNORE_RET_VAL(poDS->sHeader.H4322);
     176           2 :     CPL_IGNORE_RET_VAL(poDS->sHeader.unused1);
     177           2 :     CPL_IGNORE_RET_VAL(poDS->sHeader.IH20);
     178           2 :     CPL_IGNORE_RET_VAL(poDS->sHeader.unused2);
     179           2 :     CPL_IGNORE_RET_VAL(poDS->sHeader.Matrix);
     180           2 :     CPL_IGNORE_RET_VAL(poDS->sHeader.unused3);
     181           2 :     CPL_IGNORE_RET_VAL(poDS->sHeader.ColorTable);
     182           2 :     CPL_IGNORE_RET_VAL(poDS->sHeader.unused4);
     183             : 
     184             :     /* -------------------------------------------------------------------- */
     185             :     /*      Extract information of interest from the header.                */
     186             :     /* -------------------------------------------------------------------- */
     187           2 :     const int nLineOffset = CPL_LSBWORD32(poDS->sHeader.NBPR);
     188             : 
     189           2 :     int nStart = CPL_LSBWORD32(poDS->sHeader.IL);
     190           2 :     int nEnd = CPL_LSBWORD32(poDS->sHeader.LL);
     191           2 :     GIntBig nDiff = static_cast<GIntBig>(nEnd) - nStart + 1;
     192           2 :     if (nDiff <= 0 || nDiff > INT_MAX)
     193             :     {
     194           0 :         return nullptr;
     195             :     }
     196           2 :     poDS->nRasterYSize = static_cast<int>(nDiff);
     197             : 
     198           2 :     nStart = CPL_LSBWORD32(poDS->sHeader.IE);
     199           2 :     nEnd = CPL_LSBWORD32(poDS->sHeader.LE);
     200           2 :     nDiff = static_cast<GIntBig>(nEnd) - nStart + 1;
     201           2 :     if (nDiff <= 0 || nDiff > INT_MAX)
     202             :     {
     203           0 :         return nullptr;
     204             :     }
     205           2 :     poDS->nRasterXSize = static_cast<int>(nDiff);
     206             : 
     207           2 :     const int nBands = CPL_LSBWORD32(poDS->sHeader.NC);
     208             : 
     209           4 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
     210           2 :         !GDALCheckBandCount(nBands, FALSE))
     211             :     {
     212           0 :         return nullptr;
     213             :     }
     214             : 
     215           2 :     const int nDIPExDataType = (poDS->sHeader.IH19[1] & 0x7e) >> 2;
     216           2 :     const int nBytesPerSample = poDS->sHeader.IH19[0];
     217             : 
     218           2 :     if (nDIPExDataType == 0 && nBytesPerSample == 1)
     219           2 :         poDS->eRasterDataType = GDT_Byte;
     220           0 :     else if (nDIPExDataType == 1 && nBytesPerSample == 1)
     221           0 :         poDS->eRasterDataType = GDT_Byte;
     222           0 :     else if (nDIPExDataType == 16 && nBytesPerSample == 4)
     223           0 :         poDS->eRasterDataType = GDT_Float32;
     224           0 :     else if (nDIPExDataType == 17 && nBytesPerSample == 8)
     225           0 :         poDS->eRasterDataType = GDT_Float64;
     226             :     else
     227             :     {
     228           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     229             :                  "Unrecognized image data type %d, with BytesPerSample=%d.",
     230             :                  nDIPExDataType, nBytesPerSample);
     231           0 :         return nullptr;
     232             :     }
     233             : 
     234           2 :     if (nLineOffset <= 0 || nLineOffset > INT_MAX / nBands)
     235             :     {
     236           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     237             :                  "Invalid values: nLineOffset = %d, nBands = %d.", nLineOffset,
     238             :                  nBands);
     239           0 :         return nullptr;
     240             :     }
     241             : 
     242             :     /* -------------------------------------------------------------------- */
     243             :     /*      Create band information objects.                                */
     244             :     /* -------------------------------------------------------------------- */
     245           2 :     CPLErrorReset();
     246           4 :     for (int iBand = 0; iBand < nBands; iBand++)
     247             :     {
     248             :         auto poBand = RawRasterBand::Create(
     249           4 :             poDS.get(), iBand + 1, poDS->fp, 1024 + iBand * nLineOffset,
     250           2 :             nBytesPerSample, nLineOffset * nBands, poDS->eRasterDataType,
     251             :             RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN,
     252           2 :             RawRasterBand::OwnFP::NO);
     253           2 :         if (!poBand)
     254           0 :             return nullptr;
     255           2 :         poDS->SetBand(iBand + 1, std::move(poBand));
     256             :     }
     257             : 
     258             :     /* -------------------------------------------------------------------- */
     259             :     /*      Extract the projection coordinates, if present.                 */
     260             :     /* -------------------------------------------------------------------- */
     261           2 :     CPL_LSBPTR64(&(poDS->sHeader.XPixSize));
     262           2 :     CPL_LSBPTR64(&(poDS->sHeader.YPixSize));
     263           2 :     CPL_LSBPTR64(&(poDS->sHeader.XOffset));
     264           2 :     CPL_LSBPTR64(&(poDS->sHeader.YOffset));
     265             : 
     266           2 :     if (poDS->sHeader.XOffset != 0)
     267             :     {
     268           0 :         poDS->adfGeoTransform[0] = poDS->sHeader.XOffset;
     269           0 :         poDS->adfGeoTransform[1] = poDS->sHeader.XPixSize;
     270           0 :         poDS->adfGeoTransform[2] = 0.0;
     271           0 :         poDS->adfGeoTransform[3] = poDS->sHeader.YOffset;
     272           0 :         poDS->adfGeoTransform[4] = 0.0;
     273           0 :         poDS->adfGeoTransform[5] = -1.0 * std::abs(poDS->sHeader.YPixSize);
     274             : 
     275           0 :         poDS->adfGeoTransform[0] -= poDS->adfGeoTransform[1] * 0.5;
     276           0 :         poDS->adfGeoTransform[3] -= poDS->adfGeoTransform[5] * 0.5;
     277             :     }
     278             :     else
     279             :     {
     280           2 :         poDS->adfGeoTransform[0] = 0.0;
     281           2 :         poDS->adfGeoTransform[1] = 1.0;
     282           2 :         poDS->adfGeoTransform[2] = 0.0;
     283           2 :         poDS->adfGeoTransform[3] = 0.0;
     284           2 :         poDS->adfGeoTransform[4] = 0.0;
     285           2 :         poDS->adfGeoTransform[5] = 1.0;
     286             :     }
     287             : 
     288             :     /* -------------------------------------------------------------------- */
     289             :     /*      Look for SRID.                                                  */
     290             :     /* -------------------------------------------------------------------- */
     291           2 :     CPL_LSBPTR32(&(poDS->sHeader.SRID));
     292             : 
     293           2 :     if (poDS->sHeader.SRID > 0 && poDS->sHeader.SRID < 33000)
     294             :     {
     295           4 :         OGRSpatialReference oSR;
     296           2 :         oSR.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     297           2 :         if (oSR.importFromEPSG(poDS->sHeader.SRID) == OGRERR_NONE)
     298             :         {
     299           2 :             poDS->m_oSRS = std::move(oSR);
     300             :         }
     301             :     }
     302             : 
     303             :     /* -------------------------------------------------------------------- */
     304             :     /*      Initialize any PAM information.                                 */
     305             :     /* -------------------------------------------------------------------- */
     306           2 :     poDS->SetDescription(poOpenInfo->pszFilename);
     307           2 :     poDS->TryLoadXML();
     308             : 
     309             :     /* -------------------------------------------------------------------- */
     310             :     /*      Check for external overviews.                                   */
     311             :     /* -------------------------------------------------------------------- */
     312           2 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename,
     313             :                                 poOpenInfo->GetSiblingFiles());
     314             : 
     315           2 :     return poDS.release();
     316             : }
     317             : 
     318             : /************************************************************************/
     319             : /*                          GetGeoTransform()                           */
     320             : /************************************************************************/
     321             : 
     322           0 : CPLErr DIPExDataset::GetGeoTransform(double *padfTransform)
     323             : 
     324             : {
     325           0 :     memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
     326             : 
     327           0 :     return CE_None;
     328             : }
     329             : 
     330             : /************************************************************************/
     331             : /*                          GDALRegister_DIPEx()                        */
     332             : /************************************************************************/
     333             : 
     334        1511 : void GDALRegister_DIPEx()
     335             : 
     336             : {
     337        1511 :     if (GDALGetDriverByName("DIPEx") != nullptr)
     338         295 :         return;
     339             : 
     340        1216 :     GDALDriver *poDriver = new GDALDriver();
     341             : 
     342        1216 :     poDriver->SetDescription("DIPEx");
     343        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     344        1216 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "DIPEx");
     345        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     346             : 
     347        1216 :     poDriver->pfnOpen = DIPExDataset::Open;
     348             : 
     349        1216 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     350             : }

Generated by: LCOV version 1.14