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

Generated by: LCOV version 1.14