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 : }
|