LCOV - code coverage report
Current view: top level - alg - gdalchecksum.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 150 174 86.2 %
Date: 2024-11-21 22:18:42 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       37141 : int CPL_STDCALL GDALChecksumImage(GDALRasterBandH hBand, int nXOff, int nYOff,
      49             :                                   int nXSize, int nYSize)
      50             : 
      51             : {
      52       37141 :     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       37141 :     int nChecksum = 0;
      57       37141 :     int iPrime = 0;
      58       37141 :     const GDALDataType eDataType = GDALGetRasterDataType(hBand);
      59       37141 :     const bool bComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eDataType));
      60       37141 :     const bool bIsFloatingPoint =
      61       36544 :         (eDataType == GDT_Float32 || eDataType == GDT_Float64 ||
      62       73685 :          eDataType == GDT_CFloat32 || eDataType == GDT_CFloat64);
      63             : 
      64    75305200 :     const auto IntFromDouble = [](double dfVal)
      65             :     {
      66             :         int nVal;
      67    75305200 :         if (!std::isfinite(dfVal))
      68             :         {
      69       18029 :             nVal = INT_MIN;
      70             :         }
      71             :         else
      72             :         {
      73             :             // Standard behavior of GDALCopyWords when converting
      74             :             // from floating point to Int32.
      75    75287200 :             dfVal += 0.5;
      76             : 
      77    75287200 :             if (dfVal < -2147483647.0)
      78        1215 :                 nVal = -2147483647;
      79    75286000 :             else if (dfVal > 2147483647)
      80        2690 :                 nVal = 2147483647;
      81             :             else
      82    75283300 :                 nVal = static_cast<GInt32>(floor(dfVal));
      83             :         }
      84    75305200 :         return nVal;
      85             :     };
      86             : 
      87       37141 :     if (bIsFloatingPoint && nXOff == 0 && nYOff == 0)
      88             :     {
      89        1080 :         const GDALDataType eDstDataType = bComplex ? GDT_CFloat64 : GDT_Float64;
      90        1080 :         int nBlockXSize = 0;
      91        1080 :         int nBlockYSize = 0;
      92        1080 :         GDALGetBlockSize(hBand, &nBlockXSize, &nBlockYSize);
      93        1080 :         const int nDstDataTypeSize = GDALGetDataTypeSizeBytes(eDstDataType);
      94        1080 :         int nChunkXSize = nBlockXSize;
      95        1080 :         const int nChunkYSize = nBlockYSize;
      96        1080 :         if (nBlockXSize < nXSize)
      97             :         {
      98             :             const GIntBig nMaxChunkSize =
      99          96 :                 std::max(static_cast<GIntBig>(10 * 1000 * 1000),
     100          48 :                          GDALGetCacheMax64() / 10);
     101          48 :             if (nDstDataTypeSize > 0 &&
     102          48 :                 static_cast<GIntBig>(nXSize) * nChunkYSize <
     103          48 :                     nMaxChunkSize / nDstDataTypeSize)
     104             :             {
     105             :                 // A full line of height nChunkYSize can fit in the maximum
     106             :                 // allowed memory
     107          48 :                 nChunkXSize = nXSize;
     108             :             }
     109             :             else
     110             :             {
     111             :                 // Otherwise compute a size that is a multiple of nBlockXSize
     112           0 :                 nChunkXSize = static_cast<int>(std::min(
     113           0 :                     static_cast<GIntBig>(nXSize),
     114           0 :                     nBlockXSize *
     115           0 :                         std::max(static_cast<GIntBig>(1),
     116           0 :                                  nMaxChunkSize /
     117           0 :                                      (static_cast<GIntBig>(nBlockXSize) *
     118           0 :                                       nChunkYSize * nDstDataTypeSize))));
     119             :             }
     120             :         }
     121             : 
     122             :         double *padfLineData = static_cast<double *>(
     123        1080 :             VSI_MALLOC3_VERBOSE(nChunkXSize, nChunkYSize, nDstDataTypeSize));
     124        1080 :         if (padfLineData == nullptr)
     125             :         {
     126           0 :             return -1;
     127             :         }
     128        1080 :         const int nValsPerIter = bComplex ? 2 : 1;
     129             : 
     130        1080 :         const int nYBlocks = DIV_ROUND_UP(nYSize, nChunkYSize);
     131        1080 :         const int nXBlocks = DIV_ROUND_UP(nXSize, nChunkXSize);
     132       27109 :         for (int iYBlock = 0; iYBlock < nYBlocks; ++iYBlock)
     133             :         {
     134       26029 :             const int iYStart = iYBlock * nChunkYSize;
     135       26029 :             const int iYEnd =
     136       26029 :                 iYBlock == nYBlocks - 1 ? nYSize : iYStart + nChunkYSize;
     137       26029 :             const int nChunkActualHeight = iYEnd - iYStart;
     138       52057 :             for (int iXBlock = 0; iXBlock < nXBlocks; ++iXBlock)
     139             :             {
     140       26029 :                 const int iXStart = iXBlock * nChunkXSize;
     141       26029 :                 const int iXEnd =
     142       26029 :                     iXBlock == nXBlocks - 1 ? nXSize : iXStart + nChunkXSize;
     143       26029 :                 const int nChunkActualXSize = iXEnd - iXStart;
     144       26029 :                 if (GDALRasterIO(
     145             :                         hBand, GF_Read, iXStart, iYStart, nChunkActualXSize,
     146             :                         nChunkActualHeight, padfLineData, nChunkActualXSize,
     147       26029 :                         nChunkActualHeight, eDstDataType, 0, 0) != CE_None)
     148             :                 {
     149           1 :                     CPLError(CE_Failure, CPLE_FileIO,
     150             :                              "Checksum value could not be computed due to I/O "
     151             :                              "read error.");
     152           1 :                     nChecksum = -1;
     153           1 :                     iYBlock = nYBlocks;
     154           1 :                     break;
     155             :                 }
     156       26028 :                 const size_t xIters =
     157       26028 :                     static_cast<size_t>(nValsPerIter) * nChunkActualXSize;
     158       78463 :                 for (int iY = iYStart; iY < iYEnd; ++iY)
     159             :                 {
     160             :                     // Initialize iPrime so that it is consistent with a
     161             :                     // per full line iteration strategy
     162       52435 :                     iPrime = (nValsPerIter *
     163       52435 :                               (static_cast<int64_t>(iY) * nXSize + iXStart)) %
     164             :                              11;
     165       52435 :                     const size_t nOffset = nValsPerIter *
     166       52435 :                                            static_cast<size_t>(iY - iYStart) *
     167       52435 :                                            nChunkActualXSize;
     168    75357200 :                     for (size_t i = 0; i < xIters; ++i)
     169             :                     {
     170    75304800 :                         const double dfVal = padfLineData[nOffset + i];
     171    75304800 :                         nChecksum += IntFromDouble(dfVal) % anPrimes[iPrime++];
     172    75304800 :                         if (iPrime > 10)
     173     6845430 :                             iPrime = 0;
     174             :                     }
     175       52435 :                     nChecksum &= 0xffff;
     176             :                 }
     177             :             }
     178             :         }
     179             : 
     180        1080 :         CPLFree(padfLineData);
     181             :     }
     182       36061 :     else if (bIsFloatingPoint)
     183             :     {
     184           3 :         const GDALDataType eDstDataType = bComplex ? GDT_CFloat64 : GDT_Float64;
     185             : 
     186           3 :         double *padfLineData = static_cast<double *>(VSI_MALLOC2_VERBOSE(
     187             :             nXSize, GDALGetDataTypeSizeBytes(eDstDataType)));
     188           3 :         if (padfLineData == nullptr)
     189             :         {
     190           0 :             return -1;
     191             :         }
     192             : 
     193          33 :         for (int iLine = nYOff; iLine < nYOff + nYSize; iLine++)
     194             :         {
     195          30 :             if (GDALRasterIO(hBand, GF_Read, nXOff, iLine, nXSize, 1,
     196             :                              padfLineData, nXSize, 1, eDstDataType, 0,
     197          30 :                              0) != CE_None)
     198             :             {
     199           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     200             :                          "Checksum value couldn't be computed due to "
     201             :                          "I/O read error.");
     202           0 :                 nChecksum = -1;
     203           0 :                 break;
     204             :             }
     205          30 :             const size_t nCount = bComplex ? static_cast<size_t>(nXSize) * 2
     206             :                                            : static_cast<size_t>(nXSize);
     207             : 
     208         480 :             for (size_t i = 0; i < nCount; i++)
     209             :             {
     210         450 :                 const double dfVal = padfLineData[i];
     211         450 :                 nChecksum += IntFromDouble(dfVal) % anPrimes[iPrime++];
     212         450 :                 if (iPrime > 10)
     213          40 :                     iPrime = 0;
     214             : 
     215         450 :                 nChecksum &= 0xffff;
     216             :             }
     217             :         }
     218             : 
     219           3 :         CPLFree(padfLineData);
     220             :     }
     221       36058 :     else if (nXOff == 0 && nYOff == 0)
     222             :     {
     223       35995 :         const GDALDataType eDstDataType = bComplex ? GDT_CInt32 : GDT_Int32;
     224       35995 :         int nBlockXSize = 0;
     225       35995 :         int nBlockYSize = 0;
     226       35995 :         GDALGetBlockSize(hBand, &nBlockXSize, &nBlockYSize);
     227       35995 :         const int nDstDataTypeSize = GDALGetDataTypeSizeBytes(eDstDataType);
     228       35995 :         int nChunkXSize = nBlockXSize;
     229       35995 :         const int nChunkYSize = nBlockYSize;
     230       35995 :         if (nBlockXSize < nXSize)
     231             :         {
     232             :             const GIntBig nMaxChunkSize =
     233        1188 :                 std::max(static_cast<GIntBig>(10 * 1000 * 1000),
     234         594 :                          GDALGetCacheMax64() / 10);
     235         594 :             if (nDstDataTypeSize > 0 &&
     236         594 :                 static_cast<GIntBig>(nXSize) * nChunkYSize <
     237         594 :                     nMaxChunkSize / nDstDataTypeSize)
     238             :             {
     239             :                 // A full line of height nChunkYSize can fit in the maximum
     240             :                 // allowed memory
     241         594 :                 nChunkXSize = nXSize;
     242             :             }
     243             :             else
     244             :             {
     245             :                 // Otherwise compute a size that is a multiple of nBlockXSize
     246           0 :                 nChunkXSize = static_cast<int>(std::min(
     247           0 :                     static_cast<GIntBig>(nXSize),
     248           0 :                     nBlockXSize *
     249           0 :                         std::max(static_cast<GIntBig>(1),
     250           0 :                                  nMaxChunkSize /
     251           0 :                                      (static_cast<GIntBig>(nBlockXSize) *
     252           0 :                                       nChunkYSize * nDstDataTypeSize))));
     253             :             }
     254             :         }
     255             : 
     256             :         int *panChunkData = static_cast<GInt32 *>(
     257       35995 :             VSI_MALLOC3_VERBOSE(nChunkXSize, nChunkYSize, nDstDataTypeSize));
     258       35995 :         if (panChunkData == nullptr)
     259             :         {
     260           0 :             return -1;
     261             :         }
     262       35995 :         const int nValsPerIter = bComplex ? 2 : 1;
     263             : 
     264       35995 :         const int nYBlocks = DIV_ROUND_UP(nYSize, nChunkYSize);
     265       35995 :         const int nXBlocks = DIV_ROUND_UP(nXSize, nChunkXSize);
     266     3127850 :         for (int iYBlock = 0; iYBlock < nYBlocks; ++iYBlock)
     267             :         {
     268     3091850 :             const int iYStart = iYBlock * nChunkYSize;
     269     3091850 :             const int iYEnd =
     270     3091850 :                 iYBlock == nYBlocks - 1 ? nYSize : iYStart + nChunkYSize;
     271     3091850 :             const int nChunkActualHeight = iYEnd - iYStart;
     272     6176900 :             for (int iXBlock = 0; iXBlock < nXBlocks; ++iXBlock)
     273             :             {
     274     3090900 :                 const int iXStart = iXBlock * nChunkXSize;
     275     3090900 :                 const int iXEnd =
     276     3090900 :                     iXBlock == nXBlocks - 1 ? nXSize : iXStart + nChunkXSize;
     277     3090900 :                 const int nChunkActualXSize = iXEnd - iXStart;
     278     3090900 :                 if (GDALRasterIO(
     279             :                         hBand, GF_Read, iXStart, iYStart, nChunkActualXSize,
     280             :                         nChunkActualHeight, panChunkData, nChunkActualXSize,
     281     3085140 :                         nChunkActualHeight, eDstDataType, 0, 0) != CE_None)
     282             :                 {
     283          88 :                     CPLError(CE_Failure, CPLE_FileIO,
     284             :                              "Checksum value could not be computed due to I/O "
     285             :                              "read error.");
     286        5843 :                     nChecksum = -1;
     287        5843 :                     iYBlock = nYBlocks;
     288        5843 :                     break;
     289             :                 }
     290     3085050 :                 const size_t xIters =
     291     3085050 :                     static_cast<size_t>(nValsPerIter) * nChunkActualXSize;
     292     7890610 :                 for (int iY = iYStart; iY < iYEnd; ++iY)
     293             :                 {
     294             :                     // Initialize iPrime so that it is consistent with a
     295             :                     // per full line iteration strategy
     296     4805560 :                     iPrime = (nValsPerIter *
     297     4805560 :                               (static_cast<int64_t>(iY) * nXSize + iXStart)) %
     298             :                              11;
     299     4805560 :                     const size_t nOffset = nValsPerIter *
     300     4805560 :                                            static_cast<size_t>(iY - iYStart) *
     301     4805560 :                                            nChunkActualXSize;
     302  1179570000 :                     for (size_t i = 0; i < xIters; ++i)
     303             :                     {
     304  1174760000 :                         nChecksum +=
     305  1174760000 :                             panChunkData[nOffset + i] % anPrimes[iPrime++];
     306  1174760000 :                         if (iPrime > 10)
     307   112977000 :                             iPrime = 0;
     308             :                     }
     309     4805560 :                     nChecksum &= 0xffff;
     310             :                 }
     311             :             }
     312             :         }
     313             : 
     314       35994 :         CPLFree(panChunkData);
     315             :     }
     316             :     else
     317             :     {
     318          63 :         const GDALDataType eDstDataType = bComplex ? GDT_CInt32 : GDT_Int32;
     319             : 
     320          63 :         int *panLineData = static_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(
     321             :             nXSize, GDALGetDataTypeSizeBytes(eDstDataType)));
     322          63 :         if (panLineData == nullptr)
     323             :         {
     324           0 :             return -1;
     325             :         }
     326             : 
     327         153 :         for (int iLine = nYOff; iLine < nYOff + nYSize; iLine++)
     328             :         {
     329          90 :             if (GDALRasterIO(hBand, GF_Read, nXOff, iLine, nXSize, 1,
     330             :                              panLineData, nXSize, 1, eDstDataType, 0,
     331          90 :                              0) != CE_None)
     332             :             {
     333           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     334             :                          "Checksum value could not be computed due to I/O "
     335             :                          "read error.");
     336           0 :                 nChecksum = -1;
     337           0 :                 break;
     338             :             }
     339          90 :             const size_t nCount = bComplex ? static_cast<size_t>(nXSize) * 2
     340             :                                            : static_cast<size_t>(nXSize);
     341             : 
     342         600 :             for (size_t i = 0; i < nCount; i++)
     343             :             {
     344         510 :                 nChecksum += panLineData[i] % anPrimes[iPrime++];
     345         510 :                 if (iPrime > 10)
     346          40 :                     iPrime = 0;
     347             : 
     348         510 :                 nChecksum &= 0xffff;
     349             :             }
     350             :         }
     351             : 
     352          63 :         CPLFree(panLineData);
     353             :     }
     354             : 
     355             :     // coverity[return_overflow]
     356       37132 :     return nChecksum;
     357             : }

Generated by: LCOV version 1.14