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 38384 : int CPL_STDCALL GDALChecksumImage(GDALRasterBandH hBand, int nXOff, int nYOff,
49 : int nXSize, int nYSize)
50 :
51 : {
52 38384 : 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 38384 : int nChecksum = 0;
57 38384 : int iPrime = 0;
58 38384 : const GDALDataType eDataType = GDALGetRasterDataType(hBand);
59 38384 : const bool bComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eDataType));
60 38384 : const bool bIsFloatingPoint =
61 37782 : (eDataType == GDT_Float32 || eDataType == GDT_Float64 ||
62 76166 : eDataType == GDT_CFloat32 || eDataType == GDT_CFloat64);
63 :
64 75309600 : const auto IntFromDouble = [](double dfVal)
65 : {
66 : int nVal;
67 75309600 : 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 75291600 : dfVal += 0.5;
76 :
77 75291600 : if (dfVal < -2147483647.0)
78 1215 : nVal = -2147483647;
79 75290400 : else if (dfVal > 2147483647)
80 2690 : nVal = 2147483647;
81 : else
82 75287700 : nVal = static_cast<GInt32>(floor(dfVal));
83 : }
84 75309600 : return nVal;
85 : };
86 :
87 38384 : if (bIsFloatingPoint && nXOff == 0 && nYOff == 0)
88 : {
89 1089 : const GDALDataType eDstDataType = bComplex ? GDT_CFloat64 : GDT_Float64;
90 1089 : int nBlockXSize = 0;
91 1089 : int nBlockYSize = 0;
92 1089 : GDALGetBlockSize(hBand, &nBlockXSize, &nBlockYSize);
93 1089 : const int nDstDataTypeSize = GDALGetDataTypeSizeBytes(eDstDataType);
94 1089 : int nChunkXSize = nBlockXSize;
95 1089 : const int nChunkYSize = nBlockYSize;
96 1089 : 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 1089 : VSI_MALLOC3_VERBOSE(nChunkXSize, nChunkYSize, nDstDataTypeSize));
124 1089 : if (padfLineData == nullptr)
125 : {
126 0 : return -1;
127 : }
128 1089 : const int nValsPerIter = bComplex ? 2 : 1;
129 :
130 1089 : const int nYBlocks = DIV_ROUND_UP(nYSize, nChunkYSize);
131 1089 : const int nXBlocks = DIV_ROUND_UP(nXSize, nChunkXSize);
132 27127 : for (int iYBlock = 0; iYBlock < nYBlocks; ++iYBlock)
133 : {
134 26038 : const int iYStart = iYBlock * nChunkYSize;
135 26038 : const int iYEnd =
136 26038 : iYBlock == nYBlocks - 1 ? nYSize : iYStart + nChunkYSize;
137 26038 : const int nChunkActualHeight = iYEnd - iYStart;
138 52075 : for (int iXBlock = 0; iXBlock < nXBlocks; ++iXBlock)
139 : {
140 26038 : const int iXStart = iXBlock * nChunkXSize;
141 26038 : const int iXEnd =
142 26038 : iXBlock == nXBlocks - 1 ? nXSize : iXStart + nChunkXSize;
143 26038 : const int nChunkActualXSize = iXEnd - iXStart;
144 26038 : if (GDALRasterIO(
145 : hBand, GF_Read, iXStart, iYStart, nChunkActualXSize,
146 : nChunkActualHeight, padfLineData, nChunkActualXSize,
147 26038 : 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 26037 : const size_t xIters =
157 26037 : static_cast<size_t>(nValsPerIter) * nChunkActualXSize;
158 78652 : 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 52615 : iPrime = (nValsPerIter *
163 52615 : (static_cast<int64_t>(iY) * nXSize + iXStart)) %
164 : 11;
165 52615 : const size_t nOffset = nValsPerIter *
166 52615 : static_cast<size_t>(iY - iYStart) *
167 52615 : nChunkActualXSize;
168 75361800 : for (size_t i = 0; i < xIters; ++i)
169 : {
170 75309200 : const double dfVal = padfLineData[nOffset + i];
171 75309200 : nChecksum += IntFromDouble(dfVal) % anPrimes[iPrime++];
172 75309200 : if (iPrime > 10)
173 6845830 : iPrime = 0;
174 : }
175 52615 : nChecksum &= 0xffff;
176 : }
177 : }
178 : }
179 :
180 1089 : CPLFree(padfLineData);
181 : }
182 37295 : 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 37292 : else if (nXOff == 0 && nYOff == 0)
222 : {
223 37229 : const GDALDataType eDstDataType = bComplex ? GDT_CInt32 : GDT_Int32;
224 37229 : int nBlockXSize = 0;
225 37229 : int nBlockYSize = 0;
226 37229 : GDALGetBlockSize(hBand, &nBlockXSize, &nBlockYSize);
227 37229 : const int nDstDataTypeSize = GDALGetDataTypeSizeBytes(eDstDataType);
228 37228 : int nChunkXSize = nBlockXSize;
229 37228 : const int nChunkYSize = nBlockYSize;
230 37228 : if (nBlockXSize < nXSize)
231 : {
232 : const GIntBig nMaxChunkSize =
233 2842 : std::max(static_cast<GIntBig>(10 * 1000 * 1000),
234 1421 : GDALGetCacheMax64() / 10);
235 1421 : if (nDstDataTypeSize > 0 &&
236 1421 : static_cast<GIntBig>(nXSize) * nChunkYSize <
237 1421 : nMaxChunkSize / nDstDataTypeSize)
238 : {
239 : // A full line of height nChunkYSize can fit in the maximum
240 : // allowed memory
241 1421 : 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 37228 : VSI_MALLOC3_VERBOSE(nChunkXSize, nChunkYSize, nDstDataTypeSize));
258 37228 : if (panChunkData == nullptr)
259 : {
260 0 : return -1;
261 : }
262 37228 : const int nValsPerIter = bComplex ? 2 : 1;
263 :
264 37228 : const int nYBlocks = DIV_ROUND_UP(nYSize, nChunkYSize);
265 37228 : const int nXBlocks = DIV_ROUND_UP(nXSize, nChunkXSize);
266 3130110 : for (int iYBlock = 0; iYBlock < nYBlocks; ++iYBlock)
267 : {
268 3092900 : const int iYStart = iYBlock * nChunkYSize;
269 3092900 : const int iYEnd =
270 3092900 : iYBlock == nYBlocks - 1 ? nYSize : iYStart + nChunkYSize;
271 3092900 : const int nChunkActualHeight = iYEnd - iYStart;
272 6171130 : for (int iXBlock = 0; iXBlock < nXBlocks; ++iXBlock)
273 : {
274 3083860 : const int iXStart = iXBlock * nChunkXSize;
275 3083860 : const int iXEnd =
276 3083860 : iXBlock == nXBlocks - 1 ? nXSize : iXStart + nChunkXSize;
277 3083860 : const int nChunkActualXSize = iXEnd - iXStart;
278 3083860 : if (GDALRasterIO(
279 : hBand, GF_Read, iXStart, iYStart, nChunkActualXSize,
280 : nChunkActualHeight, panChunkData, nChunkActualXSize,
281 3078320 : nChunkActualHeight, eDstDataType, 0, 0) != CE_None)
282 : {
283 90 : CPLError(CE_Failure, CPLE_FileIO,
284 : "Checksum value could not be computed due to I/O "
285 : "read error.");
286 5615 : nChecksum = -1;
287 5615 : iYBlock = nYBlocks;
288 5615 : break;
289 : }
290 3078230 : const size_t xIters =
291 3078230 : static_cast<size_t>(nValsPerIter) * nChunkActualXSize;
292 7935870 : 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 4857640 : iPrime = (nValsPerIter *
297 4857640 : (static_cast<int64_t>(iY) * nXSize + iXStart)) %
298 : 11;
299 4857640 : const size_t nOffset = nValsPerIter *
300 4857640 : static_cast<size_t>(iY - iYStart) *
301 4857640 : nChunkActualXSize;
302 1178980000 : for (size_t i = 0; i < xIters; ++i)
303 : {
304 1174130000 : nChecksum +=
305 1174130000 : panChunkData[nOffset + i] % anPrimes[iPrime++];
306 1174130000 : if (iPrime > 10)
307 112809000 : iPrime = 0;
308 : }
309 4857640 : nChecksum &= 0xffff;
310 : }
311 : }
312 : }
313 :
314 37211 : 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 38346 : return nChecksum;
357 : }
|