LCOV - code coverage report
Current view: top level - frmts/gxf - gxfdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 91 134 67.9 %
Date: 2024-05-02 21:22:03 Functions: 8 10 80.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GXF Reader
       4             :  * Purpose:  GDAL binding for GXF reader.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1998, Frank Warmerdam
       9             :  * Copyright (c) 2008-2012, 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             : #include "gxfopen.h"
      33             : 
      34             : /************************************************************************/
      35             : /* ==================================================================== */
      36             : /*                              GXFDataset                              */
      37             : /* ==================================================================== */
      38             : /************************************************************************/
      39             : 
      40             : class GXFRasterBand;
      41             : 
      42             : class GXFDataset final : public GDALPamDataset
      43             : {
      44             :     friend class GXFRasterBand;
      45             : 
      46             :     GXFHandle hGXF;
      47             : 
      48             :     OGRSpatialReference m_oSRS{};
      49             :     double dfNoDataValue;
      50             :     GDALDataType eDataType;
      51             : 
      52             :   public:
      53             :     GXFDataset();
      54             :     ~GXFDataset();
      55             : 
      56             :     static GDALDataset *Open(GDALOpenInfo *);
      57             : 
      58             :     CPLErr GetGeoTransform(double *padfTransform) override;
      59             :     const OGRSpatialReference *GetSpatialRef() const override;
      60             : };
      61             : 
      62             : /************************************************************************/
      63             : /* ==================================================================== */
      64             : /*                            GXFRasterBand                             */
      65             : /* ==================================================================== */
      66             : /************************************************************************/
      67             : 
      68             : class GXFRasterBand final : public GDALPamRasterBand
      69             : {
      70             :     friend class GXFDataset;
      71             : 
      72             :   public:
      73             :     GXFRasterBand(GXFDataset *, int);
      74             :     double GetNoDataValue(int *bGotNoDataValue) override;
      75             : 
      76             :     virtual CPLErr IReadBlock(int, int, void *) override;
      77             : };
      78             : 
      79             : /************************************************************************/
      80             : /*                           GXFRasterBand()                            */
      81             : /************************************************************************/
      82             : 
      83           4 : GXFRasterBand::GXFRasterBand(GXFDataset *poDSIn, int nBandIn)
      84             : 
      85             : {
      86           4 :     poDS = poDSIn;
      87           4 :     nBand = nBandIn;
      88             : 
      89           4 :     eDataType = poDSIn->eDataType;
      90             : 
      91           4 :     nBlockXSize = poDS->GetRasterXSize();
      92           4 :     nBlockYSize = 1;
      93           4 : }
      94             : 
      95             : /************************************************************************/
      96             : /*                          GetNoDataValue()                          */
      97             : /************************************************************************/
      98             : 
      99           0 : double GXFRasterBand::GetNoDataValue(int *bGotNoDataValue)
     100             : 
     101             : {
     102           0 :     GXFDataset *poGXF_DS = (GXFDataset *)poDS;
     103           0 :     if (bGotNoDataValue)
     104           0 :         *bGotNoDataValue = (fabs(poGXF_DS->dfNoDataValue - -1e12) > .1);
     105           0 :     if (eDataType == GDT_Float32)
     106           0 :         return (double)(float)poGXF_DS->dfNoDataValue;
     107             : 
     108           0 :     return poGXF_DS->dfNoDataValue;
     109             : }
     110             : 
     111             : /************************************************************************/
     112             : /*                             IReadBlock()                             */
     113             : /************************************************************************/
     114             : 
     115          11 : CPLErr GXFRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     116             :                                  void *pImage)
     117             : {
     118          11 :     GXFDataset *const poGXF_DS = (GXFDataset *)poDS;
     119             : 
     120          11 :     if (eDataType == GDT_Float32)
     121             :     {
     122          11 :         double *padfBuffer = (double *)VSIMalloc2(sizeof(double), nBlockXSize);
     123          11 :         if (padfBuffer == nullptr)
     124           0 :             return CE_Failure;
     125             :         const CPLErr eErr =
     126          11 :             GXFGetScanline(poGXF_DS->hGXF, nBlockYOff, padfBuffer);
     127             : 
     128          11 :         float *pafBuffer = (float *)pImage;
     129         103 :         for (int i = 0; i < nBlockXSize; i++)
     130          92 :             pafBuffer[i] = (float)padfBuffer[i];
     131             : 
     132          11 :         CPLFree(padfBuffer);
     133             : 
     134          11 :         return eErr;
     135             :     }
     136             : 
     137             :     const CPLErr eErr =
     138           0 :         eDataType == GDT_Float64
     139           0 :             ? GXFGetScanline(poGXF_DS->hGXF, nBlockYOff, (double *)pImage)
     140           0 :             : CE_Failure;
     141             : 
     142           0 :     return eErr;
     143             : }
     144             : 
     145             : /************************************************************************/
     146             : /* ==================================================================== */
     147             : /*                              GXFDataset                              */
     148             : /* ==================================================================== */
     149             : /************************************************************************/
     150             : 
     151             : /************************************************************************/
     152             : /*                             GXFDataset()                             */
     153             : /************************************************************************/
     154             : 
     155           4 : GXFDataset::GXFDataset()
     156           4 :     : hGXF(nullptr), dfNoDataValue(0), eDataType(GDT_Float32)
     157             : {
     158           4 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     159           4 : }
     160             : 
     161             : /************************************************************************/
     162             : /*                            ~GXFDataset()                             */
     163             : /************************************************************************/
     164             : 
     165           8 : GXFDataset::~GXFDataset()
     166             : 
     167             : {
     168           4 :     FlushCache(true);
     169           4 :     if (hGXF != nullptr)
     170           4 :         GXFClose(hGXF);
     171           8 : }
     172             : 
     173             : /************************************************************************/
     174             : /*                          GetGeoTransform()                           */
     175             : /************************************************************************/
     176             : 
     177           0 : CPLErr GXFDataset::GetGeoTransform(double *padfTransform)
     178             : 
     179             : {
     180           0 :     double dfXOrigin = 0.0;
     181           0 :     double dfYOrigin = 0.0;
     182           0 :     double dfXSize = 0.0;
     183           0 :     double dfYSize = 0.0;
     184           0 :     double dfRotation = 0.0;
     185             : 
     186           0 :     const CPLErr eErr = GXFGetPosition(hGXF, &dfXOrigin, &dfYOrigin, &dfXSize,
     187             :                                        &dfYSize, &dfRotation);
     188             : 
     189           0 :     if (eErr != CE_None)
     190           0 :         return eErr;
     191             : 
     192             :     // Transform to radians.
     193           0 :     dfRotation = (dfRotation / 360.0) * 2.0 * M_PI;
     194             : 
     195           0 :     padfTransform[1] = dfXSize * cos(dfRotation);
     196           0 :     padfTransform[2] = dfYSize * sin(dfRotation);
     197           0 :     padfTransform[4] = dfXSize * sin(dfRotation);
     198           0 :     padfTransform[5] = -1 * dfYSize * cos(dfRotation);
     199             : 
     200             :     // take into account that GXF is point or center of pixel oriented.
     201           0 :     padfTransform[0] =
     202           0 :         dfXOrigin - 0.5 * padfTransform[1] - 0.5 * padfTransform[2];
     203           0 :     padfTransform[3] =
     204           0 :         dfYOrigin - 0.5 * padfTransform[4] - 0.5 * padfTransform[5];
     205             : 
     206           0 :     return CE_None;
     207             : }
     208             : 
     209             : /************************************************************************/
     210             : /*                         GetSpatialRef()                              */
     211             : /************************************************************************/
     212             : 
     213           1 : const OGRSpatialReference *GXFDataset::GetSpatialRef() const
     214             : {
     215           1 :     return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
     216             : }
     217             : 
     218             : /************************************************************************/
     219             : /*                                Open()                                */
     220             : /************************************************************************/
     221             : 
     222       28795 : GDALDataset *GXFDataset::Open(GDALOpenInfo *poOpenInfo)
     223             : 
     224             : {
     225             :     /* -------------------------------------------------------------------- */
     226             :     /*      Before trying GXFOpen() we first verify that there is at        */
     227             :     /*      least one "\n#keyword" type signature in the first chunk of     */
     228             :     /*      the file.                                                       */
     229             :     /* -------------------------------------------------------------------- */
     230       28795 :     if (poOpenInfo->nHeaderBytes < 50 || poOpenInfo->fpL == nullptr)
     231       26056 :         return nullptr;
     232             : 
     233        2739 :     bool bFoundKeyword = false;
     234        2739 :     bool bFoundIllegal = false;
     235      596022 :     for (int i = 0; i < poOpenInfo->nHeaderBytes - 1; i++)
     236             :     {
     237      595281 :         if ((poOpenInfo->pabyHeader[i] == 10 ||
     238      579964 :              poOpenInfo->pabyHeader[i] == 13) &&
     239       16434 :             poOpenInfo->pabyHeader[i + 1] == '#')
     240             :         {
     241         153 :             if (STARTS_WITH((const char *)poOpenInfo->pabyHeader + i + 2,
     242             :                             "include"))
     243           0 :                 return nullptr;
     244         153 :             if (STARTS_WITH((const char *)poOpenInfo->pabyHeader + i + 2,
     245             :                             "define"))
     246           0 :                 return nullptr;
     247         153 :             if (STARTS_WITH((const char *)poOpenInfo->pabyHeader + i + 2,
     248             :                             "ifdef"))
     249           0 :                 return nullptr;
     250         153 :             bFoundKeyword = true;
     251             :         }
     252      595281 :         if (poOpenInfo->pabyHeader[i] == 0)
     253             :         {
     254        1998 :             bFoundIllegal = true;
     255        1998 :             break;
     256             :         }
     257             :     }
     258             : 
     259        2739 :     if (!bFoundKeyword || bFoundIllegal)
     260        2702 :         return nullptr;
     261             : 
     262             :     /* -------------------------------------------------------------------- */
     263             :     /*      At this point it is plausible that this is a GXF file, but      */
     264             :     /*      we also now verify that there is a #GRID keyword before         */
     265             :     /*      passing it off to GXFOpen().  We check in the first 50K.        */
     266             :     /* -------------------------------------------------------------------- */
     267          37 :     CPL_IGNORE_RET_VAL(poOpenInfo->TryToIngest(50000));
     268          37 :     bool bGotGrid = false;
     269             : 
     270          37 :     const char *pszBigBuf = (const char *)poOpenInfo->pabyHeader;
     271        8693 :     for (int i = 0; i < poOpenInfo->nHeaderBytes - 5 && !bGotGrid; i++)
     272             :     {
     273        8656 :         if (pszBigBuf[i] == '#' && STARTS_WITH_CI(pszBigBuf + i + 1, "GRID"))
     274           4 :             bGotGrid = true;
     275             :     }
     276             : 
     277          37 :     if (!bGotGrid)
     278          33 :         return nullptr;
     279             : 
     280           4 :     VSIFCloseL(poOpenInfo->fpL);
     281           4 :     poOpenInfo->fpL = nullptr;
     282             : 
     283             :     /* -------------------------------------------------------------------- */
     284             :     /*      Try opening the dataset.                                        */
     285             :     /* -------------------------------------------------------------------- */
     286             : 
     287           4 :     GXFHandle l_hGXF = GXFOpen(poOpenInfo->pszFilename);
     288             : 
     289           4 :     if (l_hGXF == nullptr)
     290           0 :         return nullptr;
     291             : 
     292             :     /* -------------------------------------------------------------------- */
     293             :     /*      Confirm the requested access is supported.                      */
     294             :     /* -------------------------------------------------------------------- */
     295           4 :     if (poOpenInfo->eAccess == GA_Update)
     296             :     {
     297           0 :         GXFClose(l_hGXF);
     298           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     299             :                  "The GXF driver does not support update access to existing"
     300             :                  " datasets.");
     301           0 :         return nullptr;
     302             :     }
     303             : 
     304             :     /* -------------------------------------------------------------------- */
     305             :     /*      Create a corresponding GDALDataset.                             */
     306             :     /* -------------------------------------------------------------------- */
     307           4 :     GXFDataset *poDS = new GXFDataset();
     308             : 
     309           4 :     const char *pszGXFDataType = CPLGetConfigOption("GXF_DATATYPE", "Float32");
     310           4 :     GDALDataType eDT = GDALGetDataTypeByName(pszGXFDataType);
     311           4 :     if (!(eDT == GDT_Float32 || eDT == GDT_Float64))
     312             :     {
     313           0 :         CPLError(CE_Warning, CPLE_NotSupported,
     314             :                  "Unsupported value for GXF_DATATYPE : %s", pszGXFDataType);
     315           0 :         eDT = GDT_Float32;
     316             :     }
     317             : 
     318           4 :     poDS->hGXF = l_hGXF;
     319           4 :     poDS->eDataType = eDT;
     320             : 
     321             :     /* -------------------------------------------------------------------- */
     322             :     /*      Establish the projection.                                       */
     323             :     /* -------------------------------------------------------------------- */
     324           4 :     char *pszProjection = GXFGetMapProjectionAsOGCWKT(l_hGXF);
     325           4 :     if (pszProjection && pszProjection[0] != '\0')
     326           2 :         poDS->m_oSRS.importFromWkt(pszProjection);
     327           4 :     CPLFree(pszProjection);
     328             : 
     329             :     /* -------------------------------------------------------------------- */
     330             :     /*      Capture some information from the file that is of interest.     */
     331             :     /* -------------------------------------------------------------------- */
     332           4 :     GXFGetRawInfo(l_hGXF, &(poDS->nRasterXSize), &(poDS->nRasterYSize), nullptr,
     333             :                   nullptr, nullptr, &(poDS->dfNoDataValue));
     334             : 
     335           4 :     if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
     336             :     {
     337           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid dimensions : %d x %d",
     338             :                  poDS->nRasterXSize, poDS->nRasterYSize);
     339           0 :         delete poDS;
     340           0 :         return nullptr;
     341             :     }
     342             : 
     343             :     /* -------------------------------------------------------------------- */
     344             :     /*      Create band information objects.                                */
     345             :     /* -------------------------------------------------------------------- */
     346           4 :     poDS->nBands = 1;
     347           4 :     poDS->SetBand(1, new GXFRasterBand(poDS, 1));
     348             : 
     349             :     /* -------------------------------------------------------------------- */
     350             :     /*      Initialize any PAM information.                                 */
     351             :     /* -------------------------------------------------------------------- */
     352           4 :     poDS->SetDescription(poOpenInfo->pszFilename);
     353           4 :     poDS->TryLoadXML();
     354             : 
     355             :     /* -------------------------------------------------------------------- */
     356             :     /*      Check for external overviews.                                   */
     357             :     /* -------------------------------------------------------------------- */
     358           4 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
     359             :                                 poOpenInfo->GetSiblingFiles());
     360             : 
     361           4 :     return poDS;
     362             : }
     363             : 
     364             : /************************************************************************/
     365             : /*                          GDALRegister_GXF()                          */
     366             : /************************************************************************/
     367             : 
     368        1512 : void GDALRegister_GXF()
     369             : 
     370             : {
     371        1512 :     if (GDALGetDriverByName("GXF") != nullptr)
     372         295 :         return;
     373             : 
     374        1217 :     GDALDriver *poDriver = new GDALDriver();
     375             : 
     376        1217 :     poDriver->SetDescription("GXF");
     377        1217 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     378        1217 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     379        1217 :                               "GeoSoft Grid Exchange Format");
     380        1217 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gxf.html");
     381        1217 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gxf");
     382        1217 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     383             : 
     384        1217 :     poDriver->pfnOpen = GXFDataset::Open;
     385             : 
     386        1217 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     387             : }

Generated by: LCOV version 1.14