LCOV - code coverage report
Current view: top level - frmts/jdem - jdemdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 95 126 75.4 %
Date: 2024-05-06 22:33:47 Functions: 12 14 85.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  JDEM Reader
       4             :  * Purpose:  All code for Japanese DEM Reader
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2000, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2009-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 "cpl_port.h"
      31             : #include "gdal_frmts.h"
      32             : #include "gdal_pam.h"
      33             : 
      34             : #include <algorithm>
      35             : 
      36             : constexpr int HEADER_SIZE = 1011;
      37             : 
      38             : /************************************************************************/
      39             : /*                            JDEMGetField()                            */
      40             : /************************************************************************/
      41             : 
      42          26 : static int JDEMGetField(const char *pszField, int nWidth)
      43             : 
      44             : {
      45          26 :     char szWork[32] = {};
      46          26 :     CPLAssert(nWidth < static_cast<int>(sizeof(szWork)));
      47             : 
      48          26 :     strncpy(szWork, pszField, nWidth);
      49          26 :     szWork[nWidth] = '\0';
      50             : 
      51          52 :     return atoi(szWork);
      52             : }
      53             : 
      54             : /************************************************************************/
      55             : /*                            JDEMGetAngle()                            */
      56             : /************************************************************************/
      57             : 
      58          16 : static double JDEMGetAngle(const char *pszField)
      59             : 
      60             : {
      61          16 :     const int nAngle = JDEMGetField(pszField, 7);
      62             : 
      63             :     // Note, this isn't very general purpose, but it would appear
      64             :     // from the field widths that angles are never negative.  Nice
      65             :     // to be a country in the "first quadrant".
      66             : 
      67          16 :     const int nDegree = nAngle / 10000;
      68          16 :     const int nMin = (nAngle / 100) % 100;
      69          16 :     const int nSec = nAngle % 100;
      70             : 
      71          16 :     return nDegree + nMin / 60.0 + nSec / 3600.0;
      72             : }
      73             : 
      74             : /************************************************************************/
      75             : /* ==================================================================== */
      76             : /*                              JDEMDataset                             */
      77             : /* ==================================================================== */
      78             : /************************************************************************/
      79             : 
      80             : class JDEMRasterBand;
      81             : 
      82             : class JDEMDataset final : public GDALPamDataset
      83             : {
      84             :     friend class JDEMRasterBand;
      85             : 
      86             :     VSILFILE *m_fp = nullptr;
      87             :     GByte m_abyHeader[HEADER_SIZE];
      88             :     OGRSpatialReference m_oSRS{};
      89             : 
      90             :   public:
      91             :     JDEMDataset();
      92             :     ~JDEMDataset();
      93             : 
      94             :     static GDALDataset *Open(GDALOpenInfo *);
      95             :     static int Identify(GDALOpenInfo *);
      96             : 
      97             :     CPLErr GetGeoTransform(double *padfTransform) override;
      98             :     const OGRSpatialReference *GetSpatialRef() const override;
      99             : };
     100             : 
     101             : /************************************************************************/
     102             : /* ==================================================================== */
     103             : /*                            JDEMRasterBand                             */
     104             : /* ==================================================================== */
     105             : /************************************************************************/
     106             : 
     107             : class JDEMRasterBand final : public GDALPamRasterBand
     108             : {
     109             :     friend class JDEMDataset;
     110             : 
     111             :     int m_nRecordSize = 0;
     112             :     char *m_pszRecord = nullptr;
     113             :     bool m_bBufferAllocFailed = false;
     114             : 
     115             :   public:
     116             :     JDEMRasterBand(JDEMDataset *, int);
     117             :     ~JDEMRasterBand();
     118             : 
     119             :     virtual CPLErr IReadBlock(int, int, void *) override;
     120             : };
     121             : 
     122             : /************************************************************************/
     123             : /*                           JDEMRasterBand()                            */
     124             : /************************************************************************/
     125             : 
     126           2 : JDEMRasterBand::JDEMRasterBand(JDEMDataset *poDSIn, int nBandIn)
     127             :     :  // Cannot overflow as nBlockXSize <= 999.
     128           2 :       m_nRecordSize(poDSIn->GetRasterXSize() * 5 + 9 + 2)
     129             : {
     130           2 :     poDS = poDSIn;
     131           2 :     nBand = nBandIn;
     132             : 
     133           2 :     eDataType = GDT_Float32;
     134             : 
     135           2 :     nBlockXSize = poDS->GetRasterXSize();
     136           2 :     nBlockYSize = 1;
     137           2 : }
     138             : 
     139             : /************************************************************************/
     140             : /*                          ~JDEMRasterBand()                            */
     141             : /************************************************************************/
     142             : 
     143           4 : JDEMRasterBand::~JDEMRasterBand()
     144             : {
     145           2 :     VSIFree(m_pszRecord);
     146           4 : }
     147             : 
     148             : /************************************************************************/
     149             : /*                             IReadBlock()                             */
     150             : /************************************************************************/
     151             : 
     152           2 : CPLErr JDEMRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
     153             :                                   void *pImage)
     154             : 
     155             : {
     156           2 :     JDEMDataset *poGDS = cpl::down_cast<JDEMDataset *>(poDS);
     157             : 
     158           2 :     if (m_pszRecord == nullptr)
     159             :     {
     160           1 :         if (m_bBufferAllocFailed)
     161           0 :             return CE_Failure;
     162             : 
     163           1 :         m_pszRecord = static_cast<char *>(VSI_MALLOC_VERBOSE(m_nRecordSize));
     164           1 :         if (m_pszRecord == nullptr)
     165             :         {
     166           0 :             m_bBufferAllocFailed = true;
     167           0 :             return CE_Failure;
     168             :         }
     169             :     }
     170             : 
     171           2 :     CPL_IGNORE_RET_VAL(
     172           2 :         VSIFSeekL(poGDS->m_fp, 1011 + m_nRecordSize * nBlockYOff, SEEK_SET));
     173             : 
     174           2 :     if (VSIFReadL(m_pszRecord, m_nRecordSize, 1, poGDS->m_fp) != 1)
     175             :     {
     176           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot read scanline %d",
     177             :                  nBlockYOff);
     178           0 :         return CE_Failure;
     179             :     }
     180             : 
     181           2 :     if (!EQUALN(reinterpret_cast<char *>(poGDS->m_abyHeader), m_pszRecord, 6))
     182             :     {
     183           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     184             :                  "JDEM Scanline corrupt.  Perhaps file was not transferred "
     185             :                  "in binary mode?");
     186           0 :         return CE_Failure;
     187             :     }
     188             : 
     189           2 :     if (JDEMGetField(m_pszRecord + 6, 3) != nBlockYOff + 1)
     190             :     {
     191           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     192             :                  "JDEM scanline out of order, JDEM driver does not "
     193             :                  "currently support partial datasets.");
     194           0 :         return CE_Failure;
     195             :     }
     196             : 
     197           6 :     for (int i = 0; i < nBlockXSize; i++)
     198           4 :         static_cast<float *>(pImage)[i] =
     199           4 :             JDEMGetField(m_pszRecord + 9 + 5 * i, 5) * 0.1f;
     200             : 
     201           2 :     return CE_None;
     202             : }
     203             : 
     204             : /************************************************************************/
     205             : /* ==================================================================== */
     206             : /*                              JDEMDataset                             */
     207             : /* ==================================================================== */
     208             : /************************************************************************/
     209             : 
     210             : /************************************************************************/
     211             : /*                            JDEMDataset()                             */
     212             : /************************************************************************/
     213             : 
     214           2 : JDEMDataset::JDEMDataset()
     215             : {
     216           2 :     std::fill_n(m_abyHeader, CPL_ARRAYSIZE(m_abyHeader), static_cast<GByte>(0));
     217           2 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     218           2 :     m_oSRS.importFromEPSG(4301);  // Tokyo geographic CRS
     219           2 : }
     220             : 
     221             : /************************************************************************/
     222             : /*                           ~JDEMDataset()                             */
     223             : /************************************************************************/
     224             : 
     225           4 : JDEMDataset::~JDEMDataset()
     226             : 
     227             : {
     228           2 :     FlushCache(true);
     229           2 :     if (m_fp != nullptr)
     230           2 :         CPL_IGNORE_RET_VAL(VSIFCloseL(m_fp));
     231           4 : }
     232             : 
     233             : /************************************************************************/
     234             : /*                          GetGeoTransform()                           */
     235             : /************************************************************************/
     236             : 
     237           0 : CPLErr JDEMDataset::GetGeoTransform(double *padfTransform)
     238             : 
     239             : {
     240           0 :     const char *psHeader = reinterpret_cast<const char *>(m_abyHeader);
     241             : 
     242           0 :     const double dfLLLat = JDEMGetAngle(psHeader + 29);
     243           0 :     const double dfLLLong = JDEMGetAngle(psHeader + 36);
     244           0 :     const double dfURLat = JDEMGetAngle(psHeader + 43);
     245           0 :     const double dfURLong = JDEMGetAngle(psHeader + 50);
     246             : 
     247           0 :     padfTransform[0] = dfLLLong;
     248           0 :     padfTransform[3] = dfURLat;
     249           0 :     padfTransform[1] = (dfURLong - dfLLLong) / GetRasterXSize();
     250           0 :     padfTransform[2] = 0.0;
     251             : 
     252           0 :     padfTransform[4] = 0.0;
     253           0 :     padfTransform[5] = -1 * (dfURLat - dfLLLat) / GetRasterYSize();
     254             : 
     255           0 :     return CE_None;
     256             : }
     257             : 
     258             : /************************************************************************/
     259             : /*                          GetSpatialRef()                             */
     260             : /************************************************************************/
     261             : 
     262           0 : const OGRSpatialReference *JDEMDataset::GetSpatialRef() const
     263             : 
     264             : {
     265           0 :     return &m_oSRS;
     266             : }
     267             : 
     268             : /************************************************************************/
     269             : /*                              Identify()                              */
     270             : /************************************************************************/
     271             : 
     272       52992 : int JDEMDataset::Identify(GDALOpenInfo *poOpenInfo)
     273             : 
     274             : {
     275       52992 :     if (poOpenInfo->nHeaderBytes < HEADER_SIZE)
     276       48755 :         return FALSE;
     277             : 
     278             :     // Confirm that the header has what appears to be dates in the
     279             :     // expected locations.
     280             :     // Check if century values seem reasonable.
     281        4237 :     const char *psHeader = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
     282        4237 :     if ((!STARTS_WITH_CI(psHeader + 11, "19") &&
     283        4233 :          !STARTS_WITH_CI(psHeader + 11, "20")) ||
     284           9 :         (!STARTS_WITH_CI(psHeader + 15, "19") &&
     285           5 :          !STARTS_WITH_CI(psHeader + 15, "20")) ||
     286           4 :         (!STARTS_WITH_CI(psHeader + 19, "19") &&
     287           0 :          !STARTS_WITH_CI(psHeader + 19, "20")))
     288             :     {
     289        4233 :         return FALSE;
     290             :     }
     291             : 
     292             :     // Check the extent too. In particular, that we are in the first quadrant,
     293             :     // as this is only for Japan.
     294           4 :     const double dfLLLat = JDEMGetAngle(psHeader + 29);
     295           4 :     const double dfLLLong = JDEMGetAngle(psHeader + 36);
     296           4 :     const double dfURLat = JDEMGetAngle(psHeader + 43);
     297           4 :     const double dfURLong = JDEMGetAngle(psHeader + 50);
     298           4 :     if (dfLLLat > 90 || dfLLLat < 0 || dfLLLong > 180 || dfLLLong < 0 ||
     299           4 :         dfURLat > 90 || dfURLat < 0 || dfURLong > 180 || dfURLong < 0 ||
     300           4 :         dfLLLat > dfURLat || dfLLLong > dfURLong)
     301             :     {
     302           0 :         return FALSE;
     303             :     }
     304             : 
     305           4 :     return TRUE;
     306             : }
     307             : 
     308             : /************************************************************************/
     309             : /*                                Open()                                */
     310             : /************************************************************************/
     311             : 
     312           2 : GDALDataset *JDEMDataset::Open(GDALOpenInfo *poOpenInfo)
     313             : 
     314             : {
     315             :     // Confirm that the header is compatible with a JDEM dataset.
     316           2 :     if (!Identify(poOpenInfo))
     317           0 :         return nullptr;
     318             : 
     319             :     // Confirm the requested access is supported.
     320           2 :     if (poOpenInfo->eAccess == GA_Update)
     321             :     {
     322           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     323             :                  "The JDEM driver does not support update access to existing "
     324             :                  "datasets.");
     325           0 :         return nullptr;
     326             :     }
     327             : 
     328             :     // Check that the file pointer from GDALOpenInfo* is available.
     329           2 :     if (poOpenInfo->fpL == nullptr)
     330             :     {
     331           0 :         return nullptr;
     332             :     }
     333             : 
     334             :     // Create a corresponding GDALDataset.
     335           4 :     auto poDS = std::make_unique<JDEMDataset>();
     336             : 
     337             :     // Borrow the file pointer from GDALOpenInfo*.
     338           2 :     std::swap(poDS->m_fp, poOpenInfo->fpL);
     339             : 
     340             :     // Store the header (we have already checked it is at least HEADER_SIZE
     341             :     // byte large).
     342           2 :     memcpy(poDS->m_abyHeader, poOpenInfo->pabyHeader, HEADER_SIZE);
     343             : 
     344           2 :     const char *psHeader = reinterpret_cast<const char *>(poDS->m_abyHeader);
     345           2 :     poDS->nRasterXSize = JDEMGetField(psHeader + 23, 3);
     346           2 :     poDS->nRasterYSize = JDEMGetField(psHeader + 26, 3);
     347           2 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     348             :     {
     349           0 :         return nullptr;
     350             :     }
     351             : 
     352             :     // Create band information objects.
     353           2 :     poDS->SetBand(1, new JDEMRasterBand(poDS.get(), 1));
     354             : 
     355             :     // Initialize any PAM information.
     356           2 :     poDS->SetDescription(poOpenInfo->pszFilename);
     357           2 :     poDS->TryLoadXML();
     358             : 
     359             :     // Check for overviews.
     360           2 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
     361             : 
     362           2 :     return poDS.release();
     363             : }
     364             : 
     365             : /************************************************************************/
     366             : /*                          GDALRegister_JDEM()                         */
     367             : /************************************************************************/
     368             : 
     369        1520 : void GDALRegister_JDEM()
     370             : 
     371             : {
     372        1520 :     if (GDALGetDriverByName("JDEM") != nullptr)
     373         301 :         return;
     374             : 
     375        1219 :     GDALDriver *poDriver = new GDALDriver();
     376             : 
     377        1219 :     poDriver->SetDescription("JDEM");
     378        1219 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     379        1219 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Japanese DEM (.mem)");
     380        1219 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/jdem.html");
     381        1219 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "mem");
     382        1219 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     383             : 
     384        1219 :     poDriver->pfnOpen = JDEMDataset::Open;
     385        1219 :     poDriver->pfnIdentify = JDEMDataset::Identify;
     386             : 
     387        1219 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     388             : }

Generated by: LCOV version 1.14