LCOV - code coverage report
Current view: top level - frmts/gff - gff_dataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 21 121 17.4 %
Date: 2026-01-23 20:24:11 Functions: 3 9 33.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Ground-based SAR Applitcations Testbed File Format driver
       4             :  * Purpose:  Support in GDAL for Sandia National Laboratory's GFF format
       5             :  *           blame Tisham for putting me up to this
       6             :  * Author:   Philippe Vachon <philippe@cowpig.ca>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2007, Philippe Vachon
      10             :  * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_conv.h"
      16             : #include "cpl_port.h"
      17             : #include "cpl_string.h"
      18             : #include "cpl_vsi.h"
      19             : #include "gdal_frmts.h"
      20             : #include "gdal_pam.h"
      21             : #include "gdal_priv.h"
      22             : 
      23             : /*******************************************************************
      24             :  * Declaration of the GFFDataset class                             *
      25             :  *******************************************************************/
      26             : 
      27             : class GFFRasterBand;
      28             : 
      29             : class GFFDataset final : public GDALPamDataset
      30             : {
      31             :     friend class GFFRasterBand;
      32             :     VSILFILE *fp;
      33             :     GDALDataType eDataType;
      34             :     unsigned int nEndianness;
      35             :     /* Some relevant headers */
      36             :     unsigned short nVersionMajor;
      37             :     unsigned short nVersionMinor;
      38             :     unsigned int nLength;
      39             :     // char *pszCreator;
      40             :     //  TODO: Needs a better explanation.
      41             :     /* I am taking this at face value (are they insane?) */
      42             :     // float fBPP;
      43             :     unsigned int nBPP;
      44             : 
      45             :     /* Good information to know */
      46             :     unsigned int nFrameCnt;
      47             :     unsigned int nImageType;
      48             :     unsigned int nRowMajor;
      49             :     unsigned int nRgCnt;
      50             :     unsigned int nAzCnt;
      51             :     // long nScaleExponent;
      52             :     // long nScaleMantissa;
      53             :     // long nOffsetExponent;
      54             :     // long nOffsetMantissa;
      55             :   public:
      56             :     GFFDataset();
      57             :     ~GFFDataset() override;
      58             : 
      59             :     static GDALDataset *Open(GDALOpenInfo *);
      60             :     static int Identify(GDALOpenInfo *poOpenInfo);
      61             : };
      62             : 
      63           0 : GFFDataset::GFFDataset()
      64             :     : fp(nullptr), eDataType(GDT_Unknown), nEndianness(0), nVersionMajor(0),
      65             :       nVersionMinor(0), nLength(0), nBPP(0), nFrameCnt(0), nImageType(0),
      66           0 :       nRowMajor(0), nRgCnt(0), nAzCnt(0)
      67             : {
      68           0 : }
      69             : 
      70           0 : GFFDataset::~GFFDataset()
      71             : {
      72           0 :     if (fp != nullptr)
      73           0 :         VSIFCloseL(fp);
      74           0 : }
      75             : 
      76             : /*********************************************************************
      77             :  * Declaration and implementation of the GFFRasterBand Class         *
      78             :  *********************************************************************/
      79             : 
      80             : class GFFRasterBand final : public GDALPamRasterBand
      81             : {
      82             :     long nRasterBandMemory;
      83             :     int nSampleSize;
      84             : 
      85             :   public:
      86             :     GFFRasterBand(GFFDataset *, int, GDALDataType);
      87             :     CPLErr IReadBlock(int, int, void *) override;
      88             : };
      89             : 
      90           0 : static unsigned long GFFSampleSize(GDALDataType eDataType)
      91             : {
      92             :     // Determine the number of bytes per sample.
      93           0 :     unsigned long nBytes = 1;
      94           0 :     switch (eDataType)
      95             :     {
      96           0 :         case GDT_CInt16:
      97           0 :             nBytes = 4;
      98           0 :             break;
      99           0 :         case GDT_CInt32:
     100             :         case GDT_CFloat32:
     101           0 :             nBytes = 8;
     102           0 :             break;
     103           0 :         default:
     104           0 :             nBytes = 1;
     105             :     }
     106             : 
     107           0 :     return nBytes;
     108             : }
     109             : 
     110             : /************************************************************************/
     111             : /*                           GFFRasterBand()                            */
     112             : /************************************************************************/
     113           0 : GFFRasterBand::GFFRasterBand(GFFDataset *poDSIn, int nBandIn,
     114           0 :                              GDALDataType eDataTypeIn)
     115           0 :     : nRasterBandMemory(GFFSampleSize(eDataTypeIn) * poDSIn->GetRasterXSize()),
     116           0 :       nSampleSize(static_cast<int>(GFFSampleSize(eDataTypeIn)))
     117             : {
     118           0 :     poDS = poDSIn;
     119           0 :     nBand = nBandIn;
     120             : 
     121           0 :     eDataType = eDataTypeIn;
     122             : 
     123           0 :     nBlockXSize = poDS->GetRasterXSize();
     124           0 :     nBlockYSize = 1;
     125           0 : }
     126             : 
     127             : /************************************************************************/
     128             : /*                             IReadBlock()                             */
     129             : /************************************************************************/
     130             : 
     131           0 : CPLErr GFFRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
     132             :                                  void *pImage)
     133             : {
     134           0 :     GFFDataset *poGDS = cpl::down_cast<GFFDataset *>(poDS);
     135           0 :     long nOffset = poGDS->nLength;
     136             : 
     137           0 :     VSIFSeekL(poGDS->fp,
     138           0 :               nOffset + (static_cast<vsi_l_offset>(poGDS->GetRasterXSize()) *
     139           0 :                          nBlockYOff * (nSampleSize)),
     140             :               SEEK_SET);
     141             : 
     142             :     /* Ingest entire range line */
     143           0 :     if (VSIFReadL(pImage, nRasterBandMemory, 1, poGDS->fp) != 1)
     144           0 :         return CE_Failure;
     145             : 
     146             : #if defined(CPL_MSB)
     147             :     if (GDALDataTypeIsComplex(eDataType))
     148             :     {
     149             :         int nWordSize = GDALGetDataTypeSize(eDataType) / 16;
     150             :         GDALSwapWords(pImage, nWordSize, nBlockXSize, 2 * nWordSize);
     151             :         GDALSwapWords(((GByte *)pImage) + nWordSize, nWordSize, nBlockXSize,
     152             :                       2 * nWordSize);
     153             :     }
     154             : #endif
     155             : 
     156           0 :     return CE_None;
     157             : }
     158             : 
     159             : /********************************************************************
     160             :  * ================================================================ *
     161             :  * Implementation of the GFFDataset Class                           *
     162             :  * ================================================================ *
     163             :  ********************************************************************/
     164             : 
     165             : /************************************************************************/
     166             : /*                              Identify()                              */
     167             : /************************************************************************/
     168       41187 : int GFFDataset::Identify(GDALOpenInfo *poOpenInfo)
     169             : {
     170       41187 :     if (poOpenInfo->nHeaderBytes < 7)
     171       32870 :         return 0;
     172             : 
     173        8317 :     if (STARTS_WITH_CI((char *)poOpenInfo->pabyHeader, "GSATIMG"))
     174           0 :         return 1;
     175             : 
     176        8317 :     return 0;
     177             : }
     178             : 
     179             : /************************************************************************/
     180             : /*                                Open()                                */
     181             : /************************************************************************/
     182             : 
     183       41187 : GDALDataset *GFFDataset::Open(GDALOpenInfo *poOpenInfo)
     184             : {
     185             :     /* Check that the dataset is indeed a GSAT File Format (GFF) file */
     186       41187 :     if (!GFFDataset::Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
     187       41187 :         return nullptr;
     188             : 
     189             :     /* -------------------------------------------------------------------- */
     190             :     /*      Confirm the requested access is supported.                      */
     191             :     /* -------------------------------------------------------------------- */
     192           0 :     if (poOpenInfo->eAccess == GA_Update)
     193             :     {
     194           0 :         ReportUpdateNotSupportedByDriver("GFF");
     195           0 :         return nullptr;
     196             :     }
     197             : 
     198           0 :     GFFDataset *poDS = new GFFDataset();
     199             : 
     200           0 :     poDS->fp = poOpenInfo->fpL;
     201           0 :     poOpenInfo->fpL = nullptr;
     202             : 
     203             :     /* Check the endianness of the file */
     204           0 :     VSIFSeekL(poDS->fp, 54, SEEK_SET);
     205           0 :     VSIFReadL(&(poDS->nEndianness), 2, 1, poDS->fp);
     206             : 
     207           0 :     VSIFSeekL(poDS->fp, 8, SEEK_SET);
     208           0 :     VSIFReadL(&poDS->nVersionMinor, 2, 1, poDS->fp);
     209           0 :     CPL_LSBPTR16(&poDS->nVersionMinor);
     210           0 :     VSIFReadL(&poDS->nVersionMajor, 2, 1, poDS->fp);
     211           0 :     CPL_LSBPTR16(&poDS->nVersionMajor);
     212           0 :     VSIFReadL(&poDS->nLength, 4, 1, poDS->fp);
     213           0 :     CPL_LSBPTR32(&poDS->nLength);
     214             : 
     215           0 :     unsigned short nCreatorLength = 0;
     216           0 :     VSIFReadL(&nCreatorLength, 2, 1, poDS->fp);
     217           0 :     CPL_LSBPTR16(&nCreatorLength);
     218             :     /* Hack for now... I should properly load the date metadata, for
     219             :      * example
     220             :      */
     221           0 :     VSIFSeekL(poDS->fp, 56, SEEK_SET);
     222             : 
     223             :     /* By looking at the Matlab code, one should write something like the
     224             :      * following test */
     225             :     /* but the results don't seem to be the ones really expected */
     226             :     /*if ((poDS->nVersionMajor == 1 && poDS->nVersionMinor > 7) ||
     227             :     (poDS->nVersionMajor > 1))
     228             :     {
     229             :         float fBPP;
     230             :         VSIFRead(&fBPP,4,1,poDS->fp);
     231             :         poDS->nBPP = fBPP;
     232             :     }
     233             :     else*/
     234             :     {
     235           0 :         VSIFReadL(&poDS->nBPP, 4, 1, poDS->fp);
     236           0 :         CPL_LSBPTR32(&poDS->nBPP);
     237             :     }
     238           0 :     VSIFReadL(&poDS->nFrameCnt, 4, 1, poDS->fp);
     239           0 :     CPL_LSBPTR32(&poDS->nFrameCnt);
     240           0 :     VSIFReadL(&poDS->nImageType, 4, 1, poDS->fp);
     241           0 :     CPL_LSBPTR32(&poDS->nImageType);
     242           0 :     VSIFReadL(&poDS->nRowMajor, 4, 1, poDS->fp);
     243           0 :     CPL_LSBPTR32(&poDS->nRowMajor);
     244           0 :     VSIFReadL(&poDS->nRgCnt, 4, 1, poDS->fp);
     245           0 :     CPL_LSBPTR32(&poDS->nRgCnt);
     246           0 :     VSIFReadL(&poDS->nAzCnt, 4, 1, poDS->fp);
     247           0 :     CPL_LSBPTR32(&poDS->nAzCnt);
     248             : 
     249             :     /* We now have enough information to determine the number format */
     250           0 :     switch (poDS->nImageType)
     251             :     {
     252           0 :         case 0:
     253           0 :             poDS->eDataType = GDT_UInt8;
     254           0 :             break;
     255             : 
     256           0 :         case 1:
     257           0 :             if (poDS->nBPP == 4)
     258           0 :                 poDS->eDataType = GDT_CInt16;
     259             :             else
     260           0 :                 poDS->eDataType = GDT_CInt32;
     261           0 :             break;
     262             : 
     263           0 :         case 2:
     264           0 :             poDS->eDataType = GDT_CFloat32;
     265           0 :             break;
     266             : 
     267           0 :         default:
     268           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Unknown image type found!");
     269           0 :             delete poDS;
     270           0 :             return nullptr;
     271             :     }
     272             : 
     273             :     /* Set raster width/height
     274             :      * Note that the images that are complex are listed as having twice the
     275             :      * number of X-direction values than there are actual pixels. This is
     276             :      * because whoever came up with the format was crazy (actually, my
     277             :      * hunch is that they designed it very much for Matlab)
     278             :      * */
     279           0 :     if (poDS->nRowMajor)
     280             :     {
     281           0 :         poDS->nRasterXSize = poDS->nRgCnt / (poDS->nImageType == 0 ? 1 : 2);
     282           0 :         poDS->nRasterYSize = poDS->nAzCnt;
     283             :     }
     284             :     else
     285             :     {
     286           0 :         poDS->nRasterXSize = poDS->nAzCnt / (poDS->nImageType == 0 ? 1 : 2);
     287           0 :         poDS->nRasterYSize = poDS->nRgCnt;
     288             :     }
     289             : 
     290           0 :     if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
     291             :     {
     292           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     293             :                  "Invalid raster dimensions : %d x %d", poDS->nRasterXSize,
     294             :                  poDS->nRasterYSize);
     295           0 :         delete poDS;
     296           0 :         return nullptr;
     297             :     }
     298             : 
     299           0 :     poDS->SetBand(1, new GFFRasterBand(poDS, 1, poDS->eDataType));
     300             : 
     301             :     /* -------------------------------------------------------------------- */
     302             :     /*      Initialize any PAM information.                                 */
     303             :     /* -------------------------------------------------------------------- */
     304           0 :     poDS->SetDescription(poOpenInfo->pszFilename);
     305           0 :     poDS->TryLoadXML();
     306             : 
     307             :     /* -------------------------------------------------------------------- */
     308             :     /*      Support overviews.                                              */
     309             :     /* -------------------------------------------------------------------- */
     310           0 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
     311             : 
     312           0 :     return poDS;
     313             : }
     314             : 
     315             : /************************************************************************/
     316             : /*                          GDALRegister_GFF()                          */
     317             : /************************************************************************/
     318             : 
     319        2058 : void GDALRegister_GFF()
     320             : {
     321        2058 :     if (GDALGetDriverByName("GFF") != nullptr)
     322         283 :         return;
     323             : 
     324        1775 :     GDALDriver *poDriver = new GDALDriver();
     325             : 
     326        1775 :     poDriver->SetDescription("GFF");
     327        1775 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     328        1775 :     poDriver->SetMetadataItem(
     329             :         GDAL_DMD_LONGNAME,
     330        1775 :         "Ground-based SAR Applications Testbed File Format (.gff)");
     331        1775 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gff.html");
     332        1775 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gff");
     333        1775 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     334        1775 :     poDriver->pfnOpen = GFFDataset::Open;
     335        1775 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     336             : }

Generated by: LCOV version 1.14