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

Generated by: LCOV version 1.14