LCOV - code coverage report
Current view: top level - frmts/sdts - sdtsdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 93 121 76.9 %
Date: 2025-02-18 14:19:29 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  SDTS Translator
       4             :  * Purpose:  GDALDataset driver for SDTS Raster translator.
       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             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "gdal_frmts.h"
      15             : #include "gdal_pam.h"
      16             : #include "ogr_spatialref.h"
      17             : #include "sdts_al.h"
      18             : 
      19             : /**
      20             :  \file sdtsdataset.cpp
      21             : 
      22             :  exclude
      23             : */
      24             : 
      25             : /************************************************************************/
      26             : /* ==================================================================== */
      27             : /*                              SDTSDataset                             */
      28             : /* ==================================================================== */
      29             : /************************************************************************/
      30             : 
      31             : class SDTSRasterBand;
      32             : 
      33             : class SDTSDataset final : public GDALPamDataset
      34             : {
      35             :     friend class SDTSRasterBand;
      36             : 
      37             :     SDTSTransfer *poTransfer;
      38             :     SDTSRasterReader *poRL;
      39             : 
      40             :     OGRSpatialReference m_oSRS{};
      41             : 
      42             :   public:
      43             :     SDTSDataset();
      44             :     virtual ~SDTSDataset();
      45             : 
      46             :     static GDALDataset *Open(GDALOpenInfo *);
      47             : 
      48           1 :     const OGRSpatialReference *GetSpatialRef() const override
      49             :     {
      50           1 :         return &m_oSRS;
      51             :     }
      52             : 
      53             :     virtual CPLErr GetGeoTransform(double *) override;
      54             : };
      55             : 
      56             : class SDTSRasterBand final : public GDALPamRasterBand
      57             : {
      58             :     friend class SDTSDataset;
      59             : 
      60             :     SDTSRasterReader *poRL;
      61             : 
      62             :   public:
      63             :     SDTSRasterBand(SDTSDataset *, int, SDTSRasterReader *);
      64             : 
      65             :     virtual CPLErr IReadBlock(int, int, void *) override;
      66             : 
      67             :     virtual double GetNoDataValue(int *pbSuccess) override;
      68             :     virtual const char *GetUnitType() override;
      69             : };
      70             : 
      71             : /************************************************************************/
      72             : /*                             SDTSDataset()                            */
      73             : /************************************************************************/
      74             : 
      75           2 : SDTSDataset::SDTSDataset() : poTransfer(nullptr), poRL(nullptr)
      76             : {
      77           2 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      78           2 : }
      79             : 
      80             : /************************************************************************/
      81             : /*                            ~SDTSDataset()                            */
      82             : /************************************************************************/
      83             : 
      84           4 : SDTSDataset::~SDTSDataset()
      85             : 
      86             : {
      87           2 :     FlushCache(true);
      88             : 
      89           2 :     if (poTransfer != nullptr)
      90           2 :         delete poTransfer;
      91             : 
      92           2 :     if (poRL != nullptr)
      93           2 :         delete poRL;
      94           4 : }
      95             : 
      96             : /************************************************************************/
      97             : /*                                Open()                                */
      98             : /************************************************************************/
      99             : 
     100       36092 : GDALDataset *SDTSDataset::Open(GDALOpenInfo *poOpenInfo)
     101             : 
     102             : {
     103             :     /* -------------------------------------------------------------------- */
     104             :     /*      Before trying SDTSOpen() we first verify that the first         */
     105             :     /*      record is in fact a SDTS file descriptor record.                */
     106             :     /* -------------------------------------------------------------------- */
     107       36092 :     if (poOpenInfo->nHeaderBytes < 24)
     108       29053 :         return nullptr;
     109             : 
     110        7039 :     char *pachLeader = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
     111        7039 :     if (pachLeader[5] != '1' && pachLeader[5] != '2' && pachLeader[5] != '3')
     112        6715 :         return nullptr;
     113             : 
     114         324 :     if (pachLeader[6] != 'L')
     115         273 :         return nullptr;
     116             : 
     117          51 :     if (pachLeader[8] != '1' && pachLeader[8] != ' ')
     118           0 :         return nullptr;
     119             : 
     120             :     /* -------------------------------------------------------------------- */
     121             :     /*      Try opening the dataset.                                        */
     122             :     /* -------------------------------------------------------------------- */
     123          51 :     SDTSTransfer *poTransfer = new SDTSTransfer;
     124             : 
     125          51 :     if (!poTransfer->Open(poOpenInfo->pszFilename))
     126             :     {
     127          49 :         delete poTransfer;
     128          49 :         return nullptr;
     129             :     }
     130             : 
     131             :     /* -------------------------------------------------------------------- */
     132             :     /*      Confirm the requested access is supported.                      */
     133             :     /* -------------------------------------------------------------------- */
     134           2 :     if (poOpenInfo->eAccess == GA_Update)
     135             :     {
     136           0 :         delete poTransfer;
     137           0 :         ReportUpdateNotSupportedByDriver("SDTS");
     138           0 :         return nullptr;
     139             :     }
     140             : 
     141             :     /* -------------------------------------------------------------------- */
     142             :     /*      Find the first raster layer.  If there are none, abort          */
     143             :     /*      returning an error.                                             */
     144             :     /* -------------------------------------------------------------------- */
     145           2 :     SDTSRasterReader *poRL = nullptr;
     146             : 
     147           2 :     for (int i = 0; i < poTransfer->GetLayerCount(); i++)
     148             :     {
     149           2 :         if (poTransfer->GetLayerType(i) == SLTRaster)
     150             :         {
     151           2 :             poRL = poTransfer->GetLayerRasterReader(i);
     152           2 :             break;
     153             :         }
     154             :     }
     155             : 
     156           2 :     if (poRL == nullptr)
     157             :     {
     158           0 :         delete poTransfer;
     159             : 
     160           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     161             :                  "%s is an SDTS transfer, but has no raster cell layers.\n"
     162             :                  "Perhaps it is a vector transfer?\n",
     163             :                  poOpenInfo->pszFilename);
     164           0 :         return nullptr;
     165             :     }
     166             : 
     167             :     /* -------------------------------------------------------------------- */
     168             :     /*      Initialize a corresponding GDALDataset.                         */
     169             :     /* -------------------------------------------------------------------- */
     170           2 :     SDTSDataset *poDS = new SDTSDataset();
     171             : 
     172           2 :     poDS->poTransfer = poTransfer;
     173           2 :     poDS->poRL = poRL;
     174             : 
     175             :     /* -------------------------------------------------------------------- */
     176             :     /*      Capture some information from the file that is of interest.     */
     177             :     /* -------------------------------------------------------------------- */
     178           2 :     poDS->nRasterXSize = poRL->GetXSize();
     179           2 :     poDS->nRasterYSize = poRL->GetYSize();
     180             : 
     181             :     /* -------------------------------------------------------------------- */
     182             :     /*      Create band information objects.                                */
     183             :     /* -------------------------------------------------------------------- */
     184           2 :     poDS->nBands = 1;
     185           2 :     poDS->papoBands = reinterpret_cast<GDALRasterBand **>(
     186           2 :         VSICalloc(sizeof(GDALRasterBand *), poDS->nBands));
     187             : 
     188           4 :     for (int i = 0; i < poDS->nBands; i++)
     189           2 :         poDS->SetBand(i + 1, new SDTSRasterBand(poDS, i + 1, poRL));
     190             : 
     191             :     /* -------------------------------------------------------------------- */
     192             :     /*      Try to establish the projection string.  For now we only        */
     193             :     /*      support UTM and GEO.                                            */
     194             :     /* -------------------------------------------------------------------- */
     195           2 :     SDTS_XREF *poXREF = poTransfer->GetXREF();
     196             : 
     197           2 :     if (EQUAL(poXREF->pszSystemName, "UTM"))
     198             :     {
     199           2 :         poDS->m_oSRS.SetUTM(poXREF->nZone);
     200             :     }
     201           0 :     else if (EQUAL(poXREF->pszSystemName, "GEO"))
     202             :     {
     203             :         /* we set datum later */
     204             :     }
     205             :     else
     206           0 :         poDS->m_oSRS.SetLocalCS(poXREF->pszSystemName);
     207             : 
     208           2 :     if (poDS->m_oSRS.IsLocal())
     209             :         /* don't try to set datum. */;
     210           2 :     else if (EQUAL(poXREF->pszDatum, "NAS"))
     211           2 :         poDS->m_oSRS.SetWellKnownGeogCS("NAD27");
     212           0 :     else if (EQUAL(poXREF->pszDatum, "NAX"))
     213           0 :         poDS->m_oSRS.SetWellKnownGeogCS("NAD83");
     214           0 :     else if (EQUAL(poXREF->pszDatum, "WGC"))
     215           0 :         poDS->m_oSRS.SetWellKnownGeogCS("WGS72");
     216             :     else /* if( EQUAL(poXREF->pszDatum, "WGE") ) or default */
     217           0 :         poDS->m_oSRS.SetWellKnownGeogCS("WGS84");
     218             : 
     219             :     /* -------------------------------------------------------------------- */
     220             :     /*      Get metadata from the IDEN file.                                */
     221             :     /* -------------------------------------------------------------------- */
     222             :     const char *pszIDENFilePath =
     223           2 :         poTransfer->GetCATD()->GetModuleFilePath("IDEN");
     224           2 :     if (pszIDENFilePath)
     225             :     {
     226           4 :         DDFModule oIDENFile;
     227           2 :         if (oIDENFile.Open(pszIDENFilePath))
     228             :         {
     229           2 :             DDFRecord *poRecord = nullptr;
     230             : 
     231           2 :             while ((poRecord = oIDENFile.ReadRecord()) != nullptr)
     232             :             {
     233             : 
     234           2 :                 if (poRecord->GetStringSubfield("IDEN", 0, "MODN", 0) ==
     235             :                     nullptr)
     236           0 :                     continue;
     237             : 
     238             :                 static const char *const fields[][2] = {
     239             :                     {"TITL", "TITLE"},
     240             :                     {"DAID", "DATASET_ID"},
     241             :                     {"DAST", "DATA_STRUCTURE"},
     242             :                     {"MPDT", "MAP_DATE"},
     243             :                     {"DCDT", "DATASET_CREATION_DATE"}};
     244             : 
     245          12 :                 for (int i = 0; i < static_cast<int>(sizeof(fields)) /
     246             :                                         static_cast<int>(sizeof(fields[0]));
     247             :                      i++)
     248             :                 {
     249             :                     const char *pszFieldValue =
     250          10 :                         poRecord->GetStringSubfield("IDEN", 0, fields[i][0], 0);
     251          10 :                     if (pszFieldValue)
     252          10 :                         poDS->SetMetadataItem(fields[i][1], pszFieldValue);
     253             :                 }
     254             : 
     255           2 :                 break;
     256             :             }
     257             :         }
     258             :     }
     259             : 
     260             :     /* -------------------------------------------------------------------- */
     261             :     /*      Initialize any PAM information.                                 */
     262             :     /* -------------------------------------------------------------------- */
     263           2 :     poDS->SetDescription(poOpenInfo->pszFilename);
     264           2 :     poDS->TryLoadXML();
     265             : 
     266             :     /* -------------------------------------------------------------------- */
     267             :     /*      Check for external overviews.                                   */
     268             :     /* -------------------------------------------------------------------- */
     269           4 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
     270           2 :                                 poOpenInfo->GetSiblingFiles());
     271             : 
     272           2 :     return poDS;
     273             : }
     274             : 
     275             : /************************************************************************/
     276             : /*                          GetGeoTransform()                           */
     277             : /************************************************************************/
     278             : 
     279           1 : CPLErr SDTSDataset::GetGeoTransform(double *padfTransform)
     280             : 
     281             : {
     282           1 :     if (poRL->GetTransform(padfTransform))
     283           1 :         return CE_None;
     284             : 
     285           0 :     return CE_Failure;
     286             : }
     287             : 
     288             : /************************************************************************/
     289             : /* ==================================================================== */
     290             : /*                            SDTSRasterBand                             */
     291             : /* ==================================================================== */
     292             : /************************************************************************/
     293             : 
     294             : /************************************************************************/
     295             : /*                           SDTSRasterBand()                            */
     296             : /************************************************************************/
     297             : 
     298           2 : SDTSRasterBand::SDTSRasterBand(SDTSDataset *poDSIn, int nBandIn,
     299           2 :                                SDTSRasterReader *poRLIn)
     300           2 :     : poRL(poRLIn)
     301             : {
     302           2 :     poDS = poDSIn;
     303           2 :     nBand = nBandIn;
     304             : 
     305           2 :     if (poRL->GetRasterType() == SDTS_RT_INT16)
     306           2 :         eDataType = GDT_Int16;
     307             :     else
     308           0 :         eDataType = GDT_Float32;
     309             : 
     310           2 :     nBlockXSize = poRL->GetBlockXSize();
     311           2 :     nBlockYSize = poRL->GetBlockYSize();
     312           2 : }
     313             : 
     314             : /************************************************************************/
     315             : /*                             IReadBlock()                             */
     316             : /************************************************************************/
     317             : 
     318          25 : CPLErr SDTSRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     319             : 
     320             : {
     321          25 :     if (poRL->GetBlock(nBlockXOff, nBlockYOff, pImage))
     322          25 :         return CE_None;
     323             : 
     324           0 :     return CE_Failure;
     325             : }
     326             : 
     327             : /************************************************************************/
     328             : /*                           GetNoDataValue()                           */
     329             : /************************************************************************/
     330             : 
     331           0 : double SDTSRasterBand::GetNoDataValue(int *pbSuccess)
     332             : 
     333             : {
     334           0 :     if (pbSuccess != nullptr)
     335           0 :         *pbSuccess = TRUE;
     336             : 
     337           0 :     return -32766.0;
     338             : }
     339             : 
     340             : /************************************************************************/
     341             : /*                            GetUnitType()                             */
     342             : /************************************************************************/
     343             : 
     344           0 : const char *SDTSRasterBand::GetUnitType()
     345             : 
     346             : {
     347           0 :     if (EQUAL(poRL->szUNITS, "FEET"))
     348           0 :         return "ft";
     349           0 :     else if (STARTS_WITH_CI(poRL->szUNITS, "MET"))
     350           0 :         return "m";
     351             : 
     352           0 :     return poRL->szUNITS;
     353             : }
     354             : 
     355             : /************************************************************************/
     356             : /*                         GDALRegister_SDTS()                          */
     357             : /************************************************************************/
     358             : 
     359        1686 : void GDALRegister_SDTS()
     360             : 
     361             : {
     362        1686 :     if (GDALGetDriverByName("SDTS") != nullptr)
     363         302 :         return;
     364             : 
     365        1384 :     GDALDriver *poDriver = new GDALDriver();
     366             : 
     367        1384 :     poDriver->SetDescription("SDTS");
     368        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     369        1384 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "SDTS Raster");
     370        1384 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/sdts.html");
     371        1384 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "ddf");
     372        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     373             : 
     374        1384 :     poDriver->pfnOpen = SDTSDataset::Open;
     375             : 
     376        1384 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     377             : }

Generated by: LCOV version 1.14