LCOV - code coverage report
Current view: top level - frmts/sigdem - sigdemdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 284 328 86.6 %
Date: 2025-10-13 21:15:08 Functions: 19 19 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:    Scaled Integer Gridded DEM .sigdem Driver
       4             :  * Purpose:    Implementation of Scaled Integer Gridded DEM
       5             :  * Author:     Paul Austin, paul.austin@revolsys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2018, Paul Austin <paul.austin@revolsys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "sigdemdataset.h"
      14             : #include "rawdataset.h"
      15             : 
      16             : #include "gdal_frmts.h"
      17             : #include "gdal_driver.h"
      18             : #include "gdal_drivermanager.h"
      19             : #include "gdal_openinfo.h"
      20             : #include "gdal_cpp_functions.h"
      21             : 
      22             : #include <algorithm>
      23             : #include <limits>
      24             : 
      25             : #ifdef CPL_IS_LSB
      26             : #define SWAP_SIGDEM_HEADER(abyHeader)                                          \
      27             :     {                                                                          \
      28             :         CPL_SWAP16PTR(abyHeader + 6);                                          \
      29             :         CPL_SWAP32PTR(abyHeader + 8);                                          \
      30             :         CPL_SWAP64PTR(abyHeader + 12);                                         \
      31             :         CPL_SWAP64PTR(abyHeader + 20);                                         \
      32             :         CPL_SWAP64PTR(abyHeader + 28);                                         \
      33             :         CPL_SWAP64PTR(abyHeader + 36);                                         \
      34             :         CPL_SWAP64PTR(abyHeader + 44);                                         \
      35             :         CPL_SWAP64PTR(abyHeader + 52);                                         \
      36             :         CPL_SWAP64PTR(abyHeader + 60);                                         \
      37             :         CPL_SWAP64PTR(abyHeader + 68);                                         \
      38             :         CPL_SWAP64PTR(abyHeader + 76);                                         \
      39             :         CPL_SWAP64PTR(abyHeader + 84);                                         \
      40             :         CPL_SWAP64PTR(abyHeader + 92);                                         \
      41             :         CPL_SWAP64PTR(abyHeader + 100);                                        \
      42             :         CPL_SWAP32PTR(abyHeader + 108);                                        \
      43             :         CPL_SWAP32PTR(abyHeader + 112);                                        \
      44             :         CPL_SWAP64PTR(abyHeader + 116);                                        \
      45             :         CPL_SWAP64PTR(abyHeader + 124);                                        \
      46             :     }
      47             : #else
      48             : #define SWAP_SIGDEM_HEADER(abyHeader)
      49             : #endif
      50             : 
      51             : constexpr int CELL_SIZE_FILE = 4;
      52             : 
      53             : constexpr int CELL_SIZE_MEM = 8;
      54             : 
      55             : constexpr vsi_l_offset HEADER_LENGTH = 132;
      56             : 
      57             : constexpr int32_t NO_DATA = 0x80000000;
      58             : 
      59             : constexpr char SIGDEM_FILE_TYPE[6] = {'S', 'I', 'G', 'D', 'E', 'M'};
      60             : 
      61          24 : static OGRSpatialReference *BuildSRS(const char *pszWKT)
      62             : {
      63          24 :     OGRSpatialReference *poSRS = new OGRSpatialReference();
      64          24 :     if (poSRS->importFromWkt(pszWKT) != OGRERR_NONE)
      65             :     {
      66           0 :         delete poSRS;
      67           0 :         return nullptr;
      68             :     }
      69             :     else
      70             :     {
      71          24 :         if (poSRS->AutoIdentifyEPSG() != OGRERR_NONE)
      72             :         {
      73          22 :             auto poSRSMatch = poSRS->FindBestMatch(100);
      74          22 :             if (poSRSMatch)
      75             :             {
      76           1 :                 poSRS->Release();
      77           1 :                 poSRS = poSRSMatch;
      78           1 :                 poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      79             :             }
      80             :         }
      81          24 :         return poSRS;
      82             :     }
      83             : }
      84             : 
      85        2033 : void GDALRegister_SIGDEM()
      86             : {
      87        2033 :     if (GDALGetDriverByName("SIGDEM") == nullptr)
      88             :     {
      89        1750 :         GDALDriver *poDriver = new GDALDriver();
      90             : 
      91        1750 :         poDriver->SetDescription("SIGDEM");
      92        1750 :         poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
      93        1750 :         poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
      94        1750 :                                   "Scaled Integer Gridded DEM .sigdem");
      95        1750 :         poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
      96        1750 :                                   "drivers/raster/sigdem.html");
      97        1750 :         poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "sigdem");
      98             : 
      99        1750 :         poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     100        1750 :         poDriver->pfnCreateCopy = SIGDEMDataset::CreateCopy;
     101        1750 :         poDriver->pfnIdentify = SIGDEMDataset::Identify;
     102        1750 :         poDriver->pfnOpen = SIGDEMDataset::Open;
     103             : 
     104        1750 :         GetGDALDriverManager()->RegisterDriver(poDriver);
     105             :     }
     106        2033 : }
     107             : 
     108          24 : static int32_t GetCoordinateSystemId(const char *pszProjection)
     109             : {
     110          24 :     int32_t coordinateSystemId = 0;
     111          24 :     OGRSpatialReference *poSRS = BuildSRS(pszProjection);
     112          24 :     if (poSRS != nullptr)
     113             :     {
     114          48 :         std::string pszRoot;
     115          24 :         if (poSRS->IsProjected())
     116             :         {
     117           3 :             pszRoot = "PROJCS";
     118             :         }
     119             :         else
     120             :         {
     121          21 :             pszRoot = "GEOCS";
     122             :         }
     123          24 :         const char *pszAuthName = poSRS->GetAuthorityName(pszRoot.c_str());
     124          24 :         const char *pszAuthCode = poSRS->GetAuthorityCode(pszRoot.c_str());
     125          24 :         if (pszAuthName != nullptr && EQUAL(pszAuthName, "EPSG") &&
     126             :             pszAuthCode != nullptr)
     127             :         {
     128           3 :             coordinateSystemId = atoi(pszAuthCode);
     129             :         }
     130             :     }
     131          24 :     delete poSRS;
     132          24 :     return coordinateSystemId;
     133             : }
     134             : 
     135          20 : SIGDEMDataset::SIGDEMDataset(const SIGDEMHeader &sHeaderIn)
     136          20 :     : fpImage(nullptr), sHeader(sHeaderIn)
     137             : {
     138          20 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     139          20 :     this->nRasterXSize = sHeader.nCols;
     140          20 :     this->nRasterYSize = sHeader.nRows;
     141             : 
     142          20 :     m_gt[0] = sHeader.dfMinX;
     143          20 :     m_gt[1] = sHeader.dfXDim;
     144          20 :     m_gt[2] = 0.0;
     145          20 :     m_gt[3] = sHeader.dfMaxY;
     146          20 :     m_gt[4] = 0.0;
     147          20 :     m_gt[5] = -sHeader.dfYDim;
     148          20 : }
     149             : 
     150          40 : SIGDEMDataset::~SIGDEMDataset()
     151             : {
     152          20 :     FlushCache(true);
     153             : 
     154          20 :     if (fpImage != nullptr)
     155             :     {
     156          20 :         if (VSIFCloseL(fpImage) != 0)
     157             :         {
     158           0 :             CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     159             :         }
     160             :     }
     161          40 : }
     162             : 
     163          32 : GDALDataset *SIGDEMDataset::CreateCopy(const char *pszFilename,
     164             :                                        GDALDataset *poSrcDS, int /*bStrict*/,
     165             :                                        char ** /*papszOptions*/,
     166             :                                        GDALProgressFunc pfnProgress,
     167             :                                        void *pProgressData)
     168             : {
     169          32 :     const int nBands = poSrcDS->GetRasterCount();
     170          32 :     GDALGeoTransform gt;
     171          32 :     if (poSrcDS->GetGeoTransform(gt) != CE_None)
     172             :     {
     173           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     174             :                  "SIGDEM driver requires a valid GeoTransform.");
     175           0 :         return nullptr;
     176             :     }
     177             : 
     178          32 :     if (nBands != 1)
     179             :     {
     180           5 :         CPLError(CE_Failure, CPLE_NotSupported,
     181             :                  "SIGDEM driver doesn't support %d bands.  Must be 1 band.",
     182             :                  nBands);
     183           5 :         return nullptr;
     184             :     }
     185             : 
     186          27 :     VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
     187          27 :     if (fp == nullptr)
     188             :     {
     189           3 :         CPLError(CE_Failure, CPLE_OpenFailed,
     190             :                  "Attempt to create file `%s' failed.", pszFilename);
     191           3 :         return nullptr;
     192             :     }
     193             : 
     194          24 :     GDALRasterBand *band = poSrcDS->GetRasterBand(1);
     195          24 :     const char *pszProjection = poSrcDS->GetProjectionRef();
     196             : 
     197          24 :     int32_t nCols = poSrcDS->GetRasterXSize();
     198          24 :     int32_t nRows = poSrcDS->GetRasterYSize();
     199          24 :     int32_t nCoordinateSystemId = GetCoordinateSystemId(pszProjection);
     200             : 
     201          24 :     SIGDEMHeader sHeader;
     202          24 :     sHeader.nCoordinateSystemId = nCoordinateSystemId;
     203          24 :     sHeader.dfMinX = gt[0];
     204          24 :     const char *pszMin = band->GetMetadataItem("STATISTICS_MINIMUM");
     205          24 :     if (pszMin == nullptr)
     206             :     {
     207           3 :         sHeader.dfMinZ = -10000;
     208             :     }
     209             :     else
     210             :     {
     211          21 :         sHeader.dfMinZ = CPLAtof(pszMin);
     212             :     }
     213          24 :     sHeader.dfMaxY = gt[3];
     214          24 :     const char *pszMax = band->GetMetadataItem("STATISTICS_MAXIMUM");
     215          24 :     if (pszMax == nullptr)
     216             :     {
     217           3 :         sHeader.dfMaxZ = 10000;
     218             :     }
     219             :     else
     220             :     {
     221          21 :         sHeader.dfMaxZ = CPLAtof(pszMax);
     222             :     }
     223          24 :     sHeader.nCols = poSrcDS->GetRasterXSize();
     224          24 :     sHeader.nRows = poSrcDS->GetRasterYSize();
     225          24 :     sHeader.dfXDim = gt[1];
     226          24 :     sHeader.dfYDim = -gt[5];
     227          24 :     sHeader.dfMaxX = sHeader.dfMinX + sHeader.nCols * sHeader.dfXDim;
     228          24 :     sHeader.dfMinY = sHeader.dfMaxY - sHeader.nRows * sHeader.dfYDim;
     229          24 :     sHeader.dfOffsetX = sHeader.dfMinX;
     230          24 :     sHeader.dfOffsetY = sHeader.dfMinY;
     231             : 
     232          24 :     if (!sHeader.Write(fp))
     233             :     {
     234           3 :         VSIUnlink(pszFilename);
     235           3 :         VSIFCloseL(fp);
     236           3 :         return nullptr;
     237             :     }
     238             : 
     239             :     // Write fill with all NO_DATA values
     240             :     int32_t *row =
     241          21 :         static_cast<int32_t *>(VSI_MALLOC2_VERBOSE(nCols, sizeof(int32_t)));
     242          21 :     if (!row)
     243             :     {
     244           0 :         VSIUnlink(pszFilename);
     245           0 :         VSIFCloseL(fp);
     246           0 :         return nullptr;
     247             :     }
     248          21 :     std::fill(row, row + nCols, CPL_MSBWORD32(NO_DATA));
     249         236 :     for (int i = 0; i < nRows; i++)
     250             :     {
     251         222 :         if (VSIFWriteL(row, CELL_SIZE_FILE, nCols, fp) !=
     252         222 :             static_cast<size_t>(nCols))
     253             :         {
     254           7 :             VSIFree(row);
     255           7 :             VSIUnlink(pszFilename);
     256           7 :             VSIFCloseL(fp);
     257           7 :             return nullptr;
     258             :         }
     259             :     }
     260          14 :     VSIFree(row);
     261             : 
     262          14 :     if (VSIFCloseL(fp) != 0)
     263             :     {
     264           0 :         return nullptr;
     265             :     }
     266             : 
     267          14 :     if (nCoordinateSystemId <= 0)
     268             :     {
     269          11 :         if (!EQUAL(pszProjection, ""))
     270             :         {
     271             :             const CPLString osPrjFilename =
     272          22 :                 CPLResetExtensionSafe(pszFilename, "prj");
     273          11 :             VSILFILE *fpProj = VSIFOpenL(osPrjFilename, "wt");
     274          11 :             if (fpProj != nullptr)
     275             :             {
     276          22 :                 OGRSpatialReference oSRS;
     277          11 :                 oSRS.importFromWkt(pszProjection);
     278          11 :                 oSRS.morphToESRI();
     279          11 :                 char *pszESRIProjection = nullptr;
     280          11 :                 oSRS.exportToWkt(&pszESRIProjection);
     281          11 :                 CPL_IGNORE_RET_VAL(VSIFWriteL(
     282             :                     pszESRIProjection, 1, strlen(pszESRIProjection), fpProj));
     283             : 
     284          11 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(fpProj));
     285          11 :                 CPLFree(pszESRIProjection);
     286             :             }
     287             :             else
     288             :             {
     289           0 :                 CPLError(CE_Failure, CPLE_FileIO, "Unable to create file %s.",
     290             :                          osPrjFilename.c_str());
     291             :             }
     292             :         }
     293             :     }
     294          28 :     GDALOpenInfo oOpenInfo(pszFilename, GA_Update);
     295          14 :     GDALDataset *poDstDS = Open(&oOpenInfo);
     296          28 :     if (poDstDS != nullptr &&
     297          14 :         GDALDatasetCopyWholeRaster(poSrcDS, poDstDS, nullptr, pfnProgress,
     298             :                                    pProgressData) == OGRERR_NONE)
     299             :     {
     300          14 :         return poDstDS;
     301             :     }
     302             :     else
     303             :     {
     304           0 :         VSIUnlink(pszFilename);
     305           0 :         return nullptr;
     306             :     }
     307             : }
     308             : 
     309           2 : CPLErr SIGDEMDataset::GetGeoTransform(GDALGeoTransform &gt) const
     310             : {
     311           2 :     gt = m_gt;
     312           2 :     return CE_None;
     313             : }
     314             : 
     315           2 : const OGRSpatialReference *SIGDEMDataset::GetSpatialRef() const
     316             : {
     317           2 :     return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
     318             : }
     319             : 
     320       58119 : int SIGDEMDataset::Identify(GDALOpenInfo *poOpenInfo)
     321             : {
     322       58119 :     if (poOpenInfo->nHeaderBytes < static_cast<int>(HEADER_LENGTH))
     323             :     {
     324       55161 :         return FALSE;
     325             :     }
     326        2958 :     return memcmp(poOpenInfo->pabyHeader, SIGDEM_FILE_TYPE,
     327        2958 :                   sizeof(SIGDEM_FILE_TYPE)) == 0;
     328             : }
     329             : 
     330          20 : GDALDataset *SIGDEMDataset::Open(GDALOpenInfo *poOpenInfo)
     331             : {
     332          20 :     VSILFILE *fp = poOpenInfo->fpL;
     333             : 
     334          20 :     SIGDEMHeader sHeader;
     335          20 :     if (SIGDEMDataset::Identify(poOpenInfo) != TRUE || fp == nullptr)
     336             :     {
     337           0 :         return nullptr;
     338             :     }
     339             : 
     340          20 :     sHeader.Read(poOpenInfo->pabyHeader);
     341             : 
     342          20 :     if (!GDALCheckDatasetDimensions(sHeader.nCols, sHeader.nRows))
     343             :     {
     344           0 :         return nullptr;
     345             :     }
     346             : 
     347          40 :     OGRSpatialReference oSRS;
     348          20 :     oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     349             : 
     350          20 :     if (sHeader.nCoordinateSystemId > 0)
     351             :     {
     352           9 :         if (oSRS.importFromEPSG(sHeader.nCoordinateSystemId) != OGRERR_NONE)
     353             :         {
     354           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     355             :                      "SIGDEM unable to find coordinateSystemId=%d.",
     356             :                      sHeader.nCoordinateSystemId);
     357           0 :             return nullptr;
     358             :         }
     359             :     }
     360             :     else
     361             :     {
     362             :         CPLString osPrjFilename =
     363          11 :             CPLResetExtensionSafe(poOpenInfo->pszFilename, "prj");
     364             :         VSIStatBufL sStatBuf;
     365          11 :         int nRet = VSIStatL(osPrjFilename, &sStatBuf);
     366          11 :         if (nRet != 0 && VSIIsCaseSensitiveFS(osPrjFilename))
     367             :         {
     368             :             osPrjFilename =
     369           0 :                 CPLResetExtensionSafe(poOpenInfo->pszFilename, "PRJ");
     370           0 :             nRet = VSIStatL(osPrjFilename, &sStatBuf);
     371             :         }
     372             : 
     373          11 :         if (nRet == 0)
     374             :         {
     375          11 :             char **papszPrj = CSLLoad(osPrjFilename);
     376          11 :             if (oSRS.importFromESRI(papszPrj) != OGRERR_NONE)
     377             :             {
     378           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     379             :                          "SIGDEM unable to read projection from %s.",
     380             :                          osPrjFilename.c_str());
     381           0 :                 CSLDestroy(papszPrj);
     382           0 :                 return nullptr;
     383             :             }
     384          11 :             CSLDestroy(papszPrj);
     385             :         }
     386             :         else
     387             :         {
     388           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     389             :                      "SIGDEM unable to find projection.");
     390           0 :             return nullptr;
     391             :         }
     392             :     }
     393             : 
     394          20 :     if (sHeader.nCols > std::numeric_limits<int>::max() / (CELL_SIZE_MEM))
     395             :     {
     396           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Int overflow occurred.");
     397           0 :         return nullptr;
     398             :     }
     399             : 
     400          20 :     if (!RAWDatasetCheckMemoryUsage(sHeader.nCols, sHeader.nRows, 1, 4, 4,
     401          20 :                                     4 * sHeader.nCols, 0, 0, poOpenInfo->fpL))
     402             :     {
     403           0 :         return nullptr;
     404             :     }
     405          20 :     SIGDEMDataset *poDS = new SIGDEMDataset(sHeader);
     406             : 
     407          20 :     poDS->m_oSRS = std::move(oSRS);
     408             : 
     409          20 :     poDS->fpImage = poOpenInfo->fpL;
     410          20 :     poOpenInfo->fpL = nullptr;
     411          20 :     poDS->eAccess = poOpenInfo->eAccess;
     412             : 
     413          20 :     poDS->SetDescription(poOpenInfo->pszFilename);
     414          20 :     poDS->PamInitialize();
     415             : 
     416          20 :     poDS->nBands = 1;
     417          20 :     CPLErrorReset();
     418             :     SIGDEMRasterBand *poBand = new SIGDEMRasterBand(
     419          20 :         poDS, poDS->fpImage, sHeader.dfMinZ, sHeader.dfMaxZ);
     420             : 
     421          20 :     poDS->SetBand(1, poBand);
     422          20 :     if (CPLGetLastErrorType() != CE_None)
     423             :     {
     424           0 :         poDS->nBands = 1;
     425           0 :         delete poDS;
     426           0 :         return nullptr;
     427             :     }
     428             : 
     429             :     // Initialize any PAM information.
     430          20 :     poDS->TryLoadXML();
     431             : 
     432             :     // Check for overviews.
     433          20 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
     434             : 
     435          20 :     return poDS;
     436             : }
     437             : 
     438          44 : SIGDEMHeader::SIGDEMHeader()
     439             : {
     440          44 : }
     441             : 
     442          20 : bool SIGDEMHeader::Read(const GByte *pabyHeader)
     443             : {
     444             :     GByte abyHeader[HEADER_LENGTH];
     445          20 :     memcpy(abyHeader, pabyHeader, HEADER_LENGTH);
     446             : 
     447          20 :     SWAP_SIGDEM_HEADER(abyHeader);
     448          20 :     memcpy(&(this->version), abyHeader + 6, 2);
     449          20 :     memcpy(&(this->nCoordinateSystemId), abyHeader + 8, 4);
     450          20 :     memcpy(&(this->dfOffsetX), abyHeader + 12, 8);
     451          20 :     memcpy(&(this->dfScaleFactorX), abyHeader + 20, 8);
     452          20 :     memcpy(&(this->dfOffsetY), abyHeader + 28, 8);
     453          20 :     memcpy(&(this->dfScaleFactorY), abyHeader + 36, 8);
     454          20 :     memcpy(&(this->dfOffsetZ), abyHeader + 44, 8);
     455          20 :     memcpy(&(this->dfScaleFactorZ), abyHeader + 52, 8);
     456          20 :     memcpy(&(this->dfMinX), abyHeader + 60, 8);
     457          20 :     memcpy(&(this->dfMinY), abyHeader + 68, 8);
     458          20 :     memcpy(&(this->dfMinZ), abyHeader + 76, 8);
     459          20 :     memcpy(&(this->dfMaxX), abyHeader + 84, 8);
     460          20 :     memcpy(&(this->dfMaxY), abyHeader + 92, 8);
     461          20 :     memcpy(&(this->dfMaxZ), abyHeader + 100, 8);
     462          20 :     memcpy(&(this->nCols), abyHeader + 108, 4);
     463          20 :     memcpy(&(this->nRows), abyHeader + 112, 4);
     464          20 :     memcpy(&(this->dfXDim), abyHeader + 116, 8);
     465          20 :     memcpy(&(this->dfYDim), abyHeader + 124, 8);
     466             : 
     467          20 :     return true;
     468             : }
     469             : 
     470          24 : bool SIGDEMHeader::Write(VSILFILE *fp)
     471             : {
     472             :     GByte abyHeader[HEADER_LENGTH];
     473             : 
     474          24 :     memcpy(abyHeader, &(SIGDEM_FILE_TYPE), 6);
     475          24 :     memcpy(abyHeader + 6, &(this->version), 2);
     476          24 :     memcpy(abyHeader + 8, &(this->nCoordinateSystemId), 4);
     477          24 :     memcpy(abyHeader + 12, &(this->dfOffsetX), 8);
     478          24 :     memcpy(abyHeader + 20, &(this->dfScaleFactorX), 8);
     479          24 :     memcpy(abyHeader + 28, &(this->dfOffsetY), 8);
     480          24 :     memcpy(abyHeader + 36, &(this->dfScaleFactorY), 8);
     481          24 :     memcpy(abyHeader + 44, &(this->dfOffsetZ), 8);
     482          24 :     memcpy(abyHeader + 52, &(this->dfScaleFactorZ), 8);
     483          24 :     memcpy(abyHeader + 60, &(this->dfMinX), 8);
     484          24 :     memcpy(abyHeader + 68, &(this->dfMinY), 8);
     485          24 :     memcpy(abyHeader + 76, &(this->dfMinZ), 8);
     486          24 :     memcpy(abyHeader + 84, &(this->dfMaxX), 8);
     487          24 :     memcpy(abyHeader + 92, &(this->dfMaxY), 8);
     488          24 :     memcpy(abyHeader + 100, &(this->dfMaxZ), 8);
     489          24 :     memcpy(abyHeader + 108, &(this->nCols), 4);
     490          24 :     memcpy(abyHeader + 112, &(this->nRows), 4);
     491          24 :     memcpy(abyHeader + 116, &(this->dfXDim), 8);
     492          24 :     memcpy(abyHeader + 124, &(this->dfYDim), 8);
     493          24 :     SWAP_SIGDEM_HEADER(abyHeader);
     494          24 :     return VSIFWriteL(&abyHeader, HEADER_LENGTH, 1, fp) == 1;
     495             : }
     496             : 
     497          20 : SIGDEMRasterBand::SIGDEMRasterBand(SIGDEMDataset *poDSIn, VSILFILE *fpRawIn,
     498          20 :                                    double dfMinZ, double dfMaxZ)
     499          20 :     : dfOffsetZ(poDSIn->sHeader.dfOffsetZ),
     500          20 :       dfScaleFactorZ(poDSIn->sHeader.dfScaleFactorZ), fpRawL(fpRawIn)
     501             : {
     502          20 :     this->poDS = poDSIn;
     503          20 :     this->nBand = 1;
     504          20 :     this->nRasterXSize = poDSIn->GetRasterXSize();
     505          20 :     this->nRasterYSize = poDSIn->GetRasterYSize();
     506          20 :     this->nBlockXSize = this->nRasterXSize;
     507          20 :     this->nBlockYSize = 1;
     508          20 :     this->eDataType = GDT_Float64;
     509             : 
     510          20 :     this->nBlockSizeBytes = nRasterXSize * CELL_SIZE_FILE;
     511             : 
     512          20 :     this->pBlockBuffer = static_cast<int32_t *>(
     513          20 :         VSI_MALLOC2_VERBOSE(nRasterXSize, sizeof(int32_t)));
     514          20 :     SetNoDataValue(-9999);
     515          40 :     CPLString osValue;
     516          20 :     SetMetadataItem("STATISTICS_MINIMUM", osValue.Printf("%.15g", dfMinZ));
     517          20 :     SetMetadataItem("STATISTICS_MAXIMUM", osValue.Printf("%.15g", dfMaxZ));
     518          20 : }
     519             : 
     520          75 : CPLErr SIGDEMRasterBand::IReadBlock(int /*nBlockXOff*/, int nBlockYOff,
     521             :                                     void *pImage)
     522             : {
     523             : 
     524          75 :     const int nBlockIndex = nRasterYSize - nBlockYOff - 1;
     525             : 
     526          75 :     if (nLoadedBlockIndex == nBlockIndex)
     527             :     {
     528           0 :         return CE_None;
     529             :     }
     530          75 :     const vsi_l_offset nReadStart =
     531             :         HEADER_LENGTH +
     532          75 :         static_cast<vsi_l_offset>(nBlockSizeBytes) * nBlockIndex;
     533             : 
     534             :     // Seek to the correct line.
     535          75 :     if (VSIFSeekL(fpRawL, nReadStart, SEEK_SET) == -1)
     536             :     {
     537           0 :         if (poDS != nullptr && poDS->GetAccess() == GA_ReadOnly)
     538             :         {
     539           0 :             CPLError(CE_Failure, CPLE_FileIO,
     540             :                      "Failed to seek to block %d @ " CPL_FRMT_GUIB ".",
     541             :                      nBlockIndex, nReadStart);
     542           0 :             return CE_Failure;
     543             :         }
     544             :         else
     545             :         {
     546           0 :             std::fill(pBlockBuffer, pBlockBuffer + nRasterXSize, 0);
     547           0 :             nLoadedBlockIndex = nBlockIndex;
     548           0 :             return CE_None;
     549             :         }
     550             :     }
     551             :     const size_t nCellReadCount =
     552          75 :         VSIFReadL(pBlockBuffer, CELL_SIZE_FILE, nRasterXSize, fpRawL);
     553          75 :     if (nCellReadCount < static_cast<size_t>(nRasterXSize))
     554             :     {
     555           0 :         if (poDS != nullptr && poDS->GetAccess() == GA_ReadOnly)
     556             :         {
     557           0 :             CPLError(CE_Failure, CPLE_FileIO, "Failed to read block %d.",
     558             :                      nBlockIndex);
     559           0 :             return CE_Failure;
     560             :         }
     561           0 :         std::fill(pBlockBuffer + nCellReadCount, pBlockBuffer + nRasterXSize,
     562             :                   NO_DATA);
     563             :     }
     564             : 
     565          75 :     nLoadedBlockIndex = nBlockIndex;
     566             : 
     567          75 :     const int32_t *pnSourceValues = pBlockBuffer;
     568          75 :     double *padfDestValues = static_cast<double *>(pImage);
     569          75 :     double dfOffset = this->dfOffsetZ;
     570          75 :     const double dfInvScaleFactor =
     571          75 :         dfScaleFactorZ != 0.0 ? 1.0 / dfScaleFactorZ : 0.0;
     572          75 :     int nCellCount = this->nRasterXSize;
     573        1960 :     for (int i = 0; i < nCellCount; i++)
     574             :     {
     575        1885 :         int32_t nValue = CPL_MSBWORD32(*pnSourceValues);
     576        1885 :         if (nValue == NO_DATA)
     577             :         {
     578           0 :             *padfDestValues = -9999;
     579             :         }
     580             :         else
     581             :         {
     582        1885 :             *padfDestValues = dfOffset + nValue * dfInvScaleFactor;
     583             :         }
     584             : 
     585        1885 :         pnSourceValues++;
     586        1885 :         padfDestValues++;
     587             :     }
     588             : 
     589          75 :     return CE_None;
     590             : }
     591             : 
     592         185 : CPLErr SIGDEMRasterBand::IWriteBlock(int /*nBlockXOff*/, int nBlockYOff,
     593             :                                      void *pImage)
     594             : {
     595             : 
     596         185 :     const int nBlockIndex = nRasterYSize - nBlockYOff - 1;
     597             : 
     598         185 :     const double *padfSourceValues = static_cast<double *>(pImage);
     599         185 :     int32_t *pnDestValues = pBlockBuffer;
     600         185 :     double dfOffset = this->dfOffsetZ;
     601         185 :     double dfScaleFactor = this->dfScaleFactorZ;
     602         185 :     int nCellCount = this->nRasterXSize;
     603        3170 :     for (int i = 0; i < nCellCount; i++)
     604             :     {
     605        2985 :         double dfValue = *padfSourceValues;
     606             :         int32_t nValue;
     607        2985 :         if (dfValue == -9999)
     608             :         {
     609           0 :             nValue = NO_DATA;
     610             :         }
     611             :         else
     612             :         {
     613        2985 :             nValue = static_cast<int32_t>(
     614        2985 :                 std::round((dfValue - dfOffset) * dfScaleFactor));
     615             :         }
     616        2985 :         *pnDestValues = CPL_MSBWORD32(nValue);
     617        2985 :         padfSourceValues++;
     618        2985 :         pnDestValues++;
     619             :     }
     620             : 
     621         185 :     const vsi_l_offset nWriteStart =
     622             :         HEADER_LENGTH +
     623         185 :         static_cast<vsi_l_offset>(nBlockSizeBytes) * nBlockIndex;
     624             : 
     625         370 :     if (VSIFSeekL(fpRawL, nWriteStart, SEEK_SET) == -1 ||
     626         185 :         VSIFWriteL(pBlockBuffer, CELL_SIZE_FILE, nRasterXSize, fpRawL) <
     627         185 :             static_cast<size_t>(nRasterXSize))
     628             :     {
     629           0 :         CPLError(CE_Failure, CPLE_FileIO, "Failed to write block %d to file.",
     630             :                  nBlockIndex);
     631             : 
     632           0 :         return CE_Failure;
     633             :     }
     634         185 :     return CE_None;
     635             : }
     636             : 
     637          40 : SIGDEMRasterBand::~SIGDEMRasterBand()
     638             : {
     639          20 :     SIGDEMRasterBand::FlushCache(true);
     640          20 :     VSIFree(pBlockBuffer);
     641          40 : }

Generated by: LCOV version 1.14