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

Generated by: LCOV version 1.14