LCOV - code coverage report
Current view: top level - alg - gdalchecksum.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 148 175 84.6 %
Date: 2025-02-20 10:14:44 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Compute simple checksum for a region of image data.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2003, Frank Warmerdam
       9             :  * Copyright (c) 2007-2008, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "gdal_alg.h"
      16             : 
      17             : #include <cmath>
      18             : #include <cstddef>
      19             : #include <algorithm>
      20             : 
      21             : #include "cpl_conv.h"
      22             : #include "cpl_error.h"
      23             : #include "cpl_vsi.h"
      24             : #include "gdal.h"
      25             : #include "gdal_priv.h"
      26             : 
      27             : /************************************************************************/
      28             : /*                         GDALChecksumImage()                          */
      29             : /************************************************************************/
      30             : 
      31             : /**
      32             :  * Compute checksum for image region.
      33             :  *
      34             :  * Computes a 16bit (0-65535) checksum from a region of raster data on a GDAL
      35             :  * supported band.   Floating point data is converted to 32bit integer
      36             :  * so decimal portions of such raster data will not affect the checksum.
      37             :  * Real and Imaginary components of complex bands influence the result.
      38             :  *
      39             :  * @param hBand the raster band to read from.
      40             :  * @param nXOff pixel offset of window to read.
      41             :  * @param nYOff line offset of window to read.
      42             :  * @param nXSize pixel size of window to read.
      43             :  * @param nYSize line size of window to read.
      44             :  *
      45             :  * @return Checksum value, or -1 in case of error (starting with GDAL 3.6)
      46             :  */
      47             : 
      48       38432 : int CPL_STDCALL GDALChecksumImage(GDALRasterBandH hBand, int nXOff, int nYOff,
      49             :                                   int nXSize, int nYSize)
      50             : 
      51             : {
      52       38432 :     VALIDATE_POINTER1(hBand, "GDALChecksumImage", 0);
      53             : 
      54             :     const static int anPrimes[11] = {7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43};
      55             : 
      56       38432 :     int nChecksum = 0;
      57       38432 :     int iPrime = 0;
      58       38432 :     const GDALDataType eDataType = GDALGetRasterDataType(hBand);
      59       38432 :     const bool bComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eDataType));
      60       38432 :     const bool bIsFloatingPoint =
      61       38431 :         (eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
      62       37492 :          eDataType == GDT_Float64 || eDataType == GDT_CFloat16 ||
      63       76863 :          eDataType == GDT_CFloat32 || eDataType == GDT_CFloat64);
      64             : 
      65    75309700 :     const auto IntFromDouble = [](double dfVal)
      66             :     {
      67             :         int nVal;
      68    75309700 :         if (!std::isfinite(dfVal))
      69             :         {
      70       18029 :             nVal = INT_MIN;
      71             :         }
      72             :         else
      73             :         {
      74             :             // Standard behavior of GDALCopyWords when converting
      75             :             // from floating point to Int32.
      76    75291700 :             dfVal += 0.5;
      77             : 
      78    75291700 :             if (dfVal < -2147483647.0)
      79        1215 :                 nVal = -2147483647;
      80    75290500 :             else if (dfVal > 2147483647)
      81        2690 :                 nVal = 2147483647;
      82             :             else
      83    75287800 :                 nVal = static_cast<GInt32>(floor(dfVal));
      84             :         }
      85    75309700 :         return nVal;
      86             :     };
      87             : 
      88       38432 :     if (bIsFloatingPoint && nXOff == 0 && nYOff == 0)
      89             :     {
      90        1092 :         const GDALDataType eDstDataType = bComplex ? GDT_CFloat64 : GDT_Float64;
      91        1092 :         int nBlockXSize = 0;
      92        1092 :         int nBlockYSize = 0;
      93        1092 :         GDALGetBlockSize(hBand, &nBlockXSize, &nBlockYSize);
      94        1092 :         const int nDstDataTypeSize = GDALGetDataTypeSizeBytes(eDstDataType);
      95        1092 :         int nChunkXSize = nBlockXSize;
      96        1092 :         const int nChunkYSize = nBlockYSize;
      97        1092 :         if (nBlockXSize < nXSize)
      98             :         {
      99             :             const GIntBig nMaxChunkSize =
     100          96 :                 std::max(static_cast<GIntBig>(10 * 1000 * 1000),
     101          48 :                          GDALGetCacheMax64() / 10);
     102          48 :             if (nDstDataTypeSize > 0 &&
     103          48 :                 static_cast<GIntBig>(nXSize) * nChunkYSize <
     104          48 :                     nMaxChunkSize / nDstDataTypeSize)
     105             :             {
     106             :                 // A full line of height nChunkYSize can fit in the maximum
     107             :                 // allowed memory
     108          48 :                 nChunkXSize = nXSize;
     109             :             }
     110             :             else
     111             :             {
     112             :                 // Otherwise compute a size that is a multiple of nBlockXSize
     113           0 :                 nChunkXSize = static_cast<int>(std::min(
     114           0 :                     static_cast<GIntBig>(nXSize),
     115           0 :                     nBlockXSize *
     116           0 :                         std::max(static_cast<GIntBig>(1),
     117           0 :                                  nMaxChunkSize /
     118           0 :                                      (static_cast<GIntBig>(nBlockXSize) *
     119           0 :                                       nChunkYSize * nDstDataTypeSize))));
     120             :             }
     121             :         }
     122             : 
     123             :         double *padfLineData = static_cast<double *>(
     124        1092 :             VSI_MALLOC3_VERBOSE(nChunkXSize, nChunkYSize, nDstDataTypeSize));
     125        1092 :         if (padfLineData == nullptr)
     126             :         {
     127           0 :             return -1;
     128             :         }
     129        1092 :         const int nValsPerIter = bComplex ? 2 : 1;
     130             : 
     131        1092 :         const int nYBlocks = DIV_ROUND_UP(nYSize, nChunkYSize);
     132        1092 :         const int nXBlocks = DIV_ROUND_UP(nXSize, nChunkXSize);
     133       27133 :         for (int iYBlock = 0; iYBlock < nYBlocks; ++iYBlock)
     134             :         {
     135       26041 :             const int iYStart = iYBlock * nChunkYSize;
     136       26041 :             const int iYEnd =
     137       26041 :                 iYBlock == nYBlocks - 1 ? nYSize : iYStart + nChunkYSize;
     138       26041 :             const int nChunkActualHeight = iYEnd - iYStart;
     139       52079 :             for (int iXBlock = 0; iXBlock < nXBlocks; ++iXBlock)
     140             :             {
     141       26041 :                 const int iXStart = iXBlock * nChunkXSize;
     142       26041 :                 const int iXEnd =
     143       26041 :                     iXBlock == nXBlocks - 1 ? nXSize : iXStart + nChunkXSize;
     144       26041 :                 const int nChunkActualXSize = iXEnd - iXStart;
     145       26041 :                 if (GDALRasterIO(
     146             :                         hBand, GF_Read, iXStart, iYStart, nChunkActualXSize,
     147             :                         nChunkActualHeight, padfLineData, nChunkActualXSize,
     148       26041 :                         nChunkActualHeight, eDstDataType, 0, 0) != CE_None)
     149             :                 {
     150           3 :                     CPLError(CE_Failure, CPLE_FileIO,
     151             :                              "Checksum value could not be computed due to I/O "
     152             :                              "read error.");
     153           3 :                     nChecksum = -1;
     154           3 :                     iYBlock = nYBlocks;
     155           3 :                     break;
     156             :                 }
     157       26038 :                 const size_t xIters =
     158       26038 :                     static_cast<size_t>(nValsPerIter) * nChunkActualXSize;
     159       78663 :                 for (int iY = iYStart; iY < iYEnd; ++iY)
     160             :                 {
     161             :                     // Initialize iPrime so that it is consistent with a
     162             :                     // per full line iteration strategy
     163       52625 :                     iPrime = (nValsPerIter *
     164       52625 :                               (static_cast<int64_t>(iY) * nXSize + iXStart)) %
     165             :                              11;
     166       52625 :                     const size_t nOffset = nValsPerIter *
     167       52625 :                                            static_cast<size_t>(iY - iYStart) *
     168       52625 :                                            nChunkActualXSize;
     169    75361900 :                     for (size_t i = 0; i < xIters; ++i)
     170             :                     {
     171    75309300 :                         const double dfVal = padfLineData[nOffset + i];
     172    75309300 :                         nChecksum += IntFromDouble(dfVal) % anPrimes[iPrime++];
     173    75309300 :                         if (iPrime > 10)
     174     6845840 :                             iPrime = 0;
     175             :                     }
     176       52625 :                     nChecksum &= 0xffff;
     177             :                 }
     178             :             }
     179             :         }
     180             : 
     181        1092 :         CPLFree(padfLineData);
     182             :     }
     183       37340 :     else if (bIsFloatingPoint)
     184             :     {
     185           3 :         const GDALDataType eDstDataType = bComplex ? GDT_CFloat64 : GDT_Float64;
     186             : 
     187           3 :         double *padfLineData = static_cast<double *>(VSI_MALLOC2_VERBOSE(
     188             :             nXSize, GDALGetDataTypeSizeBytes(eDstDataType)));
     189           3 :         if (padfLineData == nullptr)
     190             :         {
     191           0 :             return -1;
     192             :         }
     193             : 
     194          33 :         for (int iLine = nYOff; iLine < nYOff + nYSize; iLine++)
     195             :         {
     196          30 :             if (GDALRasterIO(hBand, GF_Read, nXOff, iLine, nXSize, 1,
     197             :                              padfLineData, nXSize, 1, eDstDataType, 0,
     198          30 :                              0) != CE_None)
     199             :             {
     200           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     201             :                          "Checksum value couldn't be computed due to "
     202             :                          "I/O read error.");
     203           0 :                 nChecksum = -1;
     204           0 :                 break;
     205             :             }
     206          30 :             const size_t nCount = bComplex ? static_cast<size_t>(nXSize) * 2
     207             :                                            : static_cast<size_t>(nXSize);
     208             : 
     209         480 :             for (size_t i = 0; i < nCount; i++)
     210             :             {
     211         450 :                 const double dfVal = padfLineData[i];
     212         450 :                 nChecksum += IntFromDouble(dfVal) % anPrimes[iPrime++];
     213         450 :                 if (iPrime > 10)
     214          40 :                     iPrime = 0;
     215             : 
     216         450 :                 nChecksum &= 0xffff;
     217             :             }
     218             :         }
     219             : 
     220           3 :         CPLFree(padfLineData);
     221             :     }
     222       37337 :     else if (nXOff == 0 && nYOff == 0)
     223             :     {
     224       37274 :         const GDALDataType eDstDataType = bComplex ? GDT_CInt32 : GDT_Int32;
     225       37274 :         int nBlockXSize = 0;
     226       37274 :         int nBlockYSize = 0;
     227       37274 :         GDALGetBlockSize(hBand, &nBlockXSize, &nBlockYSize);
     228       37274 :         const int nDstDataTypeSize = GDALGetDataTypeSizeBytes(eDstDataType);
     229       37274 :         int nChunkXSize = nBlockXSize;
     230       37274 :         const int nChunkYSize = nBlockYSize;
     231       37274 :         if (nBlockXSize < nXSize)
     232             :         {
     233             :             const GIntBig nMaxChunkSize =
     234        2898 :                 std::max(static_cast<GIntBig>(10 * 1000 * 1000),
     235        1449 :                          GDALGetCacheMax64() / 10);
     236        1449 :             if (nDstDataTypeSize > 0 &&
     237        1449 :                 static_cast<GIntBig>(nXSize) * nChunkYSize <
     238        1449 :                     nMaxChunkSize / nDstDataTypeSize)
     239             :             {
     240             :                 // A full line of height nChunkYSize can fit in the maximum
     241             :                 // allowed memory
     242        1449 :                 nChunkXSize = nXSize;
     243             :             }
     244             :             else
     245             :             {
     246             :                 // Otherwise compute a size that is a multiple of nBlockXSize
     247           0 :                 nChunkXSize = static_cast<int>(std::min(
     248           0 :                     static_cast<GIntBig>(nXSize),
     249           0 :                     nBlockXSize *
     250           0 :                         std::max(static_cast<GIntBig>(1),
     251           0 :                                  nMaxChunkSize /
     252           0 :                                      (static_cast<GIntBig>(nBlockXSize) *
     253           0 :                                       nChunkYSize * nDstDataTypeSize))));
     254             :             }
     255             :         }
     256             : 
     257             :         int *panChunkData = static_cast<GInt32 *>(
     258       37274 :             VSI_MALLOC3_VERBOSE(nChunkXSize, nChunkYSize, nDstDataTypeSize));
     259       37274 :         if (panChunkData == nullptr)
     260             :         {
     261           0 :             return -1;
     262             :         }
     263       37274 :         const int nValsPerIter = bComplex ? 2 : 1;
     264             : 
     265       37274 :         const int nYBlocks = DIV_ROUND_UP(nYSize, nChunkYSize);
     266       37274 :         const int nXBlocks = DIV_ROUND_UP(nXSize, nChunkXSize);
     267     3132620 :         for (int iYBlock = 0; iYBlock < nYBlocks; ++iYBlock)
     268             :         {
     269     3095350 :             const int iYStart = iYBlock * nChunkYSize;
     270     3095350 :             const int iYEnd =
     271     3095350 :                 iYBlock == nYBlocks - 1 ? nYSize : iYStart + nChunkYSize;
     272     3095350 :             const int nChunkActualHeight = iYEnd - iYStart;
     273     6190590 :             for (int iXBlock = 0; iXBlock < nXBlocks; ++iXBlock)
     274             :             {
     275     3092350 :                 const int iXStart = iXBlock * nChunkXSize;
     276     3092350 :                 const int iXEnd =
     277     3092350 :                     iXBlock == nXBlocks - 1 ? nXSize : iXStart + nChunkXSize;
     278     3092350 :                 const int nChunkActualXSize = iXEnd - iXStart;
     279     3092350 :                 if (GDALRasterIO(
     280             :                         hBand, GF_Read, iXStart, iYStart, nChunkActualXSize,
     281             :                         nChunkActualHeight, panChunkData, nChunkActualXSize,
     282     3095330 :                         nChunkActualHeight, eDstDataType, 0, 0) != CE_None)
     283             :                 {
     284          90 :                     CPLError(CE_Failure, CPLE_FileIO,
     285             :                              "Checksum value could not be computed due to I/O "
     286             :                              "read error.");
     287           0 :                     nChecksum = -1;
     288           0 :                     iYBlock = nYBlocks;
     289           0 :                     break;
     290             :                 }
     291     3095240 :                 const size_t xIters =
     292     3095240 :                     static_cast<size_t>(nValsPerIter) * nChunkActualXSize;
     293     7974310 :                 for (int iY = iYStart; iY < iYEnd; ++iY)
     294             :                 {
     295             :                     // Initialize iPrime so that it is consistent with a
     296             :                     // per full line iteration strategy
     297     4879070 :                     iPrime = (nValsPerIter *
     298     4879070 :                               (static_cast<int64_t>(iY) * nXSize + iXStart)) %
     299             :                              11;
     300     4879070 :                     const size_t nOffset = nValsPerIter *
     301     4879070 :                                            static_cast<size_t>(iY - iYStart) *
     302     4879070 :                                            nChunkActualXSize;
     303  1186640000 :                     for (size_t i = 0; i < xIters; ++i)
     304             :                     {
     305  1181760000 :                         nChecksum +=
     306  1181760000 :                             panChunkData[nOffset + i] % anPrimes[iPrime++];
     307  1181760000 :                         if (iPrime > 10)
     308   113766000 :                             iPrime = 0;
     309             :                     }
     310     4879070 :                     nChecksum &= 0xffff;
     311             :                 }
     312             :             }
     313             :         }
     314             : 
     315       37268 :         CPLFree(panChunkData);
     316             :     }
     317             :     else
     318             :     {
     319          63 :         const GDALDataType eDstDataType = bComplex ? GDT_CInt32 : GDT_Int32;
     320             : 
     321          63 :         int *panLineData = static_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(
     322             :             nXSize, GDALGetDataTypeSizeBytes(eDstDataType)));
     323          63 :         if (panLineData == nullptr)
     324             :         {
     325           0 :             return -1;
     326             :         }
     327             : 
     328         153 :         for (int iLine = nYOff; iLine < nYOff + nYSize; iLine++)
     329             :         {
     330          90 :             if (GDALRasterIO(hBand, GF_Read, nXOff, iLine, nXSize, 1,
     331             :                              panLineData, nXSize, 1, eDstDataType, 0,
     332          90 :                              0) != CE_None)
     333             :             {
     334           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     335             :                          "Checksum value could not be computed due to I/O "
     336             :                          "read error.");
     337           0 :                 nChecksum = -1;
     338           0 :                 break;
     339             :             }
     340          90 :             const size_t nCount = bComplex ? static_cast<size_t>(nXSize) * 2
     341             :                                            : static_cast<size_t>(nXSize);
     342             : 
     343         600 :             for (size_t i = 0; i < nCount; i++)
     344             :             {
     345         510 :                 nChecksum += panLineData[i] % anPrimes[iPrime++];
     346         510 :                 if (iPrime > 10)
     347          40 :                     iPrime = 0;
     348             : 
     349         510 :                 nChecksum &= 0xffff;
     350             :             }
     351             :         }
     352             : 
     353          63 :         CPLFree(panLineData);
     354             :     }
     355             : 
     356             :     // coverity[return_overflow]
     357       38403 :     return nChecksum;
     358             : }

Generated by: LCOV version 1.14