• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 8872387746

29 Apr 2024 02:16AM UTC coverage: 69.076% (+0.003%) from 69.073%
8872387746

Pull #9801

github

web-flow
Bump actions/upload-artifact from 4.3.2 to 4.3.3

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.2 to 4.3.3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/1746f4ab6...65462800f)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #9801: Bump actions/upload-artifact from 4.3.2 to 4.3.3

534153 of 773282 relevant lines covered (69.08%)

205719.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.91
/gcore/gdalrasterband.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Base class for format specific band class implementation.  This
5
 *           base class provides default implementation for many methods.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 1998, Frank Warmerdam
10
 * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a
13
 * copy of this software and associated documentation files (the "Software"),
14
 * to deal in the Software without restriction, including without limitation
15
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16
 * and/or sell copies of the Software, and to permit persons to whom the
17
 * Software is furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included
20
 * in all copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28
 * DEALINGS IN THE SOFTWARE.
29
 ****************************************************************************/
30

31
#include "cpl_port.h"
32
#include "gdal_priv.h"
33

34
#include <climits>
35
#include <cmath>
36
#include <cstdarg>
37
#include <cstddef>
38
#include <cstdio>
39
#include <cstdlib>
40
#include <cstring>
41
#include <algorithm>
42
#include <limits>
43
#include <memory>
44
#include <new>
45
#include <type_traits>
46

47
#include "cpl_conv.h"
48
#include "cpl_error.h"
49
#include "cpl_progress.h"
50
#include "cpl_string.h"
51
#include "cpl_virtualmem.h"
52
#include "cpl_vsi.h"
53
#include "gdal.h"
54
#include "gdal_rat.h"
55
#include "gdal_priv_templates.hpp"
56

57
/************************************************************************/
58
/*                           GDALRasterBand()                           */
59
/************************************************************************/
60

61
/*! Constructor. Applications should never create GDALRasterBands directly. */
62

63
GDALRasterBand::GDALRasterBand()
978,335✔
64
    : GDALRasterBand(
65
          CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
978,335✔
66
{
67
}
978,260✔
68

69
/** Constructor. Applications should never create GDALRasterBands directly.
70
 * @param bForceCachedIOIn Whether cached IO should be forced.
71
 */
72
GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
1,040,770✔
73
    : bForceCachedIO(bForceCachedIOIn)
1,040,770✔
74

75
{
76
}
1,040,670✔
77

78
/************************************************************************/
79
/*                          ~GDALRasterBand()                           */
80
/************************************************************************/
81

82
/*! Destructor. Applications should never destroy GDALRasterBands directly,
83
    instead destroy the GDALDataset. */
84

85
GDALRasterBand::~GDALRasterBand()
1,040,780✔
86

87
{
88
    if (poDS && poDS->IsMarkedSuppressOnClose())
1,040,780✔
89
    {
90
        if (poBandBlockCache)
429✔
91
            poBandBlockCache->DisableDirtyBlockWriting();
380✔
92
    }
93
    GDALRasterBand::FlushCache(true);
1,040,780✔
94

95
    delete poBandBlockCache;
1,040,780✔
96

97
    if (static_cast<GIntBig>(nBlockReads) >
1,040,780✔
98
            static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
1,040,780✔
99
        nBand == 1 && poDS != nullptr)
190✔
100
    {
101
        CPLDebug("GDAL", "%d block reads on %d block band 1 of %s.",
278✔
102
                 nBlockReads, nBlocksPerRow * nBlocksPerColumn,
139✔
103
                 poDS->GetDescription());
139✔
104
    }
105

106
    InvalidateMaskBand();
1,040,780✔
107
    nBand = -nBand;
1,040,780✔
108
}
1,040,780✔
109

110
/************************************************************************/
111
/*                              RasterIO()                              */
112
/************************************************************************/
113

114
/**
115
 * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
116
 *                                int nXOff, int nYOff, int nXSize, int nYSize,
117
 *                                void * pData, int nBufXSize, int nBufYSize,
118
 *                                GDALDataType eBufType,
119
 *                                GSpacing nPixelSpace,
120
 *                                GSpacing nLineSpace,
121
 *                                GDALRasterIOExtraArg* psExtraArg )
122
 * \brief Read/write a region of image data for this band.
123
 *
124
 * This method allows reading a region of a GDALRasterBand into a buffer,
125
 * or writing data from a buffer into a region of a GDALRasterBand. It
126
 * automatically takes care of data type translation if the data type
127
 * (eBufType) of the buffer is different than that of the GDALRasterBand.
128
 * The method also takes care of image decimation / replication if the
129
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
130
 * region being accessed (nXSize x nYSize).
131
 *
132
 * The nPixelSpace and nLineSpace parameters allow reading into or
133
 * writing from unusually organized buffers. This is primarily used
134
 * for buffers containing more than one bands raster data in interleaved
135
 * format.
136
 *
137
 * Some formats may efficiently implement decimation into a buffer by
138
 * reading from lower resolution overview images. The logic of the default
139
 * implementation in the base class GDALRasterBand is the following one. It
140
 * computes a target_downscaling_factor from the window of interest and buffer
141
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
142
 * It then walks through overviews and will select the first one whose
143
 * downscaling factor is greater than target_downscaling_factor / 1.2.
144
 *
145
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
146
 * The relationship between target_downscaling_factor and the select overview
147
 * level is the following one:
148
 *
149
 * target_downscaling_factor  | selected_overview
150
 * -------------------------  | -----------------
151
 * ]0,       2 / 1.2]         | full resolution band
152
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
153
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
154
 * ]8 / 1.2, infinity[        | 8x downsampled band
155
 *
156
 * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
157
 * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
158
 * option. Also note that starting with GDAL 3.9, when the resampling algorithm
159
 * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
160
 * this oversampling threshold defaults to 1. Consequently if there are overviews
161
 * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
162
 * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
163
 *
164
 * For highest performance full resolution data access, read and write
165
 * on "block boundaries" as returned by GetBlockSize(), or use the
166
 * ReadBlock() and WriteBlock() methods.
167
 *
168
 * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
169
 * functions.
170
 *
171
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
172
 * write a region of data.
173
 *
174
 * @param nXOff The pixel offset to the top left corner of the region
175
 * of the band to be accessed. This would be zero to start from the left side.
176
 *
177
 * @param nYOff The line offset to the top left corner of the region
178
 * of the band to be accessed. This would be zero to start from the top.
179
 *
180
 * @param nXSize The width of the region of the band to be accessed in pixels.
181
 *
182
 * @param nYSize The height of the region of the band to be accessed in lines.
183
 *
184
 * @param pData The buffer into which the data should be read, or from which
185
 * it should be written. This buffer must contain at least nBufXSize *
186
 * nBufYSize words of type eBufType. It is organized in left to right,
187
 * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
188
 * and nLineSpace parameters.
189
 * Note that even with eRWFlag==GF_Write, the content of the buffer might be
190
 * temporarily modified during the execution of this method (and eventually
191
 * restored back to its original content), so it is not safe to use a buffer
192
 * stored in a read-only section of the calling program.
193
 *
194
 * @param nBufXSize the width of the buffer image into which the desired region
195
 * is to be read, or from which it is to be written.
196
 *
197
 * @param nBufYSize the height of the buffer image into which the desired region
198
 * is to be read, or from which it is to be written.
199
 *
200
 * @param eBufType the type of the pixel values in the pData data buffer. The
201
 * pixel values will automatically be translated to/from the GDALRasterBand
202
 * data type as needed.
203
 *
204
 * @param nPixelSpace The byte offset from the start of one pixel value in
205
 * pData to the start of the next pixel value within a scanline. If defaulted
206
 * (0) the size of the datatype eBufType is used.
207
 *
208
 * @param nLineSpace The byte offset from the start of one scanline in
209
 * pData to the start of the next. If defaulted (0) the size of the datatype
210
 * eBufType * nBufXSize is used.
211
 *
212
 * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
213
 * structure with additional arguments to specify resampling and progress
214
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
215
 * configuration option can also be defined to override the default resampling
216
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
217
 *
218
 * @return CE_Failure if the access fails, otherwise CE_None.
219
 */
220

221
/**
222
 * \brief Read/write a region of image data for this band.
223
 *
224
 * This method allows reading a region of a GDALRasterBand into a buffer,
225
 * or writing data from a buffer into a region of a GDALRasterBand. It
226
 * automatically takes care of data type translation if the data type
227
 * (eBufType) of the buffer is different than that of the GDALRasterBand.
228
 * The method also takes care of image decimation / replication if the
229
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
230
 * region being accessed (nXSize x nYSize).
231
 *
232
 * The nPixelSpace and nLineSpace parameters allow reading into or
233
 * writing from unusually organized buffers. This is primarily used
234
 * for buffers containing more than one bands raster data in interleaved
235
 * format.
236
 *
237
 * Some formats may efficiently implement decimation into a buffer by
238
 * reading from lower resolution overview images. The logic of the default
239
 * implementation in the base class GDALRasterBand is the following one. It
240
 * computes a target_downscaling_factor from the window of interest and buffer
241
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
242
 * It then walks through overviews and will select the first one whose
243
 * downscaling factor is greater than target_downscaling_factor / 1.2.
244
 *
245
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
246
 * The relationship between target_downscaling_factor and the select overview
247
 * level is the following one:
248
 *
249
 * target_downscaling_factor  | selected_overview
250
 * -------------------------  | -----------------
251
 * ]0,       2 / 1.2]         | full resolution band
252
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
253
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
254
 * ]8 / 1.2, infinity[        | 8x downsampled band
255
 *
256
 * For highest performance full resolution data access, read and write
257
 * on "block boundaries" as returned by GetBlockSize(), or use the
258
 * ReadBlock() and WriteBlock() methods.
259
 *
260
 * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
261
 * functions.
262
 *
263
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
264
 * write a region of data.
265
 *
266
 * @param nXOff The pixel offset to the top left corner of the region
267
 * of the band to be accessed. This would be zero to start from the left side.
268
 *
269
 * @param nYOff The line offset to the top left corner of the region
270
 * of the band to be accessed. This would be zero to start from the top.
271
 *
272
 * @param nXSize The width of the region of the band to be accessed in pixels.
273
 *
274
 * @param nYSize The height of the region of the band to be accessed in lines.
275
 *
276
 * @param[in,out] pData The buffer into which the data should be read, or from
277
 * which it should be written. This buffer must contain at least nBufXSize *
278
 * nBufYSize words of type eBufType. It is organized in left to right,
279
 * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
280
 * and nLineSpace parameters.
281
 *
282
 * @param nBufXSize the width of the buffer image into which the desired region
283
 * is to be read, or from which it is to be written.
284
 *
285
 * @param nBufYSize the height of the buffer image into which the desired region
286
 * is to be read, or from which it is to be written.
287
 *
288
 * @param eBufType the type of the pixel values in the pData data buffer. The
289
 * pixel values will automatically be translated to/from the GDALRasterBand
290
 * data type as needed.
291
 *
292
 * @param nPixelSpace The byte offset from the start of one pixel value in
293
 * pData to the start of the next pixel value within a scanline. If defaulted
294
 * (0) the size of the datatype eBufType is used.
295
 *
296
 * @param nLineSpace The byte offset from the start of one scanline in
297
 * pData to the start of the next. If defaulted (0) the size of the datatype
298
 * eBufType * nBufXSize is used.
299
 *
300
 * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
301
 * structure with additional arguments to specify resampling and progress
302
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
303
 * configuration option can also be defined to override the default resampling
304
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
305
 *
306
 * @return CE_Failure if the access fails, otherwise CE_None.
307
 */
308

309
CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2,751,670✔
310
                                int nXSize, int nYSize, void *pData,
311
                                int nBufXSize, int nBufYSize,
312
                                GDALDataType eBufType, GSpacing nPixelSpace,
313
                                GSpacing nLineSpace,
314
                                GDALRasterIOExtraArg *psExtraArg)
315

316
{
317
    GDALRasterIOExtraArg sExtraArg;
318
    if (psExtraArg == nullptr)
2,751,670✔
319
    {
320
        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
2,675,200✔
321
        psExtraArg = &sExtraArg;
2,675,200✔
322
    }
323
    else if (psExtraArg->nVersion != RASTERIO_EXTRA_ARG_CURRENT_VERSION)
76,470✔
324
    {
325
        ReportError(CE_Failure, CPLE_AppDefined,
×
326
                    "Unhandled version of GDALRasterIOExtraArg");
327
        return CE_Failure;
×
328
    }
329

330
    GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
2,751,670✔
331
                                       nBufYSize);
332

333
    if (nullptr == pData)
2,751,430✔
334
    {
335
        ReportError(CE_Failure, CPLE_AppDefined,
×
336
                    "The buffer into which the data should be read is null");
337
        return CE_Failure;
×
338
    }
339

340
    /* -------------------------------------------------------------------- */
341
    /*      Some size values are "noop".  Lets just return to avoid         */
342
    /*      stressing lower level functions.                                */
343
    /* -------------------------------------------------------------------- */
344
    if (nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1)
2,751,430✔
345
    {
346
        CPLDebug("GDAL",
×
347
                 "RasterIO() skipped for odd window or buffer size.\n"
348
                 "  Window = (%d,%d)x%dx%d\n"
349
                 "  Buffer = %dx%d\n",
350
                 nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
351

352
        return CE_None;
2✔
353
    }
354

355
    if (eRWFlag == GF_Write)
2,751,660✔
356
    {
357
        if (eFlushBlockErr != CE_None)
114,167✔
358
        {
359
            ReportError(eFlushBlockErr, CPLE_AppDefined,
×
360
                        "An error occurred while writing a dirty block "
361
                        "from GDALRasterBand::RasterIO");
362
            CPLErr eErr = eFlushBlockErr;
×
363
            eFlushBlockErr = CE_None;
×
364
            return eErr;
×
365
        }
366
        if (eAccess != GA_Update)
114,167✔
367
        {
368
            ReportError(CE_Failure, CPLE_AppDefined,
3✔
369
                        "Write operation not permitted on dataset opened "
370
                        "in read-only mode");
371
            return CE_Failure;
3✔
372
        }
373
    }
374

375
    /* -------------------------------------------------------------------- */
376
    /*      If pixel and line spacing are defaulted assign reasonable      */
377
    /*      value assuming a packed buffer.                                 */
378
    /* -------------------------------------------------------------------- */
379
    if (nPixelSpace == 0)
2,751,650✔
380
    {
381
        nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
2,670,930✔
382
    }
383

384
    if (nLineSpace == 0)
2,751,750✔
385
    {
386
        nLineSpace = nPixelSpace * nBufXSize;
2,667,590✔
387
    }
388

389
    /* -------------------------------------------------------------------- */
390
    /*      Do some validation of parameters.                               */
391
    /* -------------------------------------------------------------------- */
392
    if (nXOff < 0 || nXOff > INT_MAX - nXSize ||
2,751,750✔
393
        nXOff + nXSize > nRasterXSize || nYOff < 0 ||
2,751,670✔
394
        nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize)
2,751,660✔
395
    {
396
        ReportError(CE_Failure, CPLE_IllegalArg,
94✔
397
                    "Access window out of range in RasterIO().  Requested\n"
398
                    "(%d,%d) of size %dx%d on raster of %dx%d.",
399
                    nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
400
        return CE_Failure;
15✔
401
    }
402

403
    if (eRWFlag != GF_Read && eRWFlag != GF_Write)
2,751,650✔
404
    {
405
        ReportError(
×
406
            CE_Failure, CPLE_IllegalArg,
407
            "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
408
            eRWFlag);
409
        return CE_Failure;
×
410
    }
411

412
    /* -------------------------------------------------------------------- */
413
    /*      Call the format specific function.                              */
414
    /* -------------------------------------------------------------------- */
415

416
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
2,751,650✔
417

418
    CPLErr eErr;
419
    if (bForceCachedIO)
2,751,640✔
420
        eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
22✔
421
                                         pData, nBufXSize, nBufYSize, eBufType,
422
                                         nPixelSpace, nLineSpace, psExtraArg);
423
    else
424
        eErr =
425
            IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
2,751,640✔
426
                      nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
2,751,620✔
427

428
    if (bCallLeaveReadWrite)
2,751,660✔
429
        LeaveReadWrite();
186,804✔
430

431
    return eErr;
2,751,670✔
432
}
433

434
/************************************************************************/
435
/*                            GDALRasterIO()                            */
436
/************************************************************************/
437

438
/**
439
 * \brief Read/write a region of image data for this band.
440
 *
441
 * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
442
 * resolution, progress callback, etc. are needed)
443
 *
444
 * @see GDALRasterBand::RasterIO()
445
 */
446

447
CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
2,513,830✔
448
                                int nXOff, int nYOff, int nXSize, int nYSize,
449
                                void *pData, int nBufXSize, int nBufYSize,
450
                                GDALDataType eBufType, int nPixelSpace,
451
                                int nLineSpace)
452

453
{
454
    VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
2,513,830✔
455

456
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2,513,830✔
457

458
    return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2,513,830✔
459
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
460
                             nLineSpace, nullptr));
2,513,860✔
461
}
462

463
/************************************************************************/
464
/*                            GDALRasterIOEx()                          */
465
/************************************************************************/
466

467
/**
468
 * \brief Read/write a region of image data for this band.
469
 *
470
 * @see GDALRasterBand::RasterIO()
471
 * @since GDAL 2.0
472
 */
473

474
CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
31,241✔
475
                                  int nXOff, int nYOff, int nXSize, int nYSize,
476
                                  void *pData, int nBufXSize, int nBufYSize,
477
                                  GDALDataType eBufType, GSpacing nPixelSpace,
478
                                  GSpacing nLineSpace,
479
                                  GDALRasterIOExtraArg *psExtraArg)
480

481
{
482
    VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
31,241✔
483

484
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
31,241✔
485

486
    return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
31,241✔
487
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
488
                             nLineSpace, psExtraArg));
31,240✔
489
}
490

491
/************************************************************************/
492
/*                             ReadBlock()                              */
493
/************************************************************************/
494

495
/**
496
 * \brief Read a block of image data efficiently.
497
 *
498
 * This method accesses a "natural" block from the raster band without
499
 * resampling, or data type conversion.  For a more generalized, but
500
 * potentially less efficient access use RasterIO().
501
 *
502
 * This method is the same as the C GDALReadBlock() function.
503
 *
504
 * See the GetLockedBlockRef() method for a way of accessing internally cached
505
 * block oriented data without an extra copy into an application buffer.
506
 *
507
 * The following code would efficiently compute a histogram of eight bit
508
 * raster data.  Note that the final block may be partial ... data beyond
509
 * the edge of the underlying raster band in these edge blocks is of an
510
 * undetermined value.
511
 *
512
\code{.cpp}
513
 CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
514

515
 {
516
     memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
517

518
     CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
519

520
     int nXBlockSize, nYBlockSize;
521

522
     poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
523
     int nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
524
     int nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
525

526
     GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
527

528
     for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
529
     {
530
         for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
531
         {
532
             int        nXValid, nYValid;
533

534
             poBand->ReadBlock( iXBlock, iYBlock, pabyData );
535

536
             // Compute the portion of the block that is valid
537
             // for partial edge blocks.
538
             poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
539

540
             // Collect the histogram counts.
541
             for( int iY = 0; iY < nYValid; iY++ )
542
             {
543
                 for( int iX = 0; iX < nXValid; iX++ )
544
                 {
545
                     panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
546
                 }
547
             }
548
         }
549
     }
550
 }
551
\endcode
552
 *
553
 * @param nXBlockOff the horizontal block offset, with zero indicating
554
 * the left most block, 1 the next block and so forth.
555
 *
556
 * @param nYBlockOff the vertical block offset, with zero indicating
557
 * the top most block, 1 the next block and so forth.
558
 *
559
 * @param pImage the buffer into which the data will be read.  The buffer
560
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
561
 * of type GetRasterDataType().
562
 *
563
 * @return CE_None on success or CE_Failure on an error.
564
 */
565

566
CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
607✔
567

568
{
569
    /* -------------------------------------------------------------------- */
570
    /*      Validate arguments.                                             */
571
    /* -------------------------------------------------------------------- */
572
    CPLAssert(pImage != nullptr);
607✔
573

574
    if (!InitBlockInfo())
607✔
575
        return CE_Failure;
×
576

577
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
607✔
578
    {
579
        ReportError(CE_Failure, CPLE_IllegalArg,
×
580
                    "Illegal nXBlockOff value (%d) in "
581
                    "GDALRasterBand::ReadBlock()\n",
582
                    nXBlockOff);
583

584
        return (CE_Failure);
×
585
    }
586

587
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
607✔
588
    {
589
        ReportError(CE_Failure, CPLE_IllegalArg,
×
590
                    "Illegal nYBlockOff value (%d) in "
591
                    "GDALRasterBand::ReadBlock()\n",
592
                    nYBlockOff);
593

594
        return (CE_Failure);
×
595
    }
596

597
    /* -------------------------------------------------------------------- */
598
    /*      Invoke underlying implementation method.                        */
599
    /* -------------------------------------------------------------------- */
600

601
    int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
607✔
602
    CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
607✔
603
    if (bCallLeaveReadWrite)
607✔
604
        LeaveReadWrite();
4✔
605
    return eErr;
607✔
606
}
607

608
/************************************************************************/
609
/*                           GDALReadBlock()                            */
610
/************************************************************************/
611

612
/**
613
 * \brief Read a block of image data efficiently.
614
 *
615
 * @see GDALRasterBand::ReadBlock()
616
 */
617

618
CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
67✔
619
                                 void *pData)
620

621
{
622
    VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
67✔
623

624
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
67✔
625
    return (poBand->ReadBlock(nXOff, nYOff, pData));
67✔
626
}
627

628
/************************************************************************/
629
/*                            IReadBlock()                             */
630
/************************************************************************/
631

632
/** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
633
 * ) \brief Read a block of data.
634
 *
635
 * Default internal implementation ... to be overridden by
636
 * subclasses that support reading.
637
 * @param nBlockXOff Block X Offset
638
 * @param nBlockYOff Block Y Offset
639
 * @param pData Pixel buffer into which to place read data.
640
 * @return CE_None on success or CE_Failure on an error.
641
 */
642

643
/************************************************************************/
644
/*                            IWriteBlock()                             */
645
/************************************************************************/
646

647
/**
648
 * \fn GDALRasterBand::IWriteBlock(int, int, void*)
649
 * Write a block of data.
650
 *
651
 * Default internal implementation ... to be overridden by
652
 * subclasses that support writing.
653
 * @param nBlockXOff Block X Offset
654
 * @param nBlockYOff Block Y Offset
655
 * @param pData Pixel buffer to write
656
 * @return CE_None on success or CE_Failure on an error.
657
 */
658

659
/**/
660
/**/
661

662
CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
2✔
663
                                   void * /*pData*/)
664

665
{
666
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2✔
667
        ReportError(CE_Failure, CPLE_NotSupported,
2✔
668
                    "WriteBlock() not supported for this dataset.");
669

670
    return (CE_Failure);
2✔
671
}
672

673
/************************************************************************/
674
/*                             WriteBlock()                             */
675
/************************************************************************/
676

677
/**
678
 * \brief Write a block of image data efficiently.
679
 *
680
 * This method accesses a "natural" block from the raster band without
681
 * resampling, or data type conversion.  For a more generalized, but
682
 * potentially less efficient access use RasterIO().
683
 *
684
 * This method is the same as the C GDALWriteBlock() function.
685
 *
686
 * See ReadBlock() for an example of block oriented data access.
687
 *
688
 * @param nXBlockOff the horizontal block offset, with zero indicating
689
 * the left most block, 1 the next block and so forth.
690
 *
691
 * @param nYBlockOff the vertical block offset, with zero indicating
692
 * the left most block, 1 the next block and so forth.
693
 *
694
 * @param pImage the buffer from which the data will be written.  The buffer
695
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
696
 * of type GetRasterDataType(). Note that the content of the buffer might be
697
 * temporarily modified during the execution of this method (and eventually
698
 * restored back to its original content), so it is not safe to use a buffer
699
 * stored in a read-only section of the calling program.
700
 *
701
 * @return CE_None on success or CE_Failure on an error.
702
 */
703

704
CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
4,799✔
705

706
{
707
    /* -------------------------------------------------------------------- */
708
    /*      Validate arguments.                                             */
709
    /* -------------------------------------------------------------------- */
710
    CPLAssert(pImage != nullptr);
4,799✔
711

712
    if (!InitBlockInfo())
4,799✔
713
        return CE_Failure;
×
714

715
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
4,799✔
716
    {
717
        ReportError(CE_Failure, CPLE_IllegalArg,
×
718
                    "Illegal nXBlockOff value (%d) in "
719
                    "GDALRasterBand::WriteBlock()\n",
720
                    nXBlockOff);
721

722
        return (CE_Failure);
×
723
    }
724

725
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
4,799✔
726
    {
727
        ReportError(CE_Failure, CPLE_IllegalArg,
×
728
                    "Illegal nYBlockOff value (%d) in "
729
                    "GDALRasterBand::WriteBlock()\n",
730
                    nYBlockOff);
731

732
        return (CE_Failure);
×
733
    }
734

735
    if (eAccess == GA_ReadOnly)
4,799✔
736
    {
737
        ReportError(CE_Failure, CPLE_NoWriteAccess,
×
738
                    "Attempt to write to read only dataset in"
739
                    "GDALRasterBand::WriteBlock().\n");
740

741
        return (CE_Failure);
×
742
    }
743

744
    if (eFlushBlockErr != CE_None)
4,799✔
745
    {
746
        ReportError(eFlushBlockErr, CPLE_AppDefined,
×
747
                    "An error occurred while writing a dirty block "
748
                    "from GDALRasterBand::WriteBlock");
749
        CPLErr eErr = eFlushBlockErr;
×
750
        eFlushBlockErr = CE_None;
×
751
        return eErr;
×
752
    }
753

754
    /* -------------------------------------------------------------------- */
755
    /*      Invoke underlying implementation method.                        */
756
    /* -------------------------------------------------------------------- */
757

758
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
4,799✔
759
    CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
4,799✔
760
    if (bCallLeaveReadWrite)
4,799✔
761
        LeaveReadWrite();
4,799✔
762

763
    return eErr;
4,799✔
764
}
765

766
/************************************************************************/
767
/*                           GDALWriteBlock()                           */
768
/************************************************************************/
769

770
/**
771
 * \brief Write a block of image data efficiently.
772
 *
773
 * @see GDALRasterBand::WriteBlock()
774
 */
775

776
CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
×
777
                                  void *pData)
778

779
{
780
    VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
×
781

782
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
×
783
    return (poBand->WriteBlock(nXOff, nYOff, pData));
×
784
}
785

786
/************************************************************************/
787
/*                         GetActualBlockSize()                         */
788
/************************************************************************/
789
/**
790
 * \brief Fetch the actual block size for a given block offset.
791
 *
792
 * Handles partial blocks at the edges of the raster and returns the true
793
 * number of pixels
794
 *
795
 * @param nXBlockOff the horizontal block offset for which to calculate the
796
 * number of valid pixels, with zero indicating the left most block, 1 the next
797
 * block and so forth.
798
 *
799
 * @param nYBlockOff the vertical block offset, with zero indicating
800
 * the top most block, 1 the next block and so forth.
801
 *
802
 * @param pnXValid pointer to an integer in which the number of valid pixels in
803
 * the x direction will be stored
804
 *
805
 * @param pnYValid pointer to an integer in which the number of valid pixels in
806
 * the y direction will be stored
807
 *
808
 * @return CE_None if the input parameters are valid, CE_Failure otherwise
809
 *
810
 * @since GDAL 2.2
811
 */
812
CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
45,308✔
813
                                          int *pnXValid, int *pnYValid)
814
{
815
    if (nXBlockOff < 0 || nBlockXSize == 0 ||
90,615✔
816
        nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
90,613✔
817
        nYBlockOff < 0 || nBlockYSize == 0 ||
90,610✔
818
        nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
45,305✔
819
    {
820
        return CE_Failure;
4✔
821
    }
822

823
    const int nXPixelOff = nXBlockOff * nBlockXSize;
45,304✔
824
    const int nYPixelOff = nYBlockOff * nBlockYSize;
45,304✔
825

826
    *pnXValid = nBlockXSize;
45,304✔
827
    *pnYValid = nBlockYSize;
45,304✔
828

829
    if (nXPixelOff >= nRasterXSize - nBlockXSize)
45,304✔
830
    {
831
        *pnXValid = nRasterXSize - nXPixelOff;
43,815✔
832
    }
833

834
    if (nYPixelOff >= nRasterYSize - nBlockYSize)
45,304✔
835
    {
836
        *pnYValid = nRasterYSize - nYPixelOff;
3,203✔
837
    }
838

839
    return CE_None;
45,304✔
840
}
841

842
/************************************************************************/
843
/*                           GDALGetActualBlockSize()                   */
844
/************************************************************************/
845

846
/**
847
 * \brief Retrieve the actual block size for a given block offset.
848
 *
849
 * @see GDALRasterBand::GetActualBlockSize()
850
 */
851

852
CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
6✔
853
                                          int nYBlockOff, int *pnXValid,
854
                                          int *pnYValid)
855

856
{
857
    VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
6✔
858

859
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6✔
860
    return (
861
        poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
6✔
862
}
863

864
/************************************************************************/
865
/*                     GetSuggestedBlockAccessPattern()                 */
866
/************************************************************************/
867

868
/**
869
 * \brief Return the suggested/most efficient access pattern to blocks
870
 *        (for read operations).
871
 *
872
 * While all GDAL drivers have to expose a block size, not all can guarantee
873
 * efficient random access (GSBAP_RANDOM) to any block.
874
 * Some drivers for example decompress sequentially a compressed stream from
875
 * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
876
 * case best performance will be achieved while reading blocks in that order.
877
 * (accessing blocks in random access in such rasters typically causes the
878
 * decoding to be re-initialized from the start if accessing blocks in
879
 * a non-sequential order)
880
 *
881
 * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
882
 * returned by drivers that expose a somewhat artificial block size, because
883
 * they can extract any part of a raster, but in a rather inefficient way.
884
 *
885
 * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
886
 * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
887
 * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
888
 * most efficient strategy is to read as many pixels as possible in the less
889
 * RasterIO() operations.
890
 *
891
 * The return of this method is for example used to determine the swath size
892
 * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
893
 *
894
 * @since GDAL 3.6
895
 */
896

897
GDALSuggestedBlockAccessPattern
898
GDALRasterBand::GetSuggestedBlockAccessPattern() const
1,277✔
899
{
900
    return GSBAP_UNKNOWN;
1,277✔
901
}
902

903
/************************************************************************/
904
/*                         GetRasterDataType()                          */
905
/************************************************************************/
906

907
/**
908
 * \brief Fetch the pixel data type for this band.
909
 *
910
 * This method is the same as the C function GDALGetRasterDataType().
911
 *
912
 * @return the data type of pixels for this band.
913
 */
914

915
GDALDataType GDALRasterBand::GetRasterDataType()
5,254,170✔
916

917
{
918
    return eDataType;
5,254,170✔
919
}
920

921
/************************************************************************/
922
/*                       GDALGetRasterDataType()                        */
923
/************************************************************************/
924

925
/**
926
 * \brief Fetch the pixel data type for this band.
927
 *
928
 * @see GDALRasterBand::GetRasterDataType()
929
 */
930

931
GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
866,962✔
932

933
{
934
    VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
866,962✔
935

936
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
866,962✔
937
    return poBand->GetRasterDataType();
866,962✔
938
}
939

940
/************************************************************************/
941
/*                            GetBlockSize()                            */
942
/************************************************************************/
943

944
/**
945
 * \brief Fetch the "natural" block size of this band.
946
 *
947
 * GDAL contains a concept of the natural block size of rasters so that
948
 * applications can organized data access efficiently for some file formats.
949
 * The natural block size is the block size that is most efficient for
950
 * accessing the format.  For many formats this is simple a whole scanline
951
 * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
952
 *
953
 * However, for tiled images this will typically be the tile size.
954
 *
955
 * Note that the X and Y block sizes don't have to divide the image size
956
 * evenly, meaning that right and bottom edge blocks may be incomplete.
957
 * See ReadBlock() for an example of code dealing with these issues.
958
 *
959
 * This method is the same as the C function GDALGetBlockSize().
960
 *
961
 * @param pnXSize integer to put the X block size into or NULL.
962
 *
963
 * @param pnYSize integer to put the Y block size into or NULL.
964
 */
965

966
void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize)
3,277,610✔
967

968
{
969
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
3,277,610✔
970
    {
971
        ReportError(CE_Failure, CPLE_AppDefined,
13✔
972
                    "Invalid block dimension : %d * %d", nBlockXSize,
973
                    nBlockYSize);
974
        if (pnXSize != nullptr)
×
975
            *pnXSize = 0;
×
976
        if (pnYSize != nullptr)
×
977
            *pnYSize = 0;
×
978
    }
979
    else
980
    {
981
        if (pnXSize != nullptr)
3,277,590✔
982
            *pnXSize = nBlockXSize;
3,277,600✔
983
        if (pnYSize != nullptr)
3,277,590✔
984
            *pnYSize = nBlockYSize;
3,277,590✔
985
    }
986
}
3,277,590✔
987

988
/************************************************************************/
989
/*                          GDALGetBlockSize()                          */
990
/************************************************************************/
991

992
/**
993
 * \brief Fetch the "natural" block size of this band.
994
 *
995
 * @see GDALRasterBand::GetBlockSize()
996
 */
997

998
void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
10,849✔
999
                                  int *pnYSize)
1000

1001
{
1002
    VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
10,849✔
1003

1004
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10,849✔
1005
    poBand->GetBlockSize(pnXSize, pnYSize);
10,849✔
1006
}
1007

1008
/************************************************************************/
1009
/*                           InitBlockInfo()                            */
1010
/************************************************************************/
1011

1012
//! @cond Doxygen_Suppress
1013
int GDALRasterBand::InitBlockInfo()
3,144,100✔
1014

1015
{
1016
    if (poBandBlockCache != nullptr)
3,144,100✔
1017
        return poBandBlockCache->IsInitOK();
3,115,040✔
1018

1019
    /* Do some validation of raster and block dimensions in case the driver */
1020
    /* would have neglected to do it itself */
1021
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
29,059✔
1022
    {
1023
        ReportError(CE_Failure, CPLE_AppDefined,
×
1024
                    "Invalid block dimension : %d * %d", nBlockXSize,
1025
                    nBlockYSize);
1026
        return FALSE;
×
1027
    }
1028

1029
    if (nRasterXSize <= 0 || nRasterYSize <= 0)
29,059✔
1030
    {
1031
        ReportError(CE_Failure, CPLE_AppDefined,
×
1032
                    "Invalid raster dimension : %d * %d", nRasterXSize,
1033
                    nRasterYSize);
1034
        return FALSE;
×
1035
    }
1036

1037
    const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
29,059✔
1038
    if (nDataTypeSize == 0)
29,059✔
1039
    {
1040
        ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
×
1041
        return FALSE;
×
1042
    }
1043

1044
#if SIZEOF_VOIDP == 4
1045
    if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1046
    {
1047
        /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1048
         * multiplication in other cases */
1049
        if (nBlockXSize > INT_MAX / nDataTypeSize ||
1050
            nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1051
        {
1052
            ReportError(CE_Failure, CPLE_NotSupported,
1053
                        "Too big block : %d * %d for 32-bit build", nBlockXSize,
1054
                        nBlockYSize);
1055
            return FALSE;
1056
        }
1057
    }
1058
#endif
1059

1060
    nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
29,059✔
1061
    nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
29,059✔
1062

1063
    const char *pszBlockStrategy =
1064
        CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
29,059✔
1065
    bool bUseArray = true;
29,059✔
1066
    if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
29,059✔
1067
    {
1068
        if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
29,019✔
1069
                                   GDAL_OF_DEFAULT_BLOCK_ACCESS)
1070
        {
1071
            GUIntBig nBlockCount =
29,000✔
1072
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
29,000✔
1073
            if (poDS != nullptr)
29,000✔
1074
                nBlockCount *= poDS->GetRasterCount();
28,757✔
1075
            bUseArray = (nBlockCount < 1024 * 1024);
29,000✔
1076
        }
1077
        else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
19✔
1078
                 GDAL_OF_HASHSET_BLOCK_ACCESS)
1079
        {
1080
            bUseArray = false;
×
1081
        }
29,019✔
1082
    }
1083
    else if (EQUAL(pszBlockStrategy, "HASHSET"))
40✔
1084
        bUseArray = false;
40✔
1085
    else if (!EQUAL(pszBlockStrategy, "ARRAY"))
×
1086
        CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
×
1087
                 pszBlockStrategy);
1088

1089
    if (bUseArray)
29,059✔
1090
        poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
28,989✔
1091
    else
1092
    {
1093
        if (nBand == 1)
70✔
1094
            CPLDebug("GDAL", "Use hashset band block cache");
25✔
1095
        poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
70✔
1096
    }
1097
    if (poBandBlockCache == nullptr)
29,059✔
1098
        return FALSE;
×
1099
    return poBandBlockCache->Init();
29,059✔
1100
}
1101

1102
//! @endcond
1103

1104
/************************************************************************/
1105
/*                             FlushCache()                             */
1106
/************************************************************************/
1107

1108
/**
1109
 * \brief Flush raster data cache.
1110
 *
1111
 * This call will recover memory used to cache data blocks for this raster
1112
 * band, and ensure that new requests are referred to the underlying driver.
1113
 *
1114
 * This method is the same as the C function GDALFlushRasterCache().
1115
 *
1116
 * @param bAtClosing Whether this is called from a GDALDataset destructor
1117
 * @return CE_None on success.
1118
 */
1119

1120
CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
2,913,430✔
1121

1122
{
1123
    if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
2,956,800✔
1124
        poBandBlockCache)
43,367✔
1125
        poBandBlockCache->DisableDirtyBlockWriting();
2,041✔
1126

1127
    CPLErr eGlobalErr = eFlushBlockErr;
2,913,410✔
1128

1129
    if (eFlushBlockErr != CE_None)
2,913,410✔
1130
    {
1131
        ReportError(
1✔
1132
            eFlushBlockErr, CPLE_AppDefined,
1133
            "An error occurred while writing a dirty block from FlushCache");
1134
        eFlushBlockErr = CE_None;
1✔
1135
    }
1136

1137
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
2,913,410✔
1138
        return eGlobalErr;
2,774,780✔
1139

1140
    return poBandBlockCache->FlushCache();
138,628✔
1141
}
1142

1143
/************************************************************************/
1144
/*                        GDALFlushRasterCache()                        */
1145
/************************************************************************/
1146

1147
/**
1148
 * \brief Flush raster data cache.
1149
 *
1150
 * @see GDALRasterBand::FlushCache()
1151
 */
1152

1153
CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
129✔
1154

1155
{
1156
    VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
129✔
1157

1158
    return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
129✔
1159
}
1160

1161
/************************************************************************/
1162
/*                             DropCache()                              */
1163
/************************************************************************/
1164

1165
/**
1166
* \brief Drop raster data cache : data in cache will be lost.
1167
*
1168
* This call will recover memory used to cache data blocks for this raster
1169
* band, and ensure that new requests are referred to the underlying driver.
1170
*
1171
* This method is the same as the C function GDALDropRasterCache().
1172
*
1173
* @return CE_None on success.
1174
* @since 3.9
1175
*/
1176

1177
CPLErr GDALRasterBand::DropCache()
1✔
1178

1179
{
1180
    CPLErr result = CE_None;
1✔
1181

1182
    if (poBandBlockCache)
1✔
1183
        poBandBlockCache->DisableDirtyBlockWriting();
1✔
1184

1185
    CPLErr eGlobalErr = eFlushBlockErr;
1✔
1186

1187
    if (eFlushBlockErr != CE_None)
1✔
1188
    {
1189
        ReportError(
×
1190
            eFlushBlockErr, CPLE_AppDefined,
1191
            "An error occurred while writing a dirty block from DropCache");
1192
        eFlushBlockErr = CE_None;
×
1193
    }
1194

1195
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1✔
1196
        result = eGlobalErr;
×
1197
    else
1198
        result = poBandBlockCache->FlushCache();
1✔
1199

1200
    if (poBandBlockCache)
1✔
1201
        poBandBlockCache->EnableDirtyBlockWriting();
1✔
1202

1203
    return result;
1✔
1204
}
1205

1206
/************************************************************************/
1207
/*                        GDALDropRasterCache()                         */
1208
/************************************************************************/
1209

1210
/**
1211
* \brief Drop raster data cache.
1212
*
1213
* @see GDALRasterBand::DropCache()
1214
* @since 3.9
1215
*/
1216

1217
CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
×
1218

1219
{
1220
    VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
×
1221

1222
    return GDALRasterBand::FromHandle(hBand)->DropCache();
×
1223
}
1224

1225
/************************************************************************/
1226
/*                        UnreferenceBlock()                            */
1227
/*                                                                      */
1228
/*      Unreference the block from our array of blocks                  */
1229
/*      This method should only be called by                            */
1230
/*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1231
/*      the block cache mutex)                                          */
1232
/************************************************************************/
1233

1234
CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
29,638✔
1235
{
1236
#ifdef notdef
1237
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1238
    {
1239
        if (poBandBlockCache == nullptr)
1240
            printf("poBandBlockCache == NULL\n"); /*ok*/
1241
        else
1242
            printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1243
        printf("caller = %s\n", pszCaller);            /*ok*/
1244
        printf("GDALRasterBand: %p\n", this);          /*ok*/
1245
        printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
1246
        printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
1247
        printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
1248
        printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
1249
        printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
1250
        poBlock->DumpBlock();
1251
        if (GetDataset() != nullptr)
1252
            printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1253
        GDALRasterBlock::Verify();
1254
        abort();
1255
    }
1256
#endif
1257
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
29,638✔
1258
    return poBandBlockCache->UnreferenceBlock(poBlock);
29,638✔
1259
}
1260

1261
/************************************************************************/
1262
/*                        AddBlockToFreeList()                          */
1263
/*                                                                      */
1264
/*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
1265
/*      finished with a block about to be free'd, they pass it to that  */
1266
/*      method.                                                         */
1267
/************************************************************************/
1268

1269
//! @cond Doxygen_Suppress
1270
void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
29,637✔
1271
{
1272
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
29,637✔
1273
    return poBandBlockCache->AddBlockToFreeList(poBlock);
29,638✔
1274
}
1275

1276
//! @endcond
1277

1278
/************************************************************************/
1279
/*                             FlushBlock()                             */
1280
/************************************************************************/
1281

1282
/** Flush a block out of the block cache.
1283
 * @param nXBlockOff block x offset
1284
 * @param nYBlockOff blocky offset
1285
 * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1286
 * @return CE_None in case of success, an error code otherwise.
1287
 */
1288
CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
2,285✔
1289
                                  int bWriteDirtyBlock)
1290

1291
{
1292
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
2,285✔
1293
        return (CE_Failure);
×
1294

1295
    /* -------------------------------------------------------------------- */
1296
    /*      Validate the request                                            */
1297
    /* -------------------------------------------------------------------- */
1298
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
2,285✔
1299
    {
1300
        ReportError(CE_Failure, CPLE_IllegalArg,
×
1301
                    "Illegal nBlockXOff value (%d) in "
1302
                    "GDALRasterBand::FlushBlock()\n",
1303
                    nXBlockOff);
1304

1305
        return (CE_Failure);
×
1306
    }
1307

1308
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
2,285✔
1309
    {
1310
        ReportError(CE_Failure, CPLE_IllegalArg,
×
1311
                    "Illegal nBlockYOff value (%d) in "
1312
                    "GDALRasterBand::FlushBlock()\n",
1313
                    nYBlockOff);
1314

1315
        return (CE_Failure);
×
1316
    }
1317

1318
    return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
2,285✔
1319
                                        bWriteDirtyBlock);
2,285✔
1320
}
1321

1322
/************************************************************************/
1323
/*                        TryGetLockedBlockRef()                        */
1324
/************************************************************************/
1325

1326
/**
1327
 * \brief Try fetching block ref.
1328
 *
1329
 * This method will returned the requested block (locked) if it is already
1330
 * in the block cache for the layer.  If not, nullptr is returned.
1331
 *
1332
 * If a non-NULL value is returned, then a lock for the block will have been
1333
 * acquired on behalf of the caller.  It is absolutely imperative that the
1334
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1335
 * severe problems may result.
1336
 *
1337
 * @param nXBlockOff the horizontal block offset, with zero indicating
1338
 * the left most block, 1 the next block and so forth.
1339
 *
1340
 * @param nYBlockOff the vertical block offset, with zero indicating
1341
 * the top most block, 1 the next block and so forth.
1342
 *
1343
 * @return NULL if block not available, or locked block pointer.
1344
 */
1345

1346
GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
9,498,100✔
1347
                                                      int nYBlockOff)
1348

1349
{
1350
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
9,498,100✔
1351
        return nullptr;
54,277✔
1352

1353
    /* -------------------------------------------------------------------- */
1354
    /*      Validate the request                                            */
1355
    /* -------------------------------------------------------------------- */
1356
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
9,443,830✔
1357
    {
1358
        ReportError(CE_Failure, CPLE_IllegalArg,
2✔
1359
                    "Illegal nBlockXOff value (%d) in "
1360
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1361
                    nXBlockOff);
1362

1363
        return (nullptr);
×
1364
    }
1365

1366
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
9,443,830✔
1367
    {
1368
        ReportError(CE_Failure, CPLE_IllegalArg,
×
1369
                    "Illegal nBlockYOff value (%d) in "
1370
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1371
                    nYBlockOff);
1372

1373
        return (nullptr);
×
1374
    }
1375

1376
    return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
9,443,830✔
1377
}
1378

1379
/************************************************************************/
1380
/*                         GetLockedBlockRef()                          */
1381
/************************************************************************/
1382

1383
/**
1384
 * \brief Fetch a pointer to an internally cached raster block.
1385
 *
1386
 * This method will returned the requested block (locked) if it is already
1387
 * in the block cache for the layer.  If not, the block will be read from
1388
 * the driver, and placed in the layer block cached, then returned.  If an
1389
 * error occurs reading the block from the driver, a NULL value will be
1390
 * returned.
1391
 *
1392
 * If a non-NULL value is returned, then a lock for the block will have been
1393
 * acquired on behalf of the caller.  It is absolutely imperative that the
1394
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1395
 * severe problems may result.
1396
 *
1397
 * Note that calling GetLockedBlockRef() on a previously uncached band will
1398
 * enable caching.
1399
 *
1400
 * @param nXBlockOff the horizontal block offset, with zero indicating
1401
 * the left most block, 1 the next block and so forth.
1402
 *
1403
 * @param nYBlockOff the vertical block offset, with zero indicating
1404
 * the top most block, 1 the next block and so forth.
1405
 *
1406
 * @param bJustInitialize If TRUE the block will be allocated and initialized,
1407
 * but not actually read from the source.  This is useful when it will just
1408
 * be completely set and written back.
1409
 *
1410
 * @return pointer to the block object, or NULL on failure.
1411
 */
1412

1413
GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
9,304,320✔
1414
                                                   int nYBlockOff,
1415
                                                   int bJustInitialize)
1416

1417
{
1418
    /* -------------------------------------------------------------------- */
1419
    /*      Try and fetch from cache.                                       */
1420
    /* -------------------------------------------------------------------- */
1421
    GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
9,304,320✔
1422

1423
    /* -------------------------------------------------------------------- */
1424
    /*      If we didn't find it in our memory cache, instantiate a         */
1425
    /*      block (potentially load from disk) and "adopt" it into the      */
1426
    /*      cache.                                                          */
1427
    /* -------------------------------------------------------------------- */
1428
    if (poBlock == nullptr)
9,304,350✔
1429
    {
1430
        if (!InitBlockInfo())
2,967,620✔
1431
            return (nullptr);
×
1432

1433
        /* --------------------------------------------------------------------
1434
         */
1435
        /*      Validate the request */
1436
        /* --------------------------------------------------------------------
1437
         */
1438
        if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
2,967,610✔
1439
        {
1440
            ReportError(CE_Failure, CPLE_IllegalArg,
×
1441
                        "Illegal nBlockXOff value (%d) in "
1442
                        "GDALRasterBand::GetLockedBlockRef()\n",
1443
                        nXBlockOff);
1444

1445
            return (nullptr);
×
1446
        }
1447

1448
        if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
2,967,610✔
1449
        {
1450
            ReportError(CE_Failure, CPLE_IllegalArg,
×
1451
                        "Illegal nBlockYOff value (%d) in "
1452
                        "GDALRasterBand::GetLockedBlockRef()\n",
1453
                        nYBlockOff);
1454

1455
            return (nullptr);
×
1456
        }
1457

1458
        poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2,967,620✔
1459
        if (poBlock == nullptr)
2,967,620✔
1460
            return nullptr;
×
1461

1462
        poBlock->AddLock();
2,967,620✔
1463

1464
        /* We need to temporarily drop the read-write lock in the following */
1465
        /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
1466
         */
1467
        /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
1468
        /* block cache fills, T1 might need to flush dirty blocks of D2 in the
1469
         */
1470
        /* below Internalize(), which will cause GDALRasterBlock::Write() to be
1471
         */
1472
        /* called and attempt at taking the lock on T2 (already taken).
1473
         * Similarly */
1474
        /* for T2 with D1, hence a deadlock situation (#6163) */
1475
        /* But this may open the door to other problems... */
1476
        if (poDS)
2,967,620✔
1477
            poDS->TemporarilyDropReadWriteLock();
2,966,580✔
1478
        /* allocate data space */
1479
        CPLErr eErr = poBlock->Internalize();
2,967,620✔
1480
        if (poDS)
2,967,600✔
1481
            poDS->ReacquireReadWriteLock();
2,966,580✔
1482
        if (eErr != CE_None)
2,967,620✔
1483
        {
1484
            poBlock->DropLock();
×
1485
            delete poBlock;
×
1486
            return nullptr;
×
1487
        }
1488

1489
        if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2,967,620✔
1490
        {
1491
            poBlock->DropLock();
×
1492
            delete poBlock;
×
1493
            return nullptr;
×
1494
        }
1495

1496
        if (!bJustInitialize)
2,967,620✔
1497
        {
1498
            const GUInt32 nErrorCounter = CPLGetErrorCounter();
2,649,130✔
1499
            int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2,649,130✔
1500
            eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2,649,130✔
1501
            if (bCallLeaveReadWrite)
2,649,130✔
1502
                LeaveReadWrite();
127,770✔
1503
            if (eErr != CE_None)
2,649,130✔
1504
            {
1505
                poBlock->DropLock();
1,144✔
1506
                FlushBlock(nXBlockOff, nYBlockOff);
1,144✔
1507
                ReportError(CE_Failure, CPLE_AppDefined,
1,144✔
1508
                            "IReadBlock failed at X offset %d, Y offset %d%s",
1509
                            nXBlockOff, nYBlockOff,
1510
                            (nErrorCounter != CPLGetErrorCounter())
1,144✔
1511
                                ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
1,142✔
1512
                                : "");
1513
                return nullptr;
1,144✔
1514
            }
1515

1516
            nBlockReads++;
2,647,980✔
1517
            if (static_cast<GIntBig>(nBlockReads) ==
2,647,980✔
1518
                    static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2,647,980✔
1519
                        1 &&
190✔
1520
                nBand == 1 && poDS != nullptr)
190✔
1521
            {
1522
                CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
139✔
1523
                         poDS->GetDescription());
139✔
1524
            }
1525
        }
1526
    }
1527

1528
    return poBlock;
9,303,210✔
1529
}
1530

1531
/************************************************************************/
1532
/*                               Fill()                                 */
1533
/************************************************************************/
1534

1535
/**
1536
 * \brief Fill this band with a constant value.
1537
 *
1538
 * GDAL makes no guarantees
1539
 * about what values pixels in newly created files are set to, so this
1540
 * method can be used to clear a band to a specified "default" value.
1541
 * The fill value is passed in as a double but this will be converted
1542
 * to the underlying type before writing to the file. An optional
1543
 * second argument allows the imaginary component of a complex
1544
 * constant value to be specified.
1545
 *
1546
 * This method is the same as the C function GDALFillRaster().
1547
 *
1548
 * @param dfRealValue Real component of fill value
1549
 * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
1550
 *
1551
 * @return CE_Failure if the write fails, otherwise CE_None
1552
 */
1553
CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
169,125✔
1554
{
1555

1556
    // General approach is to construct a source block of the file's
1557
    // native type containing the appropriate value and then copy this
1558
    // to each block in the image via the RasterBlock cache. Using
1559
    // the cache means we avoid file I/O if it is not necessary, at the
1560
    // expense of some extra memcpy's (since we write to the
1561
    // RasterBlock cache, which is then at some point written to the
1562
    // underlying file, rather than simply directly to the underlying
1563
    // file.)
1564

1565
    // Check we can write to the file.
1566
    if (eAccess == GA_ReadOnly)
169,125✔
1567
    {
1568
        ReportError(CE_Failure, CPLE_NoWriteAccess,
1✔
1569
                    "Attempt to write to read only dataset in "
1570
                    "GDALRasterBand::Fill().");
1571
        return CE_Failure;
1✔
1572
    }
1573

1574
    // Make sure block parameters are set.
1575
    if (!InitBlockInfo())
169,124✔
1576
        return CE_Failure;
×
1577

1578
    // Allocate the source block.
1579
    auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
169,124✔
1580
    int elementSize = GDALGetDataTypeSizeBytes(eDataType);
169,124✔
1581
    auto blockByteSize = blockSize * elementSize;
169,124✔
1582
    unsigned char *srcBlock =
1583
        static_cast<unsigned char *>(VSIMalloc(blockByteSize));
169,124✔
1584
    if (srcBlock == nullptr)
169,124✔
1585
    {
1586
        ReportError(CE_Failure, CPLE_OutOfMemory,
×
1587
                    "GDALRasterBand::Fill(): Out of memory "
1588
                    "allocating " CPL_FRMT_GUIB " bytes.\n",
1589
                    static_cast<GUIntBig>(blockByteSize));
1590
        return CE_Failure;
×
1591
    }
1592

1593
    // Initialize the source block.
1594
    double complexSrc[2] = {dfRealValue, dfImaginaryValue};
169,124✔
1595
    GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
169,124✔
1596
                    elementSize, blockSize);
1597

1598
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
169,124✔
1599

1600
    // Write block to block cache
1601
    for (int j = 0; j < nBlocksPerColumn; ++j)
627,190✔
1602
    {
1603
        for (int i = 0; i < nBlocksPerRow; ++i)
1,210,460✔
1604
        {
1605
            GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
752,397✔
1606
            if (destBlock == nullptr)
752,397✔
1607
            {
1608
                ReportError(CE_Failure, CPLE_OutOfMemory,
×
1609
                            "GDALRasterBand::Fill(): Error "
1610
                            "while retrieving cache block.");
1611
                VSIFree(srcBlock);
×
1612
                return CE_Failure;
×
1613
            }
1614
            memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
752,397✔
1615
            destBlock->MarkDirty();
752,397✔
1616
            destBlock->DropLock();
752,397✔
1617
        }
1618
    }
1619

1620
    if (bCallLeaveReadWrite)
169,124✔
1621
        LeaveReadWrite();
168,655✔
1622

1623
    // Free up the source block
1624
    VSIFree(srcBlock);
169,124✔
1625

1626
    return CE_None;
169,124✔
1627
}
1628

1629
/************************************************************************/
1630
/*                         GDALFillRaster()                             */
1631
/************************************************************************/
1632

1633
/**
1634
 * \brief Fill this band with a constant value.
1635
 *
1636
 * @see GDALRasterBand::Fill()
1637
 */
1638
CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
169,091✔
1639
                                  double dfImaginaryValue)
1640
{
1641
    VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
169,091✔
1642

1643
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
169,091✔
1644
    return poBand->Fill(dfRealValue, dfImaginaryValue);
169,091✔
1645
}
1646

1647
/************************************************************************/
1648
/*                             GetAccess()                              */
1649
/************************************************************************/
1650

1651
/**
1652
 * \brief Find out if we have update permission for this band.
1653
 *
1654
 * This method is the same as the C function GDALGetRasterAccess().
1655
 *
1656
 * @return Either GA_Update or GA_ReadOnly.
1657
 */
1658

1659
GDALAccess GDALRasterBand::GetAccess()
2,407✔
1660

1661
{
1662
    return eAccess;
2,407✔
1663
}
1664

1665
/************************************************************************/
1666
/*                        GDALGetRasterAccess()                         */
1667
/************************************************************************/
1668

1669
/**
1670
 * \brief Find out if we have update permission for this band.
1671
 *
1672
 * @see GDALRasterBand::GetAccess()
1673
 */
1674

1675
GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
1,770✔
1676

1677
{
1678
    VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
1,770✔
1679

1680
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1,770✔
1681
    return poBand->GetAccess();
1,770✔
1682
}
1683

1684
/************************************************************************/
1685
/*                          GetCategoryNames()                          */
1686
/************************************************************************/
1687

1688
/**
1689
 * \brief Fetch the list of category names for this raster.
1690
 *
1691
 * The return list is a "StringList" in the sense of the CPL functions.
1692
 * That is a NULL terminated array of strings.  Raster values without
1693
 * associated names will have an empty string in the returned list.  The
1694
 * first entry in the list is for raster values of zero, and so on.
1695
 *
1696
 * The returned stringlist should not be altered or freed by the application.
1697
 * It may change on the next GDAL call, so please copy it if it is needed
1698
 * for any period of time.
1699
 *
1700
 * This method is the same as the C function GDALGetRasterCategoryNames().
1701
 *
1702
 * @return list of names, or NULL if none.
1703
 */
1704

1705
char **GDALRasterBand::GetCategoryNames()
207✔
1706

1707
{
1708
    return nullptr;
207✔
1709
}
1710

1711
/************************************************************************/
1712
/*                     GDALGetRasterCategoryNames()                     */
1713
/************************************************************************/
1714

1715
/**
1716
 * \brief Fetch the list of category names for this raster.
1717
 *
1718
 * @see GDALRasterBand::GetCategoryNames()
1719
 */
1720

1721
char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
155✔
1722

1723
{
1724
    VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
155✔
1725

1726
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
155✔
1727
    return poBand->GetCategoryNames();
155✔
1728
}
1729

1730
/************************************************************************/
1731
/*                          SetCategoryNames()                          */
1732
/************************************************************************/
1733

1734
/**
1735
 * \fn GDALRasterBand::SetCategoryNames(char**)
1736
 * \brief Set the category names for this band.
1737
 *
1738
 * See the GetCategoryNames() method for more on the interpretation of
1739
 * category names.
1740
 *
1741
 * This method is the same as the C function GDALSetRasterCategoryNames().
1742
 *
1743
 * @param papszNames the NULL terminated StringList of category names.  May
1744
 * be NULL to just clear the existing list.
1745
 *
1746
 * @return CE_None on success of CE_Failure on failure.  If unsupported
1747
 * by the driver CE_Failure is returned, but no error message is reported.
1748
 */
1749

1750
/**/
1751
/**/
1752

1753
CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
×
1754
{
1755
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
×
1756
        ReportError(CE_Failure, CPLE_NotSupported,
×
1757
                    "SetCategoryNames() not supported for this dataset.");
1758

1759
    return CE_Failure;
×
1760
}
1761

1762
/************************************************************************/
1763
/*                        GDALSetCategoryNames()                        */
1764
/************************************************************************/
1765

1766
/**
1767
 * \brief Set the category names for this band.
1768
 *
1769
 * @see GDALRasterBand::SetCategoryNames()
1770
 */
1771

1772
CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2✔
1773
                                              CSLConstList papszNames)
1774

1775
{
1776
    VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2✔
1777

1778
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2✔
1779
    return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2✔
1780
}
1781

1782
/************************************************************************/
1783
/*                           GetNoDataValue()                           */
1784
/************************************************************************/
1785

1786
/**
1787
 * \brief Fetch the no data value for this band.
1788
 *
1789
 * If there is no out of data value, an out of range value will generally
1790
 * be returned.  The no data value for a band is generally a special marker
1791
 * value used to mark pixels that are not valid data.  Such pixels should
1792
 * generally not be displayed, nor contribute to analysis operations.
1793
 *
1794
 * The no data value returned is 'raw', meaning that it has no offset and
1795
 * scale applied.
1796
 *
1797
 * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
1798
 * lossy if the nodata value cannot exactly been represented by a double.
1799
 * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
1800
 *
1801
 * This method is the same as the C function GDALGetRasterNoDataValue().
1802
 *
1803
 * @param pbSuccess pointer to a boolean to use to indicate if a value
1804
 * is actually associated with this layer.  May be NULL (default).
1805
 *
1806
 * @return the nodata value for this band.
1807
 */
1808

1809
double GDALRasterBand::GetNoDataValue(int *pbSuccess)
31,196✔
1810

1811
{
1812
    if (pbSuccess != nullptr)
31,196✔
1813
        *pbSuccess = FALSE;
31,196✔
1814

1815
    return -1e10;
31,196✔
1816
}
1817

1818
/************************************************************************/
1819
/*                      GDALGetRasterNoDataValue()                      */
1820
/************************************************************************/
1821

1822
/**
1823
 * \brief Fetch the no data value for this band.
1824
 *
1825
 * @see GDALRasterBand::GetNoDataValue()
1826
 */
1827

1828
double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
413,390✔
1829
                                            int *pbSuccess)
1830

1831
{
1832
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
413,390✔
1833

1834
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
413,390✔
1835
    return poBand->GetNoDataValue(pbSuccess);
413,390✔
1836
}
1837

1838
/************************************************************************/
1839
/*                       GetNoDataValueAsInt64()                        */
1840
/************************************************************************/
1841

1842
/**
1843
 * \brief Fetch the no data value for this band.
1844
 *
1845
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
1846
 *
1847
 * If there is no out of data value, an out of range value will generally
1848
 * be returned.  The no data value for a band is generally a special marker
1849
 * value used to mark pixels that are not valid data.  Such pixels should
1850
 * generally not be displayed, nor contribute to analysis operations.
1851
 *
1852
 * The no data value returned is 'raw', meaning that it has no offset and
1853
 * scale applied.
1854
 *
1855
 * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
1856
 *
1857
 * @param pbSuccess pointer to a boolean to use to indicate if a value
1858
 * is actually associated with this layer.  May be NULL (default).
1859
 *
1860
 * @return the nodata value for this band.
1861
 *
1862
 * @since GDAL 3.5
1863
 */
1864

1865
int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2✔
1866

1867
{
1868
    if (pbSuccess != nullptr)
2✔
1869
        *pbSuccess = FALSE;
2✔
1870

1871
    return std::numeric_limits<int64_t>::min();
2✔
1872
}
1873

1874
/************************************************************************/
1875
/*                   GDALGetRasterNoDataValueAsInt64()                  */
1876
/************************************************************************/
1877

1878
/**
1879
 * \brief Fetch the no data value for this band.
1880
 *
1881
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
1882
 *
1883
 * @see GDALRasterBand::GetNoDataValueAsInt64()
1884
 *
1885
 * @since GDAL 3.5
1886
 */
1887

1888
int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
21✔
1889
                                                    int *pbSuccess)
1890

1891
{
1892
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
21✔
1893
                      std::numeric_limits<int64_t>::min());
1894

1895
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
21✔
1896
    return poBand->GetNoDataValueAsInt64(pbSuccess);
21✔
1897
}
1898

1899
/************************************************************************/
1900
/*                       GetNoDataValueAsUInt64()                        */
1901
/************************************************************************/
1902

1903
/**
1904
 * \brief Fetch the no data value for this band.
1905
 *
1906
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
1907
 *
1908
 * If there is no out of data value, an out of range value will generally
1909
 * be returned.  The no data value for a band is generally a special marker
1910
 * value used to mark pixels that are not valid data.  Such pixels should
1911
 * generally not be displayed, nor contribute to analysis operations.
1912
 *
1913
 * The no data value returned is 'raw', meaning that it has no offset and
1914
 * scale applied.
1915
 *
1916
 * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
1917
 *
1918
 * @param pbSuccess pointer to a boolean to use to indicate if a value
1919
 * is actually associated with this layer.  May be NULL (default).
1920
 *
1921
 * @return the nodata value for this band.
1922
 *
1923
 * @since GDAL 3.5
1924
 */
1925

1926
uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2✔
1927

1928
{
1929
    if (pbSuccess != nullptr)
2✔
1930
        *pbSuccess = FALSE;
2✔
1931

1932
    return std::numeric_limits<uint64_t>::max();
2✔
1933
}
1934

1935
/************************************************************************/
1936
/*                   GDALGetRasterNoDataValueAsUInt64()                  */
1937
/************************************************************************/
1938

1939
/**
1940
 * \brief Fetch the no data value for this band.
1941
 *
1942
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
1943
 *
1944
 * @see GDALRasterBand::GetNoDataValueAsUInt64()
1945
 *
1946
 * @since GDAL 3.5
1947
 */
1948

1949
uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
17✔
1950
                                                      int *pbSuccess)
1951

1952
{
1953
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
17✔
1954
                      std::numeric_limits<uint64_t>::max());
1955

1956
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
17✔
1957
    return poBand->GetNoDataValueAsUInt64(pbSuccess);
17✔
1958
}
1959

1960
/************************************************************************/
1961
/*                           SetNoDataValue()                           */
1962
/************************************************************************/
1963

1964
/**
1965
 * \fn GDALRasterBand::SetNoDataValue(double)
1966
 * \brief Set the no data value for this band.
1967
 *
1968
 * Depending on drivers, changing the no data value may or may not have an
1969
 * effect on the pixel values of a raster that has just been created. It is
1970
 * thus advised to explicitly called Fill() if the intent is to initialize
1971
 * the raster to the nodata value.
1972
 * In any case, changing an existing no data value, when one already exists and
1973
 * the dataset exists or has been initialized, has no effect on the pixel whose
1974
 * value matched the previous nodata value.
1975
 *
1976
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
1977
 * be represented by a double, use SetNoDataValueAsInt64() or
1978
 * SetNoDataValueAsUInt64() instead.
1979
 *
1980
 * To clear the nodata value, use DeleteNoDataValue().
1981
 *
1982
 * This method is the same as the C function GDALSetRasterNoDataValue().
1983
 *
1984
 * @param dfNoData the value to set.
1985
 *
1986
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
1987
 * by the driver, CE_Failure is returned by no error message will have
1988
 * been emitted.
1989
 */
1990

1991
/**/
1992
/**/
1993

1994
CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
×
1995

1996
{
1997
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
×
1998
        ReportError(CE_Failure, CPLE_NotSupported,
×
1999
                    "SetNoDataValue() not supported for this dataset.");
2000

2001
    return CE_Failure;
×
2002
}
2003

2004
/************************************************************************/
2005
/*                         GDALSetRasterNoDataValue()                   */
2006
/************************************************************************/
2007

2008
/**
2009
 * \brief Set the no data value for this band.
2010
 *
2011
 * Depending on drivers, changing the no data value may or may not have an
2012
 * effect on the pixel values of a raster that has just been created. It is
2013
 * thus advised to explicitly called Fill() if the intent is to initialize
2014
 * the raster to the nodata value.
2015
 * In any case, changing an existing no data value, when one already exists and
2016
 * the dataset exists or has been initialized, has no effect on the pixel whose
2017
 * value matched the previous nodata value.
2018
 *
2019
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2020
 * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2021
 * GDALSetRasterNoDataValueAsUInt64() instead.
2022
 *
2023
 * @see GDALRasterBand::SetNoDataValue()
2024
 */
2025

2026
CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
556✔
2027
                                            double dfValue)
2028

2029
{
2030
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
556✔
2031

2032
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
556✔
2033
    return poBand->SetNoDataValue(dfValue);
556✔
2034
}
2035

2036
/************************************************************************/
2037
/*                       SetNoDataValueAsInt64()                        */
2038
/************************************************************************/
2039

2040
/**
2041
 * \brief Set the no data value for this band.
2042
 *
2043
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2044
 *
2045
 * Depending on drivers, changing the no data value may or may not have an
2046
 * effect on the pixel values of a raster that has just been created. It is
2047
 * thus advised to explicitly called Fill() if the intent is to initialize
2048
 * the raster to the nodata value.
2049
 * In ay case, changing an existing no data value, when one already exists and
2050
 * the dataset exists or has been initialized, has no effect on the pixel whose
2051
 * value matched the previous nodata value.
2052
 *
2053
 * To clear the nodata value, use DeleteNoDataValue().
2054
 *
2055
 * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2056
 *
2057
 * @param nNoDataValue the value to set.
2058
 *
2059
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2060
 * by the driver, CE_Failure is returned by no error message will have
2061
 * been emitted.
2062
 *
2063
 * @since GDAL 3.5
2064
 */
2065

2066
CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
×
2067

2068
{
2069
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
×
2070
        ReportError(CE_Failure, CPLE_NotSupported,
×
2071
                    "SetNoDataValueAsInt64() not supported for this dataset.");
2072

2073
    return CE_Failure;
×
2074
}
2075

2076
/************************************************************************/
2077
/*                 GDALSetRasterNoDataValueAsInt64()                    */
2078
/************************************************************************/
2079

2080
/**
2081
 * \brief Set the no data value for this band.
2082
 *
2083
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2084
 *
2085
 * Depending on drivers, changing the no data value may or may not have an
2086
 * effect on the pixel values of a raster that has just been created. It is
2087
 * thus advised to explicitly called Fill() if the intent is to initialize
2088
 * the raster to the nodata value.
2089
 * In ay case, changing an existing no data value, when one already exists and
2090
 * the dataset exists or has been initialized, has no effect on the pixel whose
2091
 * value matched the previous nodata value.
2092
 *
2093
 * @see GDALRasterBand::SetNoDataValueAsInt64()
2094
 *
2095
 * @since GDAL 3.5
2096
 */
2097

2098
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
11✔
2099
                                                   int64_t nValue)
2100

2101
{
2102
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
11✔
2103

2104
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11✔
2105
    return poBand->SetNoDataValueAsInt64(nValue);
11✔
2106
}
2107

2108
/************************************************************************/
2109
/*                       SetNoDataValueAsUInt64()                       */
2110
/************************************************************************/
2111

2112
/**
2113
 * \brief Set the no data value for this band.
2114
 *
2115
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2116
 *
2117
 * Depending on drivers, changing the no data value may or may not have an
2118
 * effect on the pixel values of a raster that has just been created. It is
2119
 * thus advised to explicitly called Fill() if the intent is to initialize
2120
 * the raster to the nodata value.
2121
 * In ay case, changing an existing no data value, when one already exists and
2122
 * the dataset exists or has been initialized, has no effect on the pixel whose
2123
 * value matched the previous nodata value.
2124
 *
2125
 * To clear the nodata value, use DeleteNoDataValue().
2126
 *
2127
 * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2128
 *
2129
 * @param nNoDataValue the value to set.
2130
 *
2131
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2132
 * by the driver, CE_Failure is returned by no error message will have
2133
 * been emitted.
2134
 *
2135
 * @since GDAL 3.5
2136
 */
2137

2138
CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
×
2139

2140
{
2141
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
×
2142
        ReportError(CE_Failure, CPLE_NotSupported,
×
2143
                    "SetNoDataValueAsUInt64() not supported for this dataset.");
2144

2145
    return CE_Failure;
×
2146
}
2147

2148
/************************************************************************/
2149
/*                 GDALSetRasterNoDataValueAsUInt64()                    */
2150
/************************************************************************/
2151

2152
/**
2153
 * \brief Set the no data value for this band.
2154
 *
2155
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2156
 *
2157
 * Depending on drivers, changing the no data value may or may not have an
2158
 * effect on the pixel values of a raster that has just been created. It is
2159
 * thus advised to explicitly called Fill() if the intent is to initialize
2160
 * the raster to the nodata value.
2161
 * In ay case, changing an existing no data value, when one already exists and
2162
 * the dataset exists or has been initialized, has no effect on the pixel whose
2163
 * value matched the previous nodata value.
2164
 *
2165
 * @see GDALRasterBand::SetNoDataValueAsUInt64()
2166
 *
2167
 * @since GDAL 3.5
2168
 */
2169

2170
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
10✔
2171
                                                    uint64_t nValue)
2172

2173
{
2174
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
10✔
2175

2176
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10✔
2177
    return poBand->SetNoDataValueAsUInt64(nValue);
10✔
2178
}
2179

2180
/************************************************************************/
2181
/*                        DeleteNoDataValue()                           */
2182
/************************************************************************/
2183

2184
/**
2185
 * \brief Remove the no data value for this band.
2186
 *
2187
 * This method is the same as the C function GDALDeleteRasterNoDataValue().
2188
 *
2189
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2190
 * by the driver, CE_Failure is returned by no error message will have
2191
 * been emitted.
2192
 *
2193
 * @since GDAL 2.1
2194
 */
2195

2196
CPLErr GDALRasterBand::DeleteNoDataValue()
×
2197

2198
{
2199
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
×
2200
        ReportError(CE_Failure, CPLE_NotSupported,
×
2201
                    "DeleteNoDataValue() not supported for this dataset.");
2202

2203
    return CE_Failure;
×
2204
}
2205

2206
/************************************************************************/
2207
/*                       GDALDeleteRasterNoDataValue()                  */
2208
/************************************************************************/
2209

2210
/**
2211
 * \brief Remove the no data value for this band.
2212
 *
2213
 * @see GDALRasterBand::DeleteNoDataValue()
2214
 *
2215
 * @since GDAL 2.1
2216
 */
2217

2218
CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
35✔
2219

2220
{
2221
    VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
35✔
2222

2223
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
35✔
2224
    return poBand->DeleteNoDataValue();
35✔
2225
}
2226

2227
/************************************************************************/
2228
/*                             GetMaximum()                             */
2229
/************************************************************************/
2230

2231
/**
2232
 * \brief Fetch the maximum value for this band.
2233
 *
2234
 * For file formats that don't know this intrinsically, the maximum supported
2235
 * value for the data type will generally be returned.
2236
 *
2237
 * This method is the same as the C function GDALGetRasterMaximum().
2238
 *
2239
 * @param pbSuccess pointer to a boolean to use to indicate if the
2240
 * returned value is a tight maximum or not.  May be NULL (default).
2241
 *
2242
 * @return the maximum raster value (excluding no data pixels)
2243
 */
2244

2245
double GDALRasterBand::GetMaximum(int *pbSuccess)
422✔
2246

2247
{
2248
    const char *pszValue = nullptr;
422✔
2249

2250
    if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
422✔
2251
    {
2252
        if (pbSuccess != nullptr)
47✔
2253
            *pbSuccess = TRUE;
42✔
2254

2255
        return CPLAtofM(pszValue);
47✔
2256
    }
2257

2258
    if (pbSuccess != nullptr)
375✔
2259
        *pbSuccess = FALSE;
343✔
2260

2261
    switch (eDataType)
375✔
2262
    {
2263
        case GDT_Byte:
269✔
2264
        {
2265
            EnablePixelTypeSignedByteWarning(false);
269✔
2266
            const char *pszPixelType =
2267
                GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
269✔
2268
            EnablePixelTypeSignedByteWarning(true);
269✔
2269
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
269✔
2270
                return 127;
×
2271

2272
            return 255;
269✔
2273
        }
2274

2275
        case GDT_Int8:
×
2276
            return 127;
×
2277

2278
        case GDT_UInt16:
19✔
2279
            return 65535;
19✔
2280

2281
        case GDT_Int16:
14✔
2282
        case GDT_CInt16:
2283
            return 32767;
14✔
2284

2285
        case GDT_Int32:
14✔
2286
        case GDT_CInt32:
2287
            return 2147483647.0;
14✔
2288

2289
        case GDT_UInt32:
13✔
2290
            return 4294967295.0;
13✔
2291

2292
        case GDT_Int64:
×
2293
            return static_cast<double>(std::numeric_limits<GInt64>::max());
×
2294

2295
        case GDT_UInt64:
×
2296
            return static_cast<double>(std::numeric_limits<GUInt64>::max());
×
2297

2298
        case GDT_Float32:
26✔
2299
        case GDT_CFloat32:
2300
            return 4294967295.0;  // Not actually accurate.
26✔
2301

2302
        case GDT_Float64:
20✔
2303
        case GDT_CFloat64:
2304
            return 4294967295.0;  // Not actually accurate.
20✔
2305

2306
        case GDT_Unknown:
×
2307
        case GDT_TypeCount:
2308
            break;
×
2309
    }
2310
    return 4294967295.0;  // Not actually accurate.
×
2311
}
2312

2313
/************************************************************************/
2314
/*                        GDALGetRasterMaximum()                        */
2315
/************************************************************************/
2316

2317
/**
2318
 * \brief Fetch the maximum value for this band.
2319
 *
2320
 * @see GDALRasterBand::GetMaximum()
2321
 */
2322

2323
double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
183✔
2324

2325
{
2326
    VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
183✔
2327

2328
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
183✔
2329
    return poBand->GetMaximum(pbSuccess);
183✔
2330
}
2331

2332
/************************************************************************/
2333
/*                             GetMinimum()                             */
2334
/************************************************************************/
2335

2336
/**
2337
 * \brief Fetch the minimum value for this band.
2338
 *
2339
 * For file formats that don't know this intrinsically, the minimum supported
2340
 * value for the data type will generally be returned.
2341
 *
2342
 * This method is the same as the C function GDALGetRasterMinimum().
2343
 *
2344
 * @param pbSuccess pointer to a boolean to use to indicate if the
2345
 * returned value is a tight minimum or not.  May be NULL (default).
2346
 *
2347
 * @return the minimum raster value (excluding no data pixels)
2348
 */
2349

2350
double GDALRasterBand::GetMinimum(int *pbSuccess)
429✔
2351

2352
{
2353
    const char *pszValue = nullptr;
429✔
2354

2355
    if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
429✔
2356
    {
2357
        if (pbSuccess != nullptr)
52✔
2358
            *pbSuccess = TRUE;
47✔
2359

2360
        return CPLAtofM(pszValue);
52✔
2361
    }
2362

2363
    if (pbSuccess != nullptr)
377✔
2364
        *pbSuccess = FALSE;
345✔
2365

2366
    switch (eDataType)
377✔
2367
    {
2368
        case GDT_Byte:
271✔
2369
        {
2370
            EnablePixelTypeSignedByteWarning(false);
271✔
2371
            const char *pszPixelType =
2372
                GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
271✔
2373
            EnablePixelTypeSignedByteWarning(true);
271✔
2374
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
271✔
2375
                return -128;
×
2376

2377
            return 0;
271✔
2378
        }
2379

2380
        case GDT_Int8:
×
2381
            return -128;
×
2382
            break;
2383

2384
        case GDT_UInt16:
19✔
2385
            return 0;
19✔
2386

2387
        case GDT_Int16:
14✔
2388
        case GDT_CInt16:
2389
            return -32768;
14✔
2390

2391
        case GDT_Int32:
14✔
2392
        case GDT_CInt32:
2393
            return -2147483648.0;
14✔
2394

2395
        case GDT_UInt32:
13✔
2396
            return 0;
13✔
2397

2398
        case GDT_Int64:
×
2399
            return static_cast<double>(std::numeric_limits<GInt64>::min());
×
2400

2401
        case GDT_UInt64:
×
2402
            return 0;
×
2403

2404
        case GDT_Float32:
26✔
2405
        case GDT_CFloat32:
2406
            return -4294967295.0;  // Not actually accurate.
26✔
2407

2408
        case GDT_Float64:
20✔
2409
        case GDT_CFloat64:
2410
            return -4294967295.0;  // Not actually accurate.
20✔
2411

2412
        case GDT_Unknown:
×
2413
        case GDT_TypeCount:
2414
            break;
×
2415
    }
2416
    return -4294967295.0;  // Not actually accurate.
×
2417
}
2418

2419
/************************************************************************/
2420
/*                        GDALGetRasterMinimum()                        */
2421
/************************************************************************/
2422

2423
/**
2424
 * \brief Fetch the minimum value for this band.
2425
 *
2426
 * @see GDALRasterBand::GetMinimum()
2427
 */
2428

2429
double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
191✔
2430

2431
{
2432
    VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
191✔
2433

2434
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
191✔
2435
    return poBand->GetMinimum(pbSuccess);
191✔
2436
}
2437

2438
/************************************************************************/
2439
/*                       GetColorInterpretation()                       */
2440
/************************************************************************/
2441

2442
/**
2443
 * \brief How should this band be interpreted as color?
2444
 *
2445
 * GCI_Undefined is returned when the format doesn't know anything
2446
 * about the color interpretation.
2447
 *
2448
 * This method is the same as the C function
2449
 * GDALGetRasterColorInterpretation().
2450
 *
2451
 * @return color interpretation value for band.
2452
 */
2453

2454
GDALColorInterp GDALRasterBand::GetColorInterpretation()
107✔
2455

2456
{
2457
    return GCI_Undefined;
107✔
2458
}
2459

2460
/************************************************************************/
2461
/*                  GDALGetRasterColorInterpretation()                  */
2462
/************************************************************************/
2463

2464
/**
2465
 * \brief How should this band be interpreted as color?
2466
 *
2467
 * @see GDALRasterBand::GetColorInterpretation()
2468
 */
2469

2470
GDALColorInterp CPL_STDCALL
2471
GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
4,637✔
2472

2473
{
2474
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
4,637✔
2475

2476
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4,637✔
2477
    return poBand->GetColorInterpretation();
4,637✔
2478
}
2479

2480
/************************************************************************/
2481
/*                       SetColorInterpretation()                       */
2482
/************************************************************************/
2483

2484
/**
2485
 * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
2486
 * \brief Set color interpretation of a band.
2487
 *
2488
 * This method is the same as the C function GDALSetRasterColorInterpretation().
2489
 *
2490
 * @param eColorInterp the new color interpretation to apply to this band.
2491
 *
2492
 * @return CE_None on success or CE_Failure if method is unsupported by format.
2493
 */
2494

2495
/**/
2496
/**/
2497

2498
CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3✔
2499

2500
{
2501
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3✔
2502
        ReportError(CE_Failure, CPLE_NotSupported,
3✔
2503
                    "SetColorInterpretation() not supported for this dataset.");
2504
    return CE_Failure;
3✔
2505
}
2506

2507
/************************************************************************/
2508
/*                  GDALSetRasterColorInterpretation()                  */
2509
/************************************************************************/
2510

2511
/**
2512
 * \brief Set color interpretation of a band.
2513
 *
2514
 * @see GDALRasterBand::SetColorInterpretation()
2515
 */
2516

2517
CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
1,697✔
2518
    GDALRasterBandH hBand, GDALColorInterp eColorInterp)
2519

2520
{
2521
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
1,697✔
2522

2523
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1,697✔
2524
    return poBand->SetColorInterpretation(eColorInterp);
1,697✔
2525
}
2526

2527
/************************************************************************/
2528
/*                           GetColorTable()                            */
2529
/************************************************************************/
2530

2531
/**
2532
 * \brief Fetch the color table associated with band.
2533
 *
2534
 * If there is no associated color table, the return result is NULL.  The
2535
 * returned color table remains owned by the GDALRasterBand, and can't
2536
 * be depended on for long, nor should it ever be modified by the caller.
2537
 *
2538
 * This method is the same as the C function GDALGetRasterColorTable().
2539
 *
2540
 * @return internal color table, or NULL.
2541
 */
2542

2543
GDALColorTable *GDALRasterBand::GetColorTable()
180✔
2544

2545
{
2546
    return nullptr;
180✔
2547
}
2548

2549
/************************************************************************/
2550
/*                      GDALGetRasterColorTable()                       */
2551
/************************************************************************/
2552

2553
/**
2554
 * \brief Fetch the color table associated with band.
2555
 *
2556
 * @see GDALRasterBand::GetColorTable()
2557
 */
2558

2559
GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
1,555✔
2560

2561
{
2562
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
1,555✔
2563

2564
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1,555✔
2565
    return GDALColorTable::ToHandle(poBand->GetColorTable());
1,555✔
2566
}
2567

2568
/************************************************************************/
2569
/*                           SetColorTable()                            */
2570
/************************************************************************/
2571

2572
/**
2573
 * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
2574
 * \brief Set the raster color table.
2575
 *
2576
 * The driver will make a copy of all desired data in the colortable.  It
2577
 * remains owned by the caller after the call.
2578
 *
2579
 * This method is the same as the C function GDALSetRasterColorTable().
2580
 *
2581
 * @param poCT the color table to apply.  This may be NULL to clear the color
2582
 * table (where supported).
2583
 *
2584
 * @return CE_None on success, or CE_Failure on failure.  If the action is
2585
 * unsupported by the driver, a value of CE_Failure is returned, but no
2586
 * error is issued.
2587
 */
2588

2589
/**/
2590
/**/
2591

2592
CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
×
2593

2594
{
2595
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
×
2596
        ReportError(CE_Failure, CPLE_NotSupported,
×
2597
                    "SetColorTable() not supported for this dataset.");
2598
    return CE_Failure;
×
2599
}
2600

2601
/************************************************************************/
2602
/*                      GDALSetRasterColorTable()                       */
2603
/************************************************************************/
2604

2605
/**
2606
 * \brief Set the raster color table.
2607
 *
2608
 * @see GDALRasterBand::SetColorTable()
2609
 */
2610

2611
CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
73✔
2612
                                           GDALColorTableH hCT)
2613

2614
{
2615
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
73✔
2616

2617
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
73✔
2618
    return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
73✔
2619
}
2620

2621
/************************************************************************/
2622
/*                       HasArbitraryOverviews()                        */
2623
/************************************************************************/
2624

2625
/**
2626
 * \brief Check for arbitrary overviews.
2627
 *
2628
 * This returns TRUE if the underlying datastore can compute arbitrary
2629
 * overviews efficiently, such as is the case with OGDI over a network.
2630
 * Datastores with arbitrary overviews don't generally have any fixed
2631
 * overviews, but the RasterIO() method can be used in downsampling mode
2632
 * to get overview data efficiently.
2633
 *
2634
 * This method is the same as the C function GDALHasArbitraryOverviews(),
2635
 *
2636
 * @return TRUE if arbitrary overviews available (efficiently), otherwise
2637
 * FALSE.
2638
 */
2639

2640
int GDALRasterBand::HasArbitraryOverviews()
210✔
2641

2642
{
2643
    return FALSE;
210✔
2644
}
2645

2646
/************************************************************************/
2647
/*                     GDALHasArbitraryOverviews()                      */
2648
/************************************************************************/
2649

2650
/**
2651
 * \brief Check for arbitrary overviews.
2652
 *
2653
 * @see GDALRasterBand::HasArbitraryOverviews()
2654
 */
2655

2656
int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
145✔
2657

2658
{
2659
    VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
145✔
2660

2661
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
145✔
2662
    return poBand->HasArbitraryOverviews();
145✔
2663
}
2664

2665
/************************************************************************/
2666
/*                          GetOverviewCount()                          */
2667
/************************************************************************/
2668

2669
/**
2670
 * \brief Return the number of overview layers available.
2671
 *
2672
 * This method is the same as the C function GDALGetOverviewCount().
2673
 *
2674
 * @return overview count, zero if none.
2675
 */
2676

2677
int GDALRasterBand::GetOverviewCount()
659,460✔
2678

2679
{
2680
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
1,314,060✔
2681
        poDS->AreOverviewsEnabled())
654,597✔
2682
        return poDS->oOvManager.GetOverviewCount(nBand);
654,597✔
2683

2684
    return 0;
4,863✔
2685
}
2686

2687
/************************************************************************/
2688
/*                        GDALGetOverviewCount()                        */
2689
/************************************************************************/
2690

2691
/**
2692
 * \brief Return the number of overview layers available.
2693
 *
2694
 * @see GDALRasterBand::GetOverviewCount()
2695
 */
2696

2697
int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3,133✔
2698

2699
{
2700
    VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3,133✔
2701

2702
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3,133✔
2703
    return poBand->GetOverviewCount();
3,133✔
2704
}
2705

2706
/************************************************************************/
2707
/*                            GetOverview()                             */
2708
/************************************************************************/
2709

2710
/**
2711
 * \brief Fetch overview raster band object.
2712
 *
2713
 * This method is the same as the C function GDALGetOverview().
2714
 *
2715
 * @param i overview index between 0 and GetOverviewCount()-1.
2716
 *
2717
 * @return overview GDALRasterBand.
2718
 */
2719

2720
GDALRasterBand *GDALRasterBand::GetOverview(int i)
795✔
2721

2722
{
2723
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
1,536✔
2724
        poDS->AreOverviewsEnabled())
741✔
2725
        return poDS->oOvManager.GetOverview(nBand, i);
741✔
2726

2727
    return nullptr;
54✔
2728
}
2729

2730
/************************************************************************/
2731
/*                          GDALGetOverview()                           */
2732
/************************************************************************/
2733

2734
/**
2735
 * \brief Fetch overview raster band object.
2736
 *
2737
 * @see GDALRasterBand::GetOverview()
2738
 */
2739

2740
GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
1,361✔
2741

2742
{
2743
    VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
1,361✔
2744

2745
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1,361✔
2746
    return GDALRasterBand::ToHandle(poBand->GetOverview(i));
1,361✔
2747
}
2748

2749
/************************************************************************/
2750
/*                      GetRasterSampleOverview()                       */
2751
/************************************************************************/
2752

2753
/**
2754
 * \brief Fetch best sampling overview.
2755
 *
2756
 * Returns the most reduced overview of the given band that still satisfies
2757
 * the desired number of samples.  This function can be used with zero
2758
 * as the number of desired samples to fetch the most reduced overview.
2759
 * The same band as was passed in will be returned if it has not overviews,
2760
 * or if none of the overviews have enough samples.
2761
 *
2762
 * This method is the same as the C functions GDALGetRasterSampleOverview()
2763
 * and GDALGetRasterSampleOverviewEx().
2764
 *
2765
 * @param nDesiredSamples the returned band will have at least this many
2766
 * pixels.
2767
 *
2768
 * @return optimal overview or the band itself.
2769
 */
2770

2771
GDALRasterBand *
2772
GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
6✔
2773

2774
{
2775
    GDALRasterBand *poBestBand = this;
6✔
2776

2777
    double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
6✔
2778

2779
    for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
23✔
2780
    {
2781
        GDALRasterBand *poOBand = GetOverview(iOverview);
17✔
2782

2783
        if (poOBand == nullptr)
17✔
2784
            continue;
×
2785

2786
        const double dfOSamples =
2787
            poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
17✔
2788

2789
        if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
17✔
2790
        {
2791
            dfBestSamples = dfOSamples;
14✔
2792
            poBestBand = poOBand;
14✔
2793
        }
2794
    }
2795

2796
    return poBestBand;
6✔
2797
}
2798

2799
/************************************************************************/
2800
/*                    GDALGetRasterSampleOverview()                     */
2801
/************************************************************************/
2802

2803
/**
2804
 * \brief Fetch best sampling overview.
2805
 *
2806
 * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
2807
 * billion samples.
2808
 *
2809
 * @see GDALRasterBand::GetRasterSampleOverview()
2810
 * @see GDALGetRasterSampleOverviewEx()
2811
 */
2812

2813
GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
×
2814
                                                        int nDesiredSamples)
2815

2816
{
2817
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
×
2818

2819
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
×
2820
    return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
×
2821
        nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
×
2822
}
2823

2824
/************************************************************************/
2825
/*                    GDALGetRasterSampleOverviewEx()                   */
2826
/************************************************************************/
2827

2828
/**
2829
 * \brief Fetch best sampling overview.
2830
 *
2831
 * @see GDALRasterBand::GetRasterSampleOverview()
2832
 * @since GDAL 2.0
2833
 */
2834

2835
GDALRasterBandH CPL_STDCALL
2836
GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
×
2837

2838
{
2839
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
×
2840

2841
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
×
2842
    return GDALRasterBand::ToHandle(
×
2843
        poBand->GetRasterSampleOverview(nDesiredSamples));
×
2844
}
2845

2846
/************************************************************************/
2847
/*                           BuildOverviews()                           */
2848
/************************************************************************/
2849

2850
/**
2851
 * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
2852
 * GDALProgressFunc, void*) \brief Build raster overview(s)
2853
 *
2854
 * If the operation is unsupported for the indicated dataset, then
2855
 * CE_Failure is returned, and CPLGetLastErrorNo() will return
2856
 * CPLE_NotSupported.
2857
 *
2858
 * WARNING:  It is not possible to build overviews for a single band in
2859
 * TIFF format, and thus this method does not work for TIFF format, or any
2860
 * formats that use the default overview building in TIFF format.  Instead
2861
 * it is necessary to build overviews on the dataset as a whole using
2862
 * GDALDataset::BuildOverviews().  That makes this method pretty useless
2863
 * from a practical point of view.
2864
 *
2865
 * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
2866
 * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
2867
 * applied.
2868
 * @param nOverviews number of overviews to build.
2869
 * @param panOverviewList the list of overview decimation factors to build.
2870
 * @param pfnProgress a function to call to report progress, or NULL.
2871
 * @param pProgressData application data to pass to the progress function.
2872
 * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
2873
 *                     key=value pairs, or NULL
2874
 *
2875
 * @return CE_None on success or CE_Failure if the operation doesn't work.
2876
 */
2877

2878
/**/
2879
/**/
2880

2881
CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
×
2882
                                      int /*nOverviews*/,
2883
                                      const int * /*panOverviewList*/,
2884
                                      GDALProgressFunc /*pfnProgress*/,
2885
                                      void * /*pProgressData*/,
2886
                                      CSLConstList /* papszOptions */)
2887

2888
{
2889
    ReportError(CE_Failure, CPLE_NotSupported,
×
2890
                "BuildOverviews() not supported for this dataset.");
2891

2892
    return (CE_Failure);
×
2893
}
2894

2895
/************************************************************************/
2896
/*                             GetOffset()                              */
2897
/************************************************************************/
2898

2899
/**
2900
 * \brief Fetch the raster value offset.
2901
 *
2902
 * This value (in combination with the GetScale() value) can be used to
2903
 * transform raw pixel values into the units returned by GetUnitType().
2904
 * For example this might be used to store elevations in GUInt16 bands
2905
 * with a precision of 0.1, and starting from -100.
2906
 *
2907
 * Units value = (raw value * scale) + offset
2908
 *
2909
 * Note that applying scale and offset is of the responsibility of the user,
2910
 * and is not done by methods such as RasterIO() or ReadBlock().
2911
 *
2912
 * For file formats that don't know this intrinsically a value of zero
2913
 * is returned.
2914
 *
2915
 * This method is the same as the C function GDALGetRasterOffset().
2916
 *
2917
 * @param pbSuccess pointer to a boolean to use to indicate if the
2918
 * returned value is meaningful or not.  May be NULL (default).
2919
 *
2920
 * @return the raster offset.
2921
 */
2922

2923
double GDALRasterBand::GetOffset(int *pbSuccess)
363✔
2924

2925
{
2926
    if (pbSuccess != nullptr)
363✔
2927
        *pbSuccess = FALSE;
315✔
2928

2929
    return 0.0;
363✔
2930
}
2931

2932
/************************************************************************/
2933
/*                        GDALGetRasterOffset()                         */
2934
/************************************************************************/
2935

2936
/**
2937
 * \brief Fetch the raster value offset.
2938
 *
2939
 * @see GDALRasterBand::GetOffset()
2940
 */
2941

2942
double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
264✔
2943

2944
{
2945
    VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
264✔
2946

2947
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
264✔
2948
    return poBand->GetOffset(pbSuccess);
264✔
2949
}
2950

2951
/************************************************************************/
2952
/*                             SetOffset()                              */
2953
/************************************************************************/
2954

2955
/**
2956
 * \fn GDALRasterBand::SetOffset(double)
2957
 * \brief Set scaling offset.
2958
 *
2959
 * Very few formats implement this method.   When not implemented it will
2960
 * issue a CPLE_NotSupported error and return CE_Failure.
2961
 *
2962
 * This method is the same as the C function GDALSetRasterOffset().
2963
 *
2964
 * @param dfNewOffset the new offset.
2965
 *
2966
 * @return CE_None or success or CE_Failure on failure.
2967
 */
2968

2969
/**/
2970
/**/
2971

2972
CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
×
2973
{
2974
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
×
2975
        ReportError(CE_Failure, CPLE_NotSupported,
×
2976
                    "SetOffset() not supported on this raster band.");
2977

2978
    return CE_Failure;
×
2979
}
2980

2981
/************************************************************************/
2982
/*                        GDALSetRasterOffset()                         */
2983
/************************************************************************/
2984

2985
/**
2986
 * \brief Set scaling offset.
2987
 *
2988
 * @see GDALRasterBand::SetOffset()
2989
 */
2990

2991
CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
41✔
2992
                                       double dfNewOffset)
2993

2994
{
2995
    VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
41✔
2996

2997
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
41✔
2998
    return poBand->SetOffset(dfNewOffset);
41✔
2999
}
3000

3001
/************************************************************************/
3002
/*                              GetScale()                              */
3003
/************************************************************************/
3004

3005
/**
3006
 * \brief Fetch the raster value scale.
3007
 *
3008
 * This value (in combination with the GetOffset() value) can be used to
3009
 * transform raw pixel values into the units returned by GetUnitType().
3010
 * For example this might be used to store elevations in GUInt16 bands
3011
 * with a precision of 0.1, and starting from -100.
3012
 *
3013
 * Units value = (raw value * scale) + offset
3014
 *
3015
 * Note that applying scale and offset is of the responsibility of the user,
3016
 * and is not done by methods such as RasterIO() or ReadBlock().
3017
 *
3018
 * For file formats that don't know this intrinsically a value of one
3019
 * is returned.
3020
 *
3021
 * This method is the same as the C function GDALGetRasterScale().
3022
 *
3023
 * @param pbSuccess pointer to a boolean to use to indicate if the
3024
 * returned value is meaningful or not.  May be NULL (default).
3025
 *
3026
 * @return the raster scale.
3027
 */
3028

3029
double GDALRasterBand::GetScale(int *pbSuccess)
363✔
3030

3031
{
3032
    if (pbSuccess != nullptr)
363✔
3033
        *pbSuccess = FALSE;
315✔
3034

3035
    return 1.0;
363✔
3036
}
3037

3038
/************************************************************************/
3039
/*                         GDALGetRasterScale()                         */
3040
/************************************************************************/
3041

3042
/**
3043
 * \brief Fetch the raster value scale.
3044
 *
3045
 * @see GDALRasterBand::GetScale()
3046
 */
3047

3048
double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
263✔
3049

3050
{
3051
    VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
263✔
3052

3053
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
263✔
3054
    return poBand->GetScale(pbSuccess);
263✔
3055
}
3056

3057
/************************************************************************/
3058
/*                              SetScale()                              */
3059
/************************************************************************/
3060

3061
/**
3062
 * \fn GDALRasterBand::SetScale(double)
3063
 * \brief Set scaling ratio.
3064
 *
3065
 * Very few formats implement this method.   When not implemented it will
3066
 * issue a CPLE_NotSupported error and return CE_Failure.
3067
 *
3068
 * This method is the same as the C function GDALSetRasterScale().
3069
 *
3070
 * @param dfNewScale the new scale.
3071
 *
3072
 * @return CE_None or success or CE_Failure on failure.
3073
 */
3074

3075
/**/
3076
/**/
3077

3078
CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
×
3079

3080
{
3081
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
×
3082
        ReportError(CE_Failure, CPLE_NotSupported,
×
3083
                    "SetScale() not supported on this raster band.");
3084

3085
    return CE_Failure;
×
3086
}
3087

3088
/************************************************************************/
3089
/*                        GDALSetRasterScale()                          */
3090
/************************************************************************/
3091

3092
/**
3093
 * \brief Set scaling ratio.
3094
 *
3095
 * @see GDALRasterBand::SetScale()
3096
 */
3097

3098
CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
42✔
3099

3100
{
3101
    VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
42✔
3102

3103
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
42✔
3104
    return poBand->SetScale(dfNewOffset);
42✔
3105
}
3106

3107
/************************************************************************/
3108
/*                            GetUnitType()                             */
3109
/************************************************************************/
3110

3111
/**
3112
 * \brief Return raster unit type.
3113
 *
3114
 * Return a name for the units of this raster's values.  For instance, it
3115
 * might be "m" for an elevation model in meters, or "ft" for feet.  If no
3116
 * units are available, a value of "" will be returned.  The returned string
3117
 * should not be modified, nor freed by the calling application.
3118
 *
3119
 * This method is the same as the C function GDALGetRasterUnitType().
3120
 *
3121
 * @return unit name string.
3122
 */
3123

3124
const char *GDALRasterBand::GetUnitType()
155✔
3125

3126
{
3127
    return "";
155✔
3128
}
3129

3130
/************************************************************************/
3131
/*                       GDALGetRasterUnitType()                        */
3132
/************************************************************************/
3133

3134
/**
3135
 * \brief Return raster unit type.
3136
 *
3137
 * @see GDALRasterBand::GetUnitType()
3138
 */
3139

3140
const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
1,220✔
3141

3142
{
3143
    VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
1,220✔
3144

3145
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1,220✔
3146
    return poBand->GetUnitType();
1,220✔
3147
}
3148

3149
/************************************************************************/
3150
/*                            SetUnitType()                             */
3151
/************************************************************************/
3152

3153
/**
3154
 * \fn GDALRasterBand::SetUnitType(const char*)
3155
 * \brief Set unit type.
3156
 *
3157
 * Set the unit type for a raster band.  Values should be one of
3158
 * "" (the default indicating it is unknown), "m" indicating meters,
3159
 * or "ft" indicating feet, though other nonstandard values are allowed.
3160
 *
3161
 * This method is the same as the C function GDALSetRasterUnitType().
3162
 *
3163
 * @param pszNewValue the new unit type value.
3164
 *
3165
 * @return CE_None on success or CE_Failure if not successful, or
3166
 * unsupported.
3167
 */
3168

3169
/**/
3170
/**/
3171

3172
CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
×
3173

3174
{
3175
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
×
3176
        ReportError(CE_Failure, CPLE_NotSupported,
×
3177
                    "SetUnitType() not supported on this raster band.");
3178
    return CE_Failure;
×
3179
}
3180

3181
/************************************************************************/
3182
/*                       GDALSetRasterUnitType()                        */
3183
/************************************************************************/
3184

3185
/**
3186
 * \brief Set unit type.
3187
 *
3188
 * @see GDALRasterBand::SetUnitType()
3189
 *
3190
 * @since GDAL 1.8.0
3191
 */
3192

3193
CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
53✔
3194
                                         const char *pszNewValue)
3195

3196
{
3197
    VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
53✔
3198

3199
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
53✔
3200
    return poBand->SetUnitType(pszNewValue);
53✔
3201
}
3202

3203
/************************************************************************/
3204
/*                              GetXSize()                              */
3205
/************************************************************************/
3206

3207
/**
3208
 * \brief Fetch XSize of raster.
3209
 *
3210
 * This method is the same as the C function GDALGetRasterBandXSize().
3211
 *
3212
 * @return the width in pixels of this band.
3213
 */
3214

3215
int GDALRasterBand::GetXSize()
3,483,280✔
3216

3217
{
3218
    return nRasterXSize;
3,483,280✔
3219
}
3220

3221
/************************************************************************/
3222
/*                       GDALGetRasterBandXSize()                       */
3223
/************************************************************************/
3224

3225
/**
3226
 * \brief Fetch XSize of raster.
3227
 *
3228
 * @see GDALRasterBand::GetXSize()
3229
 */
3230

3231
int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
23,506✔
3232

3233
{
3234
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
23,506✔
3235

3236
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
23,506✔
3237
    return poBand->GetXSize();
23,506✔
3238
}
3239

3240
/************************************************************************/
3241
/*                              GetYSize()                              */
3242
/************************************************************************/
3243

3244
/**
3245
 * \brief Fetch YSize of raster.
3246
 *
3247
 * This method is the same as the C function GDALGetRasterBandYSize().
3248
 *
3249
 * @return the height in pixels of this band.
3250
 */
3251

3252
int GDALRasterBand::GetYSize()
416,332✔
3253

3254
{
3255
    return nRasterYSize;
416,332✔
3256
}
3257

3258
/************************************************************************/
3259
/*                       GDALGetRasterBandYSize()                       */
3260
/************************************************************************/
3261

3262
/**
3263
 * \brief Fetch YSize of raster.
3264
 *
3265
 * @see GDALRasterBand::GetYSize()
3266
 */
3267

3268
int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
22,883✔
3269

3270
{
3271
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
22,883✔
3272

3273
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
22,883✔
3274
    return poBand->GetYSize();
22,883✔
3275
}
3276

3277
/************************************************************************/
3278
/*                              GetBand()                               */
3279
/************************************************************************/
3280

3281
/**
3282
 * \brief Fetch the band number.
3283
 *
3284
 * This method returns the band that this GDALRasterBand objects represents
3285
 * within its dataset.  This method may return a value of 0 to indicate
3286
 * GDALRasterBand objects without an apparently relationship to a dataset,
3287
 * such as GDALRasterBands serving as overviews.
3288
 *
3289
 * This method is the same as the C function GDALGetBandNumber().
3290
 *
3291
 * @return band number (1+) or 0 if the band number isn't known.
3292
 */
3293

3294
int GDALRasterBand::GetBand()
14,728✔
3295

3296
{
3297
    return nBand;
14,728✔
3298
}
3299

3300
/************************************************************************/
3301
/*                         GDALGetBandNumber()                          */
3302
/************************************************************************/
3303

3304
/**
3305
 * \brief Fetch the band number.
3306
 *
3307
 * @see GDALRasterBand::GetBand()
3308
 */
3309

3310
int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
129✔
3311

3312
{
3313
    VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
129✔
3314

3315
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
129✔
3316
    return poBand->GetBand();
129✔
3317
}
3318

3319
/************************************************************************/
3320
/*                             GetDataset()                             */
3321
/************************************************************************/
3322

3323
/**
3324
 * \brief Fetch the owning dataset handle.
3325
 *
3326
 * Note that some GDALRasterBands are not considered to be a part of a dataset,
3327
 * such as overviews or other "freestanding" bands.
3328
 *
3329
 * This method is the same as the C function GDALGetBandDataset().
3330
 *
3331
 * @return the pointer to the GDALDataset to which this band belongs, or
3332
 * NULL if this cannot be determined.
3333
 */
3334

3335
GDALDataset *GDALRasterBand::GetDataset()
3,640,460✔
3336

3337
{
3338
    return poDS;
3,640,460✔
3339
}
3340

3341
/************************************************************************/
3342
/*                         GDALGetBandDataset()                         */
3343
/************************************************************************/
3344

3345
/**
3346
 * \brief Fetch the owning dataset handle.
3347
 *
3348
 * @see GDALRasterBand::GetDataset()
3349
 */
3350

3351
GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
301✔
3352

3353
{
3354
    VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
301✔
3355

3356
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
301✔
3357
    return GDALDataset::ToHandle(poBand->GetDataset());
301✔
3358
}
3359

3360
/************************************************************************/
3361
/*                        ComputeFloatNoDataValue()                     */
3362
/************************************************************************/
3363

3364
static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
1,948✔
3365
                                           double dfNoDataValue,
3366
                                           int &bGotNoDataValue,
3367
                                           float &fNoDataValue,
3368
                                           bool &bGotFloatNoDataValue)
3369
{
3370
    if (eDataType == GDT_Float32 && bGotNoDataValue)
1,948✔
3371
    {
3372
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
77✔
3373
        if (GDALIsValueInRange<float>(dfNoDataValue))
77✔
3374
        {
3375
            fNoDataValue = static_cast<float>(dfNoDataValue);
77✔
3376
            bGotFloatNoDataValue = true;
77✔
3377
            bGotNoDataValue = false;
77✔
3378
        }
3379
    }
3380
}
1,948✔
3381

3382
/************************************************************************/
3383
/*                            GetHistogram()                            */
3384
/************************************************************************/
3385

3386
/**
3387
 * \brief Compute raster histogram.
3388
 *
3389
 * Note that the bucket size is (dfMax-dfMin) / nBuckets.
3390
 *
3391
 * For example to compute a simple 256 entry histogram of eight bit data,
3392
 * the following would be suitable.  The unusual bounds are to ensure that
3393
 * bucket boundaries don't fall right on integer values causing possible errors
3394
 * due to rounding after scaling.
3395
\code{.cpp}
3396
    GUIntBig anHistogram[256];
3397

3398
    poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
3399
                          GDALDummyProgress, nullptr );
3400
\endcode
3401
 *
3402
 * Note that setting bApproxOK will generally result in a subsampling of the
3403
 * file, and will utilize overviews if available.  It should generally
3404
 * produce a representative histogram for the data that is suitable for use
3405
 * in generating histogram based luts for instance.  Generally bApproxOK is
3406
 * much faster than an exactly computed histogram.
3407
 *
3408
 * This method is the same as the C functions GDALGetRasterHistogram() and
3409
 * GDALGetRasterHistogramEx().
3410
 *
3411
 * @param dfMin the lower bound of the histogram.
3412
 * @param dfMax the upper bound of the histogram.
3413
 * @param nBuckets the number of buckets in panHistogram.
3414
 * @param panHistogram array into which the histogram totals are placed.
3415
 * @param bIncludeOutOfRange if TRUE values below the histogram range will
3416
 * mapped into panHistogram[0], and values above will be mapped into
3417
 * panHistogram[nBuckets-1] otherwise out of range values are discarded.
3418
 * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
3419
 * @param pfnProgress function to report progress to completion.
3420
 * @param pProgressData application data to pass to pfnProgress.
3421
 *
3422
 * @return CE_None on success, or CE_Failure if something goes wrong.
3423
 */
3424

3425
CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
35✔
3426
                                    GUIntBig *panHistogram,
3427
                                    int bIncludeOutOfRange, int bApproxOK,
3428
                                    GDALProgressFunc pfnProgress,
3429
                                    void *pProgressData)
3430

3431
{
3432
    CPLAssert(nullptr != panHistogram);
35✔
3433

3434
    if (pfnProgress == nullptr)
35✔
3435
        pfnProgress = GDALDummyProgress;
26✔
3436

3437
    /* -------------------------------------------------------------------- */
3438
    /*      If we have overviews, use them for the histogram.               */
3439
    /* -------------------------------------------------------------------- */
3440
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
35✔
3441
    {
3442
        // FIXME: should we use the most reduced overview here or use some
3443
        // minimum number of samples like GDALRasterBand::ComputeStatistics()
3444
        // does?
3445
        GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
×
3446

3447
        if (poBestOverview != this)
×
3448
        {
3449
            return poBestOverview->GetHistogram(
×
3450
                dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
3451
                bApproxOK, pfnProgress, pProgressData);
×
3452
        }
3453
    }
3454

3455
    /* -------------------------------------------------------------------- */
3456
    /*      Read actual data and build histogram.                           */
3457
    /* -------------------------------------------------------------------- */
3458
    if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
35✔
3459
    {
3460
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
×
3461
        return CE_Failure;
×
3462
    }
3463

3464
    // Written this way to deal with NaN
3465
    if (!(dfMax > dfMin))
35✔
3466
    {
3467
        ReportError(CE_Failure, CPLE_IllegalArg,
5✔
3468
                    "dfMax should be strictly greater than dfMin");
3469
        return CE_Failure;
5✔
3470
    }
3471

3472
    GDALRasterIOExtraArg sExtraArg;
3473
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
30✔
3474

3475
    const double dfScale = nBuckets / (dfMax - dfMin);
30✔
3476
    if (dfScale == 0 || !std::isfinite(dfScale))
30✔
3477
    {
3478
        ReportError(CE_Failure, CPLE_IllegalArg,
5✔
3479
                    "dfMin and dfMax should be finite values such that "
3480
                    "nBuckets / (dfMax - dfMin) is non-zero");
3481
        return CE_Failure;
5✔
3482
    }
3483
    memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
25✔
3484

3485
    int bGotNoDataValue = FALSE;
25✔
3486
    const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
25✔
3487
    bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
25✔
3488
    bool bGotFloatNoDataValue = false;
25✔
3489
    float fNoDataValue = 0.0f;
25✔
3490
    ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
25✔
3491
                            fNoDataValue, bGotFloatNoDataValue);
3492
    GDALRasterBand *poMaskBand = nullptr;
25✔
3493
    if (!bGotNoDataValue)
25✔
3494
    {
3495
        const int l_nMaskFlags = GetMaskFlags();
24✔
3496
        if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
25✔
3497
            GetColorInterpretation() != GCI_AlphaBand)
1✔
3498
        {
3499
            poMaskBand = GetMaskBand();
1✔
3500
        }
3501
    }
3502

3503
    bool bSignedByte = false;
25✔
3504
    if (eDataType == GDT_Byte)
25✔
3505
    {
3506
        EnablePixelTypeSignedByteWarning(false);
18✔
3507
        const char *pszPixelType =
3508
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
18✔
3509
        EnablePixelTypeSignedByteWarning(true);
18✔
3510
        bSignedByte =
18✔
3511
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
18✔
3512
    }
3513

3514
    if (bApproxOK && HasArbitraryOverviews())
25✔
3515
    {
3516
        /* --------------------------------------------------------------------
3517
         */
3518
        /*      Figure out how much the image should be reduced to get an */
3519
        /*      approximate value. */
3520
        /* --------------------------------------------------------------------
3521
         */
3522
        const double dfReduction =
3523
            sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
×
3524
                 GDALSTAT_APPROX_NUMSAMPLES);
3525

3526
        int nXReduced = nRasterXSize;
×
3527
        int nYReduced = nRasterYSize;
×
3528
        if (dfReduction > 1.0)
×
3529
        {
3530
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
×
3531
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
×
3532

3533
            // Catch the case of huge resizing ratios here
3534
            if (nXReduced == 0)
×
3535
                nXReduced = 1;
×
3536
            if (nYReduced == 0)
×
3537
                nYReduced = 1;
×
3538
        }
3539

3540
        void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
×
3541
                                          nXReduced, nYReduced);
3542
        if (!pData)
×
3543
            return CE_Failure;
×
3544

3545
        const CPLErr eErr =
3546
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
×
3547
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
×
3548
        if (eErr != CE_None)
×
3549
        {
3550
            CPLFree(pData);
×
3551
            return eErr;
×
3552
        }
3553

3554
        GByte *pabyMaskData = nullptr;
×
3555
        if (poMaskBand)
×
3556
        {
3557
            pabyMaskData =
3558
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
×
3559
            if (!pabyMaskData)
×
3560
            {
3561
                CPLFree(pData);
×
3562
                return CE_Failure;
×
3563
            }
3564

3565
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
×
3566
                                     pabyMaskData, nXReduced, nYReduced,
3567
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
×
3568
            {
3569
                CPLFree(pData);
×
3570
                CPLFree(pabyMaskData);
×
3571
                return CE_Failure;
×
3572
            }
3573
        }
3574

3575
        // This isn't the fastest way to do this, but is easier for now.
3576
        for (int iY = 0; iY < nYReduced; iY++)
×
3577
        {
3578
            for (int iX = 0; iX < nXReduced; iX++)
×
3579
            {
3580
                const int iOffset = iX + iY * nXReduced;
×
3581
                double dfValue = 0.0;
×
3582

3583
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
×
3584
                    continue;
×
3585

3586
                switch (eDataType)
×
3587
                {
3588
                    case GDT_Byte:
×
3589
                    {
3590
                        if (bSignedByte)
×
3591
                            dfValue =
×
3592
                                static_cast<signed char *>(pData)[iOffset];
×
3593
                        else
3594
                            dfValue = static_cast<GByte *>(pData)[iOffset];
×
3595
                        break;
×
3596
                    }
3597
                    case GDT_Int8:
×
3598
                        dfValue = static_cast<GInt8 *>(pData)[iOffset];
×
3599
                        break;
×
3600
                    case GDT_UInt16:
×
3601
                        dfValue = static_cast<GUInt16 *>(pData)[iOffset];
×
3602
                        break;
×
3603
                    case GDT_Int16:
×
3604
                        dfValue = static_cast<GInt16 *>(pData)[iOffset];
×
3605
                        break;
×
3606
                    case GDT_UInt32:
×
3607
                        dfValue = static_cast<GUInt32 *>(pData)[iOffset];
×
3608
                        break;
×
3609
                    case GDT_Int32:
×
3610
                        dfValue = static_cast<GInt32 *>(pData)[iOffset];
×
3611
                        break;
×
3612
                    case GDT_UInt64:
×
3613
                        dfValue = static_cast<double>(
×
3614
                            static_cast<GUInt64 *>(pData)[iOffset]);
×
3615
                        break;
×
3616
                    case GDT_Int64:
×
3617
                        dfValue = static_cast<double>(
×
3618
                            static_cast<GInt64 *>(pData)[iOffset]);
×
3619
                        break;
×
3620
                    case GDT_Float32:
×
3621
                    {
3622
                        const float fValue =
×
3623
                            static_cast<float *>(pData)[iOffset];
×
3624
                        if (CPLIsNan(fValue) ||
×
3625
                            (bGotFloatNoDataValue &&
×
3626
                             ARE_REAL_EQUAL(fValue, fNoDataValue)))
×
3627
                            continue;
×
3628
                        dfValue = fValue;
×
3629
                        break;
×
3630
                    }
3631
                    case GDT_Float64:
×
3632
                        dfValue = static_cast<double *>(pData)[iOffset];
×
3633
                        if (CPLIsNan(dfValue))
×
3634
                            continue;
×
3635
                        break;
×
3636
                    case GDT_CInt16:
×
3637
                    {
3638
                        const double dfReal =
×
3639
                            static_cast<GInt16 *>(pData)[iOffset * 2];
×
3640
                        const double dfImag =
×
3641
                            static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
×
3642
                        if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
×
3643
                            continue;
×
3644
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
×
3645
                    }
3646
                    break;
×
3647
                    case GDT_CInt32:
×
3648
                    {
3649
                        const double dfReal =
×
3650
                            static_cast<GInt32 *>(pData)[iOffset * 2];
×
3651
                        const double dfImag =
×
3652
                            static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
×
3653
                        if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
×
3654
                            continue;
×
3655
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
×
3656
                    }
3657
                    break;
×
3658
                    case GDT_CFloat32:
×
3659
                    {
3660
                        const double dfReal =
×
3661
                            static_cast<float *>(pData)[iOffset * 2];
×
3662
                        const double dfImag =
×
3663
                            static_cast<float *>(pData)[iOffset * 2 + 1];
×
3664
                        if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
×
3665
                            continue;
×
3666
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
×
3667
                    }
3668
                    break;
×
3669
                    case GDT_CFloat64:
×
3670
                    {
3671
                        const double dfReal =
×
3672
                            static_cast<double *>(pData)[iOffset * 2];
×
3673
                        const double dfImag =
×
3674
                            static_cast<double *>(pData)[iOffset * 2 + 1];
×
3675
                        if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
×
3676
                            continue;
×
3677
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
×
3678
                    }
3679
                    break;
×
3680
                    case GDT_Unknown:
×
3681
                    case GDT_TypeCount:
3682
                        CPLAssert(false);
×
3683
                }
3684

3685
                if (eDataType != GDT_Float32 && bGotNoDataValue &&
×
3686
                    ARE_REAL_EQUAL(dfValue, dfNoDataValue))
×
3687
                    continue;
×
3688

3689
                // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
3690
                // finite, the result of the multiplication cannot be NaN
3691
                const double dfIndex = floor((dfValue - dfMin) * dfScale);
×
3692

3693
                if (dfIndex < 0)
×
3694
                {
3695
                    if (bIncludeOutOfRange)
×
3696
                        panHistogram[0]++;
×
3697
                }
3698
                else if (dfIndex >= nBuckets)
×
3699
                {
3700
                    if (bIncludeOutOfRange)
×
3701
                        ++panHistogram[nBuckets - 1];
×
3702
                }
3703
                else
3704
                {
3705
                    ++panHistogram[static_cast<int>(dfIndex)];
×
3706
                }
3707
            }
3708
        }
3709

3710
        CPLFree(pData);
×
3711
        CPLFree(pabyMaskData);
×
3712
    }
3713
    else  // No arbitrary overviews.
3714
    {
3715
        if (!InitBlockInfo())
25✔
3716
            return CE_Failure;
×
3717

3718
        /* --------------------------------------------------------------------
3719
         */
3720
        /*      Figure out the ratio of blocks we will read to get an */
3721
        /*      approximate value. */
3722
        /* --------------------------------------------------------------------
3723
         */
3724

3725
        int nSampleRate = 1;
25✔
3726
        if (bApproxOK)
25✔
3727
        {
3728
            nSampleRate = static_cast<int>(std::max(
8✔
3729
                1.0,
16✔
3730
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8✔
3731
            // We want to avoid probing only the first column of blocks for
3732
            // a square shaped raster, because it is not unlikely that it may
3733
            // be padding only (#6378).
3734
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8✔
3735
                nSampleRate += 1;
2✔
3736
        }
3737

3738
        GByte *pabyMaskData = nullptr;
25✔
3739
        if (poMaskBand)
25✔
3740
        {
3741
            pabyMaskData = static_cast<GByte *>(
3742
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
1✔
3743
            if (!pabyMaskData)
1✔
3744
            {
3745
                return CE_Failure;
×
3746
            }
3747
        }
3748

3749
        /* --------------------------------------------------------------------
3750
         */
3751
        /*      Read the blocks, and add to histogram. */
3752
        /* --------------------------------------------------------------------
3753
         */
3754
        for (int iSampleBlock = 0;
25✔
3755
             iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
109✔
3756
             iSampleBlock += nSampleRate)
84✔
3757
        {
3758
            if (!pfnProgress(
84✔
3759
                    iSampleBlock /
3760
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
84✔
3761
                    "Compute Histogram", pProgressData))
3762
            {
3763
                CPLFree(pabyMaskData);
×
3764
                return CE_Failure;
×
3765
            }
3766

3767
            const int iYBlock = iSampleBlock / nBlocksPerRow;
84✔
3768
            const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
84✔
3769

3770
            GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
84✔
3771
            if (poBlock == nullptr)
84✔
3772
            {
3773
                CPLFree(pabyMaskData);
×
3774
                return CE_Failure;
×
3775
            }
3776

3777
            void *pData = poBlock->GetDataRef();
84✔
3778

3779
            int nXCheck = 0, nYCheck = 0;
84✔
3780
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
84✔
3781

3782
            if (poMaskBand &&
85✔
3783
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
1✔
3784
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
1✔
3785
                                     pabyMaskData, nXCheck, nYCheck, GDT_Byte,
3786
                                     0, nBlockXSize, nullptr) != CE_None)
1✔
3787
            {
3788
                CPLFree(pabyMaskData);
×
3789
                poBlock->DropLock();
×
3790
                return CE_Failure;
×
3791
            }
3792

3793
            // this is a special case for a common situation.
3794
            if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
84✔
3795
                (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
62✔
3796
                nXCheck == nBlockXSize && nBuckets == 256)
59✔
3797
            {
3798
                const GPtrDiff_t nPixels =
59✔
3799
                    static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
59✔
3800
                GByte *pabyData = static_cast<GByte *>(pData);
59✔
3801

3802
                for (GPtrDiff_t i = 0; i < nPixels; i++)
64,211✔
3803
                {
3804
                    if (pabyMaskData && pabyMaskData[i] == 0)
64,152✔
3805
                        continue;
×
3806
                    if (!(bGotNoDataValue &&
64,664✔
3807
                          (pabyData[i] == static_cast<GByte>(dfNoDataValue))))
64,152✔
3808
                    {
3809
                        panHistogram[pabyData[i]]++;
63,896✔
3810
                    }
3811
                }
3812

3813
                poBlock->DropLock();
59✔
3814
                continue;  // To next sample block.
59✔
3815
            }
3816

3817
            // This isn't the fastest way to do this, but is easier for now.
3818
            for (int iY = 0; iY < nYCheck; iY++)
721✔
3819
            {
3820
                for (int iX = 0; iX < nXCheck; iX++)
86,017✔
3821
                {
3822
                    const GPtrDiff_t iOffset =
85,321✔
3823
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
85,321✔
3824

3825
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
85,321✔
3826
                        continue;
1✔
3827

3828
                    double dfValue = 0.0;
85,320✔
3829

3830
                    switch (eDataType)
85,320✔
3831
                    {
3832
                        case GDT_Byte:
19,716✔
3833
                        {
3834
                            if (bSignedByte)
19,716✔
3835
                                dfValue =
×
3836
                                    static_cast<signed char *>(pData)[iOffset];
×
3837
                            else
3838
                                dfValue = static_cast<GByte *>(pData)[iOffset];
19,716✔
3839
                            break;
19,716✔
3840
                        }
3841
                        case GDT_Int8:
×
3842
                            dfValue = static_cast<GInt8 *>(pData)[iOffset];
×
3843
                            break;
×
3844
                        case GDT_UInt16:
65,536✔
3845
                            dfValue = static_cast<GUInt16 *>(pData)[iOffset];
65,536✔
3846
                            break;
65,536✔
3847
                        case GDT_Int16:
2✔
3848
                            dfValue = static_cast<GInt16 *>(pData)[iOffset];
2✔
3849
                            break;
2✔
3850
                        case GDT_UInt32:
×
3851
                            dfValue = static_cast<GUInt32 *>(pData)[iOffset];
×
3852
                            break;
×
3853
                        case GDT_Int32:
60✔
3854
                            dfValue = static_cast<GInt32 *>(pData)[iOffset];
60✔
3855
                            break;
60✔
3856
                        case GDT_UInt64:
×
3857
                            dfValue = static_cast<double>(
×
3858
                                static_cast<GUInt64 *>(pData)[iOffset]);
×
3859
                            break;
×
3860
                        case GDT_Int64:
×
3861
                            dfValue = static_cast<double>(
×
3862
                                static_cast<GInt64 *>(pData)[iOffset]);
×
3863
                            break;
×
3864
                        case GDT_Float32:
4✔
3865
                        {
3866
                            const float fValue =
4✔
3867
                                static_cast<float *>(pData)[iOffset];
4✔
3868
                            if (CPLIsNan(fValue) ||
8✔
3869
                                (bGotFloatNoDataValue &&
4✔
3870
                                 ARE_REAL_EQUAL(fValue, fNoDataValue)))
4✔
3871
                                continue;
1✔
3872
                            dfValue = fValue;
3✔
3873
                            break;
3✔
3874
                        }
3875
                        case GDT_Float64:
2✔
3876
                            dfValue = static_cast<double *>(pData)[iOffset];
2✔
3877
                            if (CPLIsNan(dfValue))
2✔
3878
                                continue;
×
3879
                            break;
2✔
3880
                        case GDT_CInt16:
×
3881
                        {
3882
                            double dfReal =
×
3883
                                static_cast<GInt16 *>(pData)[iOffset * 2];
×
3884
                            double dfImag =
×
3885
                                static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
×
3886
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
×
3887
                        }
3888
                        break;
×
3889
                        case GDT_CInt32:
×
3890
                        {
3891
                            double dfReal =
×
3892
                                static_cast<GInt32 *>(pData)[iOffset * 2];
×
3893
                            double dfImag =
×
3894
                                static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
×
3895
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
×
3896
                        }
3897
                        break;
×
3898
                        case GDT_CFloat32:
×
3899
                        {
3900
                            double dfReal =
×
3901
                                static_cast<float *>(pData)[iOffset * 2];
×
3902
                            double dfImag =
×
3903
                                static_cast<float *>(pData)[iOffset * 2 + 1];
×
3904
                            if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
×
3905
                                continue;
×
3906
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
×
3907
                        }
3908
                        break;
×
3909
                        case GDT_CFloat64:
×
3910
                        {
3911
                            double dfReal =
×
3912
                                static_cast<double *>(pData)[iOffset * 2];
×
3913
                            double dfImag =
×
3914
                                static_cast<double *>(pData)[iOffset * 2 + 1];
×
3915
                            if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
×
3916
                                continue;
×
3917
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
×
3918
                        }
3919
                        break;
×
3920
                        case GDT_Unknown:
×
3921
                        case GDT_TypeCount:
3922
                            CPLAssert(false);
×
3923
                            CPLFree(pabyMaskData);
3924
                            return CE_Failure;
3925
                    }
3926

3927
                    if (eDataType != GDT_Float32 && bGotNoDataValue &&
85,319✔
3928
                        ARE_REAL_EQUAL(dfValue, dfNoDataValue))
×
3929
                        continue;
×
3930

3931
                    // Given that dfValue and dfMin are not NaN, and dfScale > 0
3932
                    // and finite, the result of the multiplication cannot be
3933
                    // NaN
3934
                    const double dfIndex = floor((dfValue - dfMin) * dfScale);
85,319✔
3935

3936
                    if (dfIndex < 0)
85,319✔
3937
                    {
3938
                        if (bIncludeOutOfRange)
1✔
3939
                            panHistogram[0]++;
1✔
3940
                    }
3941
                    else if (dfIndex >= nBuckets)
85,318✔
3942
                    {
3943
                        if (bIncludeOutOfRange)
7✔
3944
                            ++panHistogram[nBuckets - 1];
4✔
3945
                    }
3946
                    else
3947
                    {
3948
                        ++panHistogram[static_cast<int>(dfIndex)];
85,311✔
3949
                    }
3950
                }
3951
            }
3952

3953
            poBlock->DropLock();
25✔
3954
        }
3955

3956
        CPLFree(pabyMaskData);
25✔
3957
    }
3958

3959
    pfnProgress(1.0, "Compute Histogram", pProgressData);
25✔
3960

3961
    return CE_None;
25✔
3962
}
3963

3964
/************************************************************************/
3965
/*                       GDALGetRasterHistogram()                       */
3966
/************************************************************************/
3967

3968
/**
3969
 * \brief Compute raster histogram.
3970
 *
3971
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
3972
 * exceeding 2 billion.
3973
 *
3974
 * @see GDALRasterBand::GetHistogram()
3975
 * @see GDALGetRasterHistogramEx()
3976
 */
3977

3978
CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
×
3979
                                          double dfMax, int nBuckets,
3980
                                          int *panHistogram,
3981
                                          int bIncludeOutOfRange, int bApproxOK,
3982
                                          GDALProgressFunc pfnProgress,
3983
                                          void *pProgressData)
3984

3985
{
3986
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
×
3987
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
×
3988

3989
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
×
3990

3991
    GUIntBig *panHistogramTemp =
3992
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
×
3993
    if (panHistogramTemp == nullptr)
×
3994
    {
3995
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
×
3996
                            "Out of memory in GDALGetRasterHistogram().");
3997
        return CE_Failure;
×
3998
    }
3999

4000
    CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
×
4001
                                       bIncludeOutOfRange, bApproxOK,
4002
                                       pfnProgress, pProgressData);
×
4003

4004
    if (eErr == CE_None)
×
4005
    {
4006
        for (int i = 0; i < nBuckets; i++)
×
4007
        {
4008
            if (panHistogramTemp[i] > INT_MAX)
×
4009
            {
4010
                CPLError(CE_Warning, CPLE_AppDefined,
×
4011
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
4012
                         " exceeds maximum 32 bit value",
4013
                         i, panHistogramTemp[i]);
×
4014
                panHistogram[i] = INT_MAX;
×
4015
            }
4016
            else
4017
            {
4018
                panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
×
4019
            }
4020
        }
4021
    }
4022

4023
    CPLFree(panHistogramTemp);
×
4024

4025
    return eErr;
×
4026
}
4027

4028
/************************************************************************/
4029
/*                      GDALGetRasterHistogramEx()                      */
4030
/************************************************************************/
4031

4032
/**
4033
 * \brief Compute raster histogram.
4034
 *
4035
 * @see GDALRasterBand::GetHistogram()
4036
 *
4037
 * @since GDAL 2.0
4038
 */
4039

4040
CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
26✔
4041
    GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4042
    GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4043
    GDALProgressFunc pfnProgress, void *pProgressData)
4044

4045
{
4046
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
26✔
4047
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
26✔
4048

4049
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
26✔
4050

4051
    return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
26✔
4052
                                bIncludeOutOfRange, bApproxOK, pfnProgress,
4053
                                pProgressData);
26✔
4054
}
4055

4056
/************************************************************************/
4057
/*                        GetDefaultHistogram()                         */
4058
/************************************************************************/
4059

4060
/**
4061
 * \brief Fetch default raster histogram.
4062
 *
4063
 * The default method in GDALRasterBand will compute a default histogram. This
4064
 * method is overridden by derived classes (such as GDALPamRasterBand,
4065
 * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4066
 * stored histogram.
4067
 *
4068
 * This method is the same as the C functions GDALGetDefaultHistogram() and
4069
 * GDALGetDefaultHistogramEx().
4070
 *
4071
 * @param pdfMin pointer to double value that will contain the lower bound of
4072
 * the histogram.
4073
 * @param pdfMax pointer to double value that will contain the upper bound of
4074
 * the histogram.
4075
 * @param pnBuckets pointer to int value that will contain the number of buckets
4076
 * in *ppanHistogram.
4077
 * @param ppanHistogram pointer to array into which the histogram totals are
4078
 * placed. To be freed with VSIFree
4079
 * @param bForce TRUE to force the computation. If FALSE and no default
4080
 * histogram is available, the method will return CE_Warning
4081
 * @param pfnProgress function to report progress to completion.
4082
 * @param pProgressData application data to pass to pfnProgress.
4083
 *
4084
 * @return CE_None on success, CE_Failure if something goes wrong, or
4085
 * CE_Warning if no default histogram is available.
4086
 */
4087

4088
CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
18✔
4089
                                           int *pnBuckets,
4090
                                           GUIntBig **ppanHistogram, int bForce,
4091
                                           GDALProgressFunc pfnProgress,
4092
                                           void *pProgressData)
4093

4094
{
4095
    CPLAssert(nullptr != pnBuckets);
18✔
4096
    CPLAssert(nullptr != ppanHistogram);
18✔
4097
    CPLAssert(nullptr != pdfMin);
18✔
4098
    CPLAssert(nullptr != pdfMax);
18✔
4099

4100
    *pnBuckets = 0;
18✔
4101
    *ppanHistogram = nullptr;
18✔
4102

4103
    if (!bForce)
18✔
4104
        return CE_Warning;
6✔
4105

4106
    const int nBuckets = 256;
12✔
4107

4108
    bool bSignedByte = false;
12✔
4109
    if (eDataType == GDT_Byte)
12✔
4110
    {
4111
        EnablePixelTypeSignedByteWarning(false);
12✔
4112
        const char *pszPixelType =
4113
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
12✔
4114
        EnablePixelTypeSignedByteWarning(true);
12✔
4115
        bSignedByte =
12✔
4116
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
12✔
4117
    }
4118

4119
    if (GetRasterDataType() == GDT_Byte && !bSignedByte)
12✔
4120
    {
4121
        *pdfMin = -0.5;
12✔
4122
        *pdfMax = 255.5;
12✔
4123
    }
4124
    else
4125
    {
4126

4127
        const CPLErr eErr =
4128
            GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
×
4129
        const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
×
4130
        *pdfMin -= dfHalfBucket;
×
4131
        *pdfMax += dfHalfBucket;
×
4132

4133
        if (eErr != CE_None)
×
4134
            return eErr;
×
4135
    }
4136

4137
    *ppanHistogram =
12✔
4138
        static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
12✔
4139
    if (*ppanHistogram == nullptr)
12✔
4140
    {
4141
        ReportError(CE_Failure, CPLE_OutOfMemory,
×
4142
                    "Out of memory in InitBlockInfo().");
4143
        return CE_Failure;
×
4144
    }
4145

4146
    *pnBuckets = nBuckets;
12✔
4147
    CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
24✔
4148
                               TRUE, FALSE, pfnProgress, pProgressData);
12✔
4149
    if (eErr != CE_None)
12✔
4150
    {
4151
        *pnBuckets = 0;
×
4152
    }
4153
    return eErr;
12✔
4154
}
4155

4156
/************************************************************************/
4157
/*                      GDALGetDefaultHistogram()                       */
4158
/************************************************************************/
4159

4160
/**
4161
 * \brief Fetch default raster histogram.
4162
 *
4163
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4164
 * exceeding 2 billion.
4165
 *
4166
 * @see GDALRasterBand::GDALGetDefaultHistogram()
4167
 * @see GDALGetRasterHistogramEx()
4168
 */
4169

4170
CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
×
4171
                                           double *pdfMin, double *pdfMax,
4172
                                           int *pnBuckets, int **ppanHistogram,
4173
                                           int bForce,
4174
                                           GDALProgressFunc pfnProgress,
4175
                                           void *pProgressData)
4176

4177
{
4178
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
×
4179
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
×
4180
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
×
4181
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
×
4182
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
×
4183

4184
    GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
×
4185
    GUIntBig *panHistogramTemp = nullptr;
×
4186
    CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
×
4187
                                              &panHistogramTemp, bForce,
4188
                                              pfnProgress, pProgressData);
×
4189
    if (eErr == CE_None)
×
4190
    {
4191
        const int nBuckets = *pnBuckets;
×
4192
        *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
×
4193
        if (*ppanHistogram == nullptr)
×
4194
        {
4195
            poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
×
4196
                                "Out of memory in GDALGetDefaultHistogram().");
4197
            VSIFree(panHistogramTemp);
×
4198
            return CE_Failure;
×
4199
        }
4200

4201
        for (int i = 0; i < nBuckets; ++i)
×
4202
        {
4203
            if (panHistogramTemp[i] > INT_MAX)
×
4204
            {
4205
                CPLError(CE_Warning, CPLE_AppDefined,
×
4206
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
4207
                         " exceeds maximum 32 bit value",
4208
                         i, panHistogramTemp[i]);
×
4209
                (*ppanHistogram)[i] = INT_MAX;
×
4210
            }
4211
            else
4212
            {
4213
                (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
×
4214
            }
4215
        }
4216

4217
        CPLFree(panHistogramTemp);
×
4218
    }
4219
    else
4220
    {
4221
        *ppanHistogram = nullptr;
×
4222
    }
4223

4224
    return eErr;
×
4225
}
4226

4227
/************************************************************************/
4228
/*                      GDALGetDefaultHistogramEx()                     */
4229
/************************************************************************/
4230

4231
/**
4232
 * \brief Fetch default raster histogram.
4233
 *
4234
 * @see GDALRasterBand::GetDefaultHistogram()
4235
 *
4236
 * @since GDAL 2.0
4237
 */
4238

4239
CPLErr CPL_STDCALL
4240
GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
15✔
4241
                          int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
4242
                          GDALProgressFunc pfnProgress, void *pProgressData)
4243

4244
{
4245
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
15✔
4246
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
15✔
4247
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
15✔
4248
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
15✔
4249
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
15✔
4250

4251
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
15✔
4252
    return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
15✔
4253
                                       bForce, pfnProgress, pProgressData);
15✔
4254
}
4255

4256
/************************************************************************/
4257
/*                             AdviseRead()                             */
4258
/************************************************************************/
4259

4260
/**
4261
 * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
4262
 * \brief Advise driver of upcoming read requests.
4263
 *
4264
 * Some GDAL drivers operate more efficiently if they know in advance what
4265
 * set of upcoming read requests will be made.  The AdviseRead() method allows
4266
 * an application to notify the driver of the region of interest,
4267
 * and at what resolution the region will be read.
4268
 *
4269
 * Many drivers just ignore the AdviseRead() call, but it can dramatically
4270
 * accelerate access via some drivers.
4271
 *
4272
 * Depending on call paths, drivers might receive several calls to
4273
 * AdviseRead() with the same parameters.
4274
 *
4275
 * @param nXOff The pixel offset to the top left corner of the region
4276
 * of the band to be accessed.  This would be zero to start from the left side.
4277
 *
4278
 * @param nYOff The line offset to the top left corner of the region
4279
 * of the band to be accessed.  This would be zero to start from the top.
4280
 *
4281
 * @param nXSize The width of the region of the band to be accessed in pixels.
4282
 *
4283
 * @param nYSize The height of the region of the band to be accessed in lines.
4284
 *
4285
 * @param nBufXSize the width of the buffer image into which the desired region
4286
 * is to be read, or from which it is to be written.
4287
 *
4288
 * @param nBufYSize the height of the buffer image into which the desired
4289
 * region is to be read, or from which it is to be written.
4290
 *
4291
 * @param eBufType the type of the pixel values in the pData data buffer.  The
4292
 * pixel values will automatically be translated to/from the GDALRasterBand
4293
 * data type as needed.
4294
 *
4295
 * @param papszOptions a list of name=value strings with special control
4296
 * options.  Normally this is NULL.
4297
 *
4298
 * @return CE_Failure if the request is invalid and CE_None if it works or
4299
 * is ignored.
4300
 */
4301

4302
/**/
4303
/**/
4304

4305
CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
41,569✔
4306
                                  int /*nYSize*/, int /*nBufXSize*/,
4307
                                  int /*nBufYSize*/, GDALDataType /*eBufType*/,
4308
                                  char ** /*papszOptions*/)
4309
{
4310
    return CE_None;
41,569✔
4311
}
4312

4313
/************************************************************************/
4314
/*                        GDALRasterAdviseRead()                        */
4315
/************************************************************************/
4316

4317
/**
4318
 * \brief Advise driver of upcoming read requests.
4319
 *
4320
 * @see GDALRasterBand::AdviseRead()
4321
 */
4322

4323
CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
2✔
4324
                                        int nYOff, int nXSize, int nYSize,
4325
                                        int nBufXSize, int nBufYSize,
4326
                                        GDALDataType eDT,
4327
                                        CSLConstList papszOptions)
4328

4329
{
4330
    VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
2✔
4331

4332
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2✔
4333
    return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
2✔
4334
                              nBufYSize, eDT,
4335
                              const_cast<char **>(papszOptions));
2✔
4336
}
4337

4338
/************************************************************************/
4339
/*                           GetStatistics()                            */
4340
/************************************************************************/
4341

4342
/**
4343
 * \brief Fetch image statistics.
4344
 *
4345
 * Returns the minimum, maximum, mean and standard deviation of all
4346
 * pixel values in this band.  If approximate statistics are sufficient,
4347
 * the bApproxOK flag can be set to true in which case overviews, or a
4348
 * subset of image tiles may be used in computing the statistics.
4349
 *
4350
 * If bForce is FALSE results will only be returned if it can be done
4351
 * quickly (i.e. without scanning the image, typically by using pre-existing
4352
 * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
4353
 * returned efficiently, the method will return CE_Warning but no warning will
4354
 * be issued. This is a non-standard use of the CE_Warning return value
4355
 * to indicate "nothing done".
4356
 *
4357
 * If bForce is TRUE, and results are quickly available without scanning the
4358
 * image, they will be used. If bForce is TRUE and results are not quickly
4359
 * available, GetStatistics() forwards the computation to ComputeStatistics(),
4360
 * which will scan the image.
4361
 *
4362
 * To always force recomputation of statistics, use ComputeStatistics() instead
4363
 * of this method.
4364
 *
4365
 * Note that file formats using PAM (Persistent Auxiliary Metadata) services
4366
 * will generally cache statistics in the .pam file allowing fast fetch
4367
 * after the first request.
4368
 *
4369
 * This method is the same as the C function GDALGetRasterStatistics().
4370
 *
4371
 * @param bApproxOK If TRUE statistics may be computed based on overviews
4372
 * or a subset of all tiles.
4373
 *
4374
 * @param bForce If FALSE statistics will only be returned if it can
4375
 * be done without rescanning the image. If TRUE, statistics computation will
4376
 * be forced if pre-existing values are not quickly available.
4377
 *
4378
 * @param pdfMin Location into which to load image minimum (may be NULL).
4379
 *
4380
 * @param pdfMax Location into which to load image maximum (may be NULL).-
4381
 *
4382
 * @param pdfMean Location into which to load image mean (may be NULL).
4383
 *
4384
 * @param pdfStdDev Location into which to load image standard deviation
4385
 * (may be NULL).
4386
 *
4387
 * @return CE_None on success, CE_Warning if no values returned,
4388
 * CE_Failure if an error occurs.
4389
 */
4390

4391
CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
588✔
4392
                                     double *pdfMax, double *pdfMean,
4393
                                     double *pdfStdDev)
4394

4395
{
4396
    /* -------------------------------------------------------------------- */
4397
    /*      Do we already have metadata items for the requested values?     */
4398
    /* -------------------------------------------------------------------- */
4399
    if ((pdfMin == nullptr ||
1,176✔
4400
         GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
588✔
4401
        (pdfMax == nullptr ||
209✔
4402
         GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
209✔
4403
        (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
1,385✔
4404
        (pdfStdDev == nullptr ||
209✔
4405
         GetMetadataItem("STATISTICS_STDDEV") != nullptr))
209✔
4406
    {
4407
        if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
209✔
4408
        {
4409
            if (pdfMin != nullptr)
202✔
4410
                *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
202✔
4411
            if (pdfMax != nullptr)
202✔
4412
                *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
202✔
4413
            if (pdfMean != nullptr)
202✔
4414
                *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
202✔
4415
            if (pdfStdDev != nullptr)
202✔
4416
                *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
202✔
4417

4418
            return CE_None;
202✔
4419
        }
4420
    }
4421

4422
    /* -------------------------------------------------------------------- */
4423
    /*      Does the driver already know the min/max?                       */
4424
    /* -------------------------------------------------------------------- */
4425
    if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
386✔
4426
    {
4427
        int bSuccessMin = FALSE;
×
4428
        int bSuccessMax = FALSE;
×
4429

4430
        const double dfMin = GetMinimum(&bSuccessMin);
×
4431
        const double dfMax = GetMaximum(&bSuccessMax);
×
4432

4433
        if (bSuccessMin && bSuccessMax)
×
4434
        {
4435
            if (pdfMin != nullptr)
×
4436
                *pdfMin = dfMin;
×
4437
            if (pdfMax != nullptr)
×
4438
                *pdfMax = dfMax;
×
4439
            return CE_None;
×
4440
        }
4441
    }
4442

4443
    /* -------------------------------------------------------------------- */
4444
    /*      Either return without results, or force computation.            */
4445
    /* -------------------------------------------------------------------- */
4446
    if (!bForce)
386✔
4447
        return CE_Warning;
136✔
4448
    else
4449
        return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
250✔
4450
                                 GDALDummyProgress, nullptr);
250✔
4451
}
4452

4453
/************************************************************************/
4454
/*                      GDALGetRasterStatistics()                       */
4455
/************************************************************************/
4456

4457
/**
4458
 * \brief Fetch image statistics.
4459
 *
4460
 * @see GDALRasterBand::GetStatistics()
4461
 */
4462

4463
CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
237✔
4464
                                           int bForce, double *pdfMin,
4465
                                           double *pdfMax, double *pdfMean,
4466
                                           double *pdfStdDev)
4467

4468
{
4469
    VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
237✔
4470

4471
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
237✔
4472
    return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
237✔
4473
                                 pdfStdDev);
237✔
4474
}
4475

4476
#ifdef CPL_HAS_GINT64
4477

4478
/************************************************************************/
4479
/*                         GDALUInt128                                  */
4480
/************************************************************************/
4481

4482
#ifdef HAVE_UINT128_T
4483
class GDALUInt128
4484
{
4485
    __uint128_t val;
4486

4487
    explicit GDALUInt128(__uint128_t valIn) : val(valIn)
603✔
4488
    {
4489
    }
603✔
4490

4491
  public:
4492
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
402✔
4493
    {
4494
        // Evaluates to just a single mul on x86_64
4495
        return GDALUInt128(static_cast<__uint128_t>(first) * second);
402✔
4496
    }
4497

4498
    GDALUInt128 operator-(const GDALUInt128 &other) const
201✔
4499
    {
4500
        return GDALUInt128(val - other.val);
201✔
4501
    }
4502

4503
    operator double() const
192✔
4504
    {
4505
        return static_cast<double>(val);
192✔
4506
    }
4507
};
4508
#else
4509

4510
#if defined(_MSC_VER) && defined(_M_X64)
4511
#include <intrin.h>
4512
#endif
4513

4514
class GDALUInt128
4515
{
4516
    GUIntBig low, high;
4517

4518
    GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
4519
    {
4520
    }
4521

4522
  public:
4523
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
4524
    {
4525
#if defined(_MSC_VER) && defined(_M_X64)
4526
        GUIntBig highRes;
4527
        GUIntBig lowRes = _umul128(first, second, &highRes);
4528
        return GDALUInt128(lowRes, highRes);
4529
#else
4530
        const GUInt32 firstLow = static_cast<GUInt32>(first);
4531
        const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
4532
        const GUInt32 secondLow = static_cast<GUInt32>(second);
4533
        const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
4534
        GUIntBig highRes = 0;
4535
        const GUIntBig firstLowSecondHigh =
4536
            static_cast<GUIntBig>(firstLow) * secondHigh;
4537
        const GUIntBig firstHighSecondLow =
4538
            static_cast<GUIntBig>(firstHigh) * secondLow;
4539
        const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
4540
        if (middleTerm < firstLowSecondHigh)  // check for overflow
4541
            highRes += static_cast<GUIntBig>(1) << 32;
4542
        const GUIntBig firstLowSecondLow =
4543
            static_cast<GUIntBig>(firstLow) * secondLow;
4544
        GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
4545
        if (lowRes < firstLowSecondLow)  // check for overflow
4546
            highRes++;
4547
        highRes +=
4548
            (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
4549
        return GDALUInt128(lowRes, highRes);
4550
#endif
4551
    }
4552

4553
    GDALUInt128 operator-(const GDALUInt128 &other) const
4554
    {
4555
        GUIntBig highRes = high - other.high;
4556
        GUIntBig lowRes = low - other.low;
4557
        if (lowRes > low)  // check for underflow
4558
            --highRes;
4559
        return GDALUInt128(lowRes, highRes);
4560
    }
4561

4562
    operator double() const
4563
    {
4564
        const double twoPow64 = 18446744073709551616.0;
4565
        return high * twoPow64 + low;
4566
    }
4567
};
4568
#endif
4569

4570
/************************************************************************/
4571
/*                    ComputeStatisticsInternal()                       */
4572
/************************************************************************/
4573

4574
// Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
4575
// not needed.
4576
#define static_cast_for_coverity_scan static_cast
4577

4578
// The rationale for below optimizations is detailed in statistics.txt
4579

4580
// Use with T = GByte or GUInt16 only !
4581
template <class T, bool COMPUTE_OTHER_STATS>
4582
struct ComputeStatisticsInternalGeneric
4583
{
4584
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
179✔
4585
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
4586
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
4587
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
4588
    {
4589
        static_assert(std::is_same<T, GByte>::value ||
4590
                          std::is_same<T, GUInt16>::value,
4591
                      "bad type for T");
4592
        if (bHasNoData)
179✔
4593
        {
4594
            // General case
4595
            for (int iY = 0; iY < nYCheck; iY++)
386✔
4596
            {
4597
                for (int iX = 0; iX < nXCheck; iX++)
81,751✔
4598
                {
4599
                    const GPtrDiff_t iOffset =
81,468✔
4600
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
81,468✔
4601
                    const GUInt32 nValue = pData[iOffset];
81,468✔
4602
                    if (nValue == nNoDataValue)
81,468✔
4603
                        continue;
175✔
4604
                    if (nValue < nMin)
81,293✔
4605
                        nMin = nValue;
26✔
4606
                    if (nValue > nMax)
81,293✔
4607
                        nMax = nValue;
57✔
4608
                    if constexpr (COMPUTE_OTHER_STATS)
4609
                    {
4610
                        nValidCount++;
79,657✔
4611
                        nSum += nValue;
79,657✔
4612
                        nSumSquare +=
79,657✔
4613
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
79,657✔
4614
                            nValue;
79,657✔
4615
                    }
4616
                }
4617
            }
4618
            if constexpr (COMPUTE_OTHER_STATS)
4619
            {
4620
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
20✔
4621
            }
4622
        }
4623
        else if (nMin == std::numeric_limits<T>::min() &&
84✔
4624
                 nMax == std::numeric_limits<T>::max())
8✔
4625
        {
4626
            if constexpr (COMPUTE_OTHER_STATS)
4627
            {
4628
                // Optimization when there is no nodata and we know we have already
4629
                // reached the min and max
4630
                for (int iY = 0; iY < nYCheck; iY++)
208✔
4631
                {
4632
                    int iX;
4633
                    for (iX = 0; iX + 3 < nXCheck; iX += 4)
1,002✔
4634
                    {
4635
                        const GPtrDiff_t iOffset =
800✔
4636
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
800✔
4637
                        const GUIntBig nValue = pData[iOffset];
800✔
4638
                        const GUIntBig nValue2 = pData[iOffset + 1];
800✔
4639
                        const GUIntBig nValue3 = pData[iOffset + 2];
800✔
4640
                        const GUIntBig nValue4 = pData[iOffset + 3];
800✔
4641
                        nSum += nValue;
800✔
4642
                        nSumSquare += nValue * nValue;
800✔
4643
                        nSum += nValue2;
800✔
4644
                        nSumSquare += nValue2 * nValue2;
800✔
4645
                        nSum += nValue3;
800✔
4646
                        nSumSquare += nValue3 * nValue3;
800✔
4647
                        nSum += nValue4;
800✔
4648
                        nSumSquare += nValue4 * nValue4;
800✔
4649
                    }
4650
                    for (; iX < nXCheck; ++iX)
207✔
4651
                    {
4652
                        const GPtrDiff_t iOffset =
5✔
4653
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5✔
4654
                        const GUIntBig nValue = pData[iOffset];
5✔
4655
                        nSum += nValue;
5✔
4656
                        nSumSquare += nValue * nValue;
5✔
4657
                    }
4658
                }
4659
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6✔
4660
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6✔
4661
            }
4662
        }
4663
        else
4664
        {
4665
            for (int iY = 0; iY < nYCheck; iY++)
3,360✔
4666
            {
4667
                int iX;
4668
                for (iX = 0; iX + 1 < nXCheck; iX += 2)
635,035✔
4669
                {
4670
                    const GPtrDiff_t iOffset =
631,745✔
4671
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
631,745✔
4672
                    const GUInt32 nValue = pData[iOffset];
631,745✔
4673
                    const GUInt32 nValue2 = pData[iOffset + 1];
631,745✔
4674
                    if (nValue < nValue2)
631,745✔
4675
                    {
4676
                        if (nValue < nMin)
2,160✔
4677
                            nMin = nValue;
48✔
4678
                        if (nValue2 > nMax)
2,160✔
4679
                            nMax = nValue2;
108✔
4680
                    }
4681
                    else
4682
                    {
4683
                        if (nValue2 < nMin)
629,585✔
4684
                            nMin = nValue2;
61✔
4685
                        if (nValue > nMax)
629,585✔
4686
                            nMax = nValue;
212✔
4687
                    }
4688
                    if constexpr (COMPUTE_OTHER_STATS)
4689
                    {
4690
                        nSum += nValue;
624,695✔
4691
                        nSumSquare +=
624,695✔
4692
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
624,695✔
4693
                            nValue;
624,695✔
4694
                        nSum += nValue2;
624,695✔
4695
                        nSumSquare +=
624,695✔
4696
                            static_cast_for_coverity_scan<GUIntBig>(nValue2) *
624,695✔
4697
                            nValue2;
624,695✔
4698
                    }
4699
                }
4700
                if (iX < nXCheck)
3,290✔
4701
                {
4702
                    const GPtrDiff_t iOffset =
9✔
4703
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
9✔
4704
                    const GUInt32 nValue = pData[iOffset];
9✔
4705
                    if (nValue < nMin)
9✔
4706
                        nMin = nValue;
6✔
4707
                    if (nValue > nMax)
9✔
4708
                        nMax = nValue;
6✔
4709
                    if (COMPUTE_OTHER_STATS)
4710
                    {
4711
                        nSum += nValue;
9✔
4712
                        nSumSquare +=
9✔
4713
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
9✔
4714
                            nValue;
9✔
4715
                    }
4716
                }
4717
            }
4718
            if constexpr (COMPUTE_OTHER_STATS)
4719
            {
4720
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
25✔
4721
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
25✔
4722
            }
4723
        }
4724
    }
179✔
4725
};
4726

4727
// Specialization for Byte that is mostly 32 bit friendly as it avoids
4728
// using 64bit accumulators in internal loops. This also slightly helps in
4729
// 64bit mode.
4730
template <bool COMPUTE_OTHER_STATS>
4731
struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
4732
{
4733
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
11,605✔
4734
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
4735
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
4736
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
4737
    {
4738
        int nOuterLoops = nXCheck / 65536;
11,605✔
4739
        if (nXCheck % 65536)
11,605✔
4740
            nOuterLoops++;
11,605✔
4741

4742
        if (bHasNoData)
11,605✔
4743
        {
4744
            // General case
4745
            for (int iY = 0; iY < nYCheck; iY++)
19,549✔
4746
            {
4747
                int iX = 0;
10,938✔
4748
                for (int k = 0; k < nOuterLoops; k++)
21,876✔
4749
                {
4750
                    int iMax = iX + 65536;
10,938✔
4751
                    if (iMax > nXCheck)
10,938✔
4752
                        iMax = nXCheck;
10,938✔
4753
                    GUInt32 nSum32bit = 0;
10,938✔
4754
                    GUInt32 nSumSquare32bit = 0;
10,938✔
4755
                    GUInt32 nValidCount32bit = 0;
10,938✔
4756
                    GUInt32 nSampleCount32bit = 0;
10,938✔
4757
                    for (; iX < iMax; iX++)
16,705,781✔
4758
                    {
4759
                        const GPtrDiff_t iOffset =
16,694,931✔
4760
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
16,694,931✔
4761
                        const GUInt32 nValue = pData[iOffset];
16,694,931✔
4762

4763
                        nSampleCount32bit++;
16,694,931✔
4764
                        if (nValue == nNoDataValue)
16,694,931✔
4765
                            continue;
16,353,480✔
4766
                        if (nValue < nMin)
341,396✔
4767
                            nMin = nValue;
343✔
4768
                        if (nValue > nMax)
341,396✔
4769
                            nMax = nValue;
828✔
4770
                        if constexpr (COMPUTE_OTHER_STATS)
4771
                        {
4772
                            nValidCount32bit++;
16,951✔
4773
                            nSum32bit += nValue;
16,951✔
4774
                            nSumSquare32bit += nValue * nValue;
16,951✔
4775
                        }
4776
                    }
4777
                    if constexpr (COMPUTE_OTHER_STATS)
4778
                    {
4779
                        nSampleCount += nSampleCount32bit;
650✔
4780
                        nValidCount += nValidCount32bit;
650✔
4781
                        nSum += nSum32bit;
650✔
4782
                        nSumSquare += nSumSquare32bit;
650✔
4783
                    }
4784
                }
4785
            }
4786
        }
4787
        else if (nMin == 0 && nMax == 255)
2,994✔
4788
        {
4789
            if constexpr (COMPUTE_OTHER_STATS)
4790
            {
4791
                // Optimization when there is no nodata and we know we have already
4792
                // reached the min and max
4793
                for (int iY = 0; iY < nYCheck; iY++)
2,644✔
4794
                {
4795
                    int iX = 0;
2,617✔
4796
                    for (int k = 0; k < nOuterLoops; k++)
5,234✔
4797
                    {
4798
                        int iMax = iX + 65536;
2,617✔
4799
                        if (iMax > nXCheck)
2,617✔
4800
                            iMax = nXCheck;
2,617✔
4801
                        GUInt32 nSum32bit = 0;
2,617✔
4802
                        GUInt32 nSumSquare32bit = 0;
2,617✔
4803
                        for (; iX + 3 < iMax; iX += 4)
176,297✔
4804
                        {
4805
                            const GPtrDiff_t iOffset =
173,680✔
4806
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
173,680✔
4807
                            const GUInt32 nValue = pData[iOffset];
173,680✔
4808
                            const GUInt32 nValue2 = pData[iOffset + 1];
173,680✔
4809
                            const GUInt32 nValue3 = pData[iOffset + 2];
173,680✔
4810
                            const GUInt32 nValue4 = pData[iOffset + 3];
173,680✔
4811
                            nSum32bit += nValue;
173,680✔
4812
                            nSumSquare32bit += nValue * nValue;
173,680✔
4813
                            nSum32bit += nValue2;
173,680✔
4814
                            nSumSquare32bit += nValue2 * nValue2;
173,680✔
4815
                            nSum32bit += nValue3;
173,680✔
4816
                            nSumSquare32bit += nValue3 * nValue3;
173,680✔
4817
                            nSum32bit += nValue4;
173,680✔
4818
                            nSumSquare32bit += nValue4 * nValue4;
173,680✔
4819
                        }
4820
                        nSum += nSum32bit;
2,617✔
4821
                        nSumSquare += nSumSquare32bit;
2,617✔
4822
                    }
4823
                    for (; iX < nXCheck; ++iX)
2,620✔
4824
                    {
4825
                        const GPtrDiff_t iOffset =
3✔
4826
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
3✔
4827
                        const GUIntBig nValue = pData[iOffset];
3✔
4828
                        nSum += nValue;
3✔
4829
                        nSumSquare += nValue * nValue;
3✔
4830
                    }
4831
                }
4832
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
27✔
4833
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
27✔
4834
            }
27✔
4835
        }
4836
        else
4837
        {
4838
            for (int iY = 0; iY < nYCheck; iY++)
7,335✔
4839
            {
4840
                int iX = 0;
4,368✔
4841
                for (int k = 0; k < nOuterLoops; k++)
8,736✔
4842
                {
4843
                    int iMax = iX + 65536;
4,368✔
4844
                    if (iMax > nXCheck)
4,368✔
4845
                        iMax = nXCheck;
4,368✔
4846
                    GUInt32 nSum32bit = 0;
4,368✔
4847
                    GUInt32 nSumSquare32bit = 0;
4,368✔
4848
                    for (; iX + 1 < iMax; iX += 2)
159,809✔
4849
                    {
4850
                        const GPtrDiff_t iOffset =
155,441✔
4851
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
155,441✔
4852
                        const GUInt32 nValue = pData[iOffset];
155,441✔
4853
                        const GUInt32 nValue2 = pData[iOffset + 1];
155,441✔
4854
                        if (nValue < nValue2)
155,441✔
4855
                        {
4856
                            if (nValue < nMin)
8,844✔
4857
                                nMin = nValue;
248✔
4858
                            if (nValue2 > nMax)
8,844✔
4859
                                nMax = nValue2;
236✔
4860
                        }
4861
                        else
4862
                        {
4863
                            if (nValue2 < nMin)
146,597✔
4864
                                nMin = nValue2;
290✔
4865
                            if (nValue > nMax)
146,597✔
4866
                                nMax = nValue;
839✔
4867
                        }
4868
                        if constexpr (COMPUTE_OTHER_STATS)
4869
                        {
4870
                            nSum32bit += nValue;
132,239✔
4871
                            nSumSquare32bit += nValue * nValue;
132,239✔
4872
                            nSum32bit += nValue2;
132,239✔
4873
                            nSumSquare32bit += nValue2 * nValue2;
132,239✔
4874
                        }
4875
                    }
4876
                    if constexpr (COMPUTE_OTHER_STATS)
4877
                    {
4878
                        nSum += nSum32bit;
1,582✔
4879
                        nSumSquare += nSumSquare32bit;
1,582✔
4880
                    }
4881
                }
4882
                if (iX < nXCheck)
4,368✔
4883
                {
4884
                    const GPtrDiff_t iOffset =
1,104✔
4885
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
1,104✔
4886
                    const GUInt32 nValue = pData[iOffset];
1,104✔
4887
                    if (nValue < nMin)
1,104✔
4888
                        nMin = nValue;
37✔
4889
                    if (nValue > nMax)
1,104✔
4890
                        nMax = nValue;
47✔
4891
                    if constexpr (COMPUTE_OTHER_STATS)
4892
                    {
4893
                        nSum += nValue;
312✔
4894
                        nSumSquare +=
312✔
4895
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
312✔
4896
                            nValue;
312✔
4897
                    }
4898
                }
4899
            }
4900
            if constexpr (COMPUTE_OTHER_STATS)
4901
            {
4902
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
881✔
4903
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
881✔
4904
            }
4905
        }
4906
    }
11,605✔
4907
};
4908

4909
template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
4910
{
4911
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
4912
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
4913
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
4914
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
4915
    {
4916
        ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
4917
            nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
4918
            nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
4919
    }
4920
};
4921

4922
#if (defined(__x86_64__) || defined(_M_X64)) &&                                \
4923
    (defined(__GNUC__) || defined(_MSC_VER))
4924

4925
#include "gdal_avx2_emulation.hpp"
4926

4927
#define ZERO256 GDALmm256_setzero_si256()
4928

4929
template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
4930
static void
4931
ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
18,897✔
4932
                              // assumed to be aligned on 256 bits
4933
                              const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
4934
                              GUIntBig &nSum, GUIntBig &nSumSquare,
4935
                              GUIntBig &nSampleCount, GUIntBig &nValidCount)
4936
{
4937
    // 32-byte alignment may not be enforced by linker, so do it at hand
4938
    GByte
4939
        aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
4940
    GByte *paby32ByteAligned =
18,897✔
4941
        aby32ByteUnaligned +
4942
        (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
18,897✔
4943
    GByte *pabyMin = paby32ByteAligned;
18,897✔
4944
    GByte *pabyMax = paby32ByteAligned + 32;
18,897✔
4945
    GUInt32 *panSum =
18,897✔
4946
        COMPUTE_OTHER_STATS
4947
            ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
4948
            : nullptr;
4949
    GUInt32 *panSumSquare =
18,897✔
4950
        COMPUTE_OTHER_STATS
4951
            ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
4952
            : nullptr;
4953

4954
    CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
18,897✔
4955

4956
    GPtrDiff_t i = 0;
18,897✔
4957
    // Make sure that sumSquare can fit on uint32
4958
    // * 8 since we can hold 8 sums per vector register
4959
    const int nMaxIterationsPerInnerLoop =
18,897✔
4960
        8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
4961
    GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
18,897✔
4962
    if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
18,897✔
4963
        nOuterLoops++;
18,897✔
4964

4965
    GDALm256i ymm_min =
4966
        GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
18,897✔
4967
    GDALm256i ymm_max = ymm_min;
18,897✔
4968
    [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
18,897✔
4969

4970
    for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
37,794✔
4971
    {
4972
        const auto iMax =
18,897✔
4973
            std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
18,897✔
4974

4975
        // holds 4 uint32 sums in [0], [2], [4] and [6]
4976
        [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
18,897✔
4977
        [[maybe_unused]] GDALm256i ymm_sumsquare =
4978
            ZERO256;  // holds 8 uint32 sums
18,897✔
4979
        for (; i + 31 < iMax; i += 32)
625,620✔
4980
        {
4981
            const GDALm256i ymm = GDALmm256_load_si256(
606,723✔
4982
                reinterpret_cast<const GDALm256i *>(pData + i));
606,723✔
4983
            if (COMPUTE_MIN)
4984
            {
4985
                ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
153,148✔
4986
            }
4987
            if (COMPUTE_MAX)
4988
            {
4989
                ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
515,841✔
4990
            }
4991

4992
            if constexpr (COMPUTE_OTHER_STATS)
4993
            {
4994
                // Extract even-8bit values
4995
                const GDALm256i ymm_even =
4996
                    GDALmm256_and_si256(ymm, ymm_mask_8bits);
493,355✔
4997
                // Compute square of those 16 values as 32 bit result
4998
                // and add adjacent pairs
4999
                const GDALm256i ymm_even_square =
5000
                    GDALmm256_madd_epi16(ymm_even, ymm_even);
493,355✔
5001
                // Add to the sumsquare accumulator
5002
                ymm_sumsquare =
5003
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
493,355✔
5004

5005
                // Extract odd-8bit values
5006
                const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
493,355✔
5007
                const GDALm256i ymm_odd_square =
5008
                    GDALmm256_madd_epi16(ymm_odd, ymm_odd);
493,355✔
5009
                ymm_sumsquare =
5010
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
493,355✔
5011

5012
                // Now compute the sums
5013
                ymm_sum = GDALmm256_add_epi32(ymm_sum,
493,355✔
5014
                                              GDALmm256_sad_epu8(ymm, ZERO256));
5015
            }
5016
        }
5017

5018
        if constexpr (COMPUTE_OTHER_STATS)
5019
        {
5020
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
10,584✔
5021
                                  ymm_sum);
5022
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
10,584✔
5023
                                  ymm_sumsquare);
5024

5025
            nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
10,584✔
5026
            nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
10,584✔
5027
                          panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
10,584✔
5028
                          panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
10,584✔
5029
                          panSumSquare[7];
5030
        }
5031
    }
5032

5033
    if constexpr (COMPUTE_MIN)
5034
    {
5035
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5,949✔
5036
    }
5037
    if constexpr (COMPUTE_MAX)
5038
    {
5039
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
14,901✔
5040
    }
5041
    if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5042
    {
5043
        for (int j = 0; j < 32; j++)
509,190✔
5044
        {
5045
            if constexpr (COMPUTE_MIN)
5046
            {
5047
                if (pabyMin[j] < nMin)
190,368✔
5048
                    nMin = pabyMin[j];
1,239✔
5049
            }
5050
            if constexpr (COMPUTE_MAX)
5051
            {
5052
                if (pabyMax[j] > nMax)
476,832✔
5053
                    nMax = pabyMax[j];
1,745✔
5054
            }
5055
        }
5056
    }
5057

5058
    for (; i < nBlockPixels; i++)
211,431✔
5059
    {
5060
        const GUInt32 nValue = pData[i];
192,534✔
5061
        if constexpr (COMPUTE_MIN)
5062
        {
5063
            if (nValue < nMin)
66,094✔
5064
                nMin = nValue;
1✔
5065
        }
5066
        if constexpr (COMPUTE_MAX)
5067
        {
5068
            if (nValue > nMax)
189,771✔
5069
                nMax = nValue;
1,167✔
5070
        }
5071
        if constexpr (COMPUTE_OTHER_STATS)
5072
        {
5073
            nSum += nValue;
77,179✔
5074
            nSumSquare +=
77,179✔
5075
                static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
77,179✔
5076
        }
5077
    }
5078

5079
    if constexpr (COMPUTE_OTHER_STATS)
5080
    {
5081
        nSampleCount += static_cast<GUIntBig>(nBlockPixels);
10,584✔
5082
        nValidCount += static_cast<GUIntBig>(nBlockPixels);
10,584✔
5083
    }
5084
}
18,897✔
5085

5086
// SSE2/AVX2 optimization for GByte case
5087
// In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5088
// penaly in using the emulation, because, given the mm256 intrinsics used here,
5089
// there are strictly equivalent to 2 parallel SSE2 streams.
5090
template <bool COMPUTE_OTHER_STATS>
5091
struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5092
{
5093
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
27,813✔
5094
                  // assumed to be aligned on 256 bits
5095
                  const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5096
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5097
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5098
                  GUIntBig &nValidCount)
5099
    {
5100
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
27,813✔
5101
        if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
27,813✔
5102
            nMin <= nMax)
9,352✔
5103
        {
5104
            // 32-byte alignment may not be enforced by linker, so do it at hand
5105
            GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5106
            GByte *paby32ByteAligned =
1,240✔
5107
                aby32ByteUnaligned +
5108
                (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
1,240✔
5109
            GByte *pabyMin = paby32ByteAligned;
1,240✔
5110
            GByte *pabyMax = paby32ByteAligned + 32;
1,240✔
5111
            GUInt32 *panSum =
1,240✔
5112
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5113
            GUInt32 *panSumSquare =
1,240✔
5114
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5115

5116
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
1,240✔
5117

5118
            GPtrDiff_t i = 0;
1,240✔
5119
            // Make sure that sumSquare can fit on uint32
5120
            // * 8 since we can hold 8 sums per vector register
5121
            const int nMaxIterationsPerInnerLoop =
1,240✔
5122
                8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5123
            auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
1,240✔
5124
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
1,240✔
5125
                nOuterLoops++;
1,240✔
5126

5127
            const GDALm256i ymm_nodata =
5128
                GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
1,240✔
5129
            // any non noData value in [min,max] would do.
5130
            const GDALm256i ymm_neutral =
5131
                GDALmm256_set1_epi8(static_cast<GByte>(nMin));
1,240✔
5132
            GDALm256i ymm_min = ymm_neutral;
1,240✔
5133
            GDALm256i ymm_max = ymm_neutral;
1,240✔
5134
            [[maybe_unused]] const auto ymm_mask_8bits =
5135
                GDALmm256_set1_epi16(0xFF);
1,240✔
5136

5137
            const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
1,240✔
5138
            const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
1,240✔
5139
            const bool bComputeMinMax =
1,240✔
5140
                nMin > nMinThreshold || nMax < nMaxThreshold;
1,240✔
5141

5142
            for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
2,480✔
5143
            {
5144
                const auto iMax =
1,240✔
5145
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
1,240✔
5146

5147
                // holds 4 uint32 sums in [0], [2], [4] and [6]
5148
                [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
1,240✔
5149
                // holds 8 uint32 sums
5150
                [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
1,240✔
5151
                // holds 4 uint32 sums in [0], [2], [4] and [6]
5152
                [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
1,240✔
5153
                const auto iInit = i;
1,240✔
5154
                for (; i + 31 < iMax; i += 32)
13,799✔
5155
                {
5156
                    const GDALm256i ymm = GDALmm256_load_si256(
12,559✔
5157
                        reinterpret_cast<const GDALm256i *>(pData + i));
12,559✔
5158

5159
                    // Check which values are nodata
5160
                    const GDALm256i ymm_eq_nodata =
5161
                        GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
12,559✔
5162
                    if constexpr (COMPUTE_OTHER_STATS)
5163
                    {
5164
                        // Count how many values are nodata (due to cmpeq
5165
                        // putting 255 when condition is met, this will actually
5166
                        // be 255 times the number of nodata value, spread in 4
5167
                        // 64 bits words). We can use add_epi32 as the counter
5168
                        // will not overflow uint32
5169
                        ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
4,514✔
5170
                            ymm_count_nodata_mul_255,
5171
                            GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5172
                    }
5173
                    // Replace all nodata values by zero for the purpose of sum
5174
                    // and sumquare.
5175
                    const GDALm256i ymm_nodata_by_zero =
5176
                        GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
12,559✔
5177
                    if (bComputeMinMax)
12,559✔
5178
                    {
5179
                        // Replace all nodata values by a neutral value for the
5180
                        // purpose of min and max.
5181
                        const GDALm256i ymm_nodata_by_neutral =
5182
                            GDALmm256_or_si256(
8,174✔
5183
                                GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5184
                                ymm_nodata_by_zero);
5185

5186
                        ymm_min =
5187
                            GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
8,174✔
5188
                        ymm_max =
5189
                            GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
8,174✔
5190
                    }
5191

5192
                    if constexpr (COMPUTE_OTHER_STATS)
5193
                    {
5194
                        // Extract even-8bit values
5195
                        const GDALm256i ymm_even = GDALmm256_and_si256(
4,514✔
5196
                            ymm_nodata_by_zero, ymm_mask_8bits);
5197
                        // Compute square of those 16 values as 32 bit result
5198
                        // and add adjacent pairs
5199
                        const GDALm256i ymm_even_square =
5200
                            GDALmm256_madd_epi16(ymm_even, ymm_even);
4,514✔
5201
                        // Add to the sumsquare accumulator
5202
                        ymm_sumsquare =
5203
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
4,514✔
5204

5205
                        // Extract odd-8bit values
5206
                        const GDALm256i ymm_odd =
5207
                            GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
4,514✔
5208
                        const GDALm256i ymm_odd_square =
5209
                            GDALmm256_madd_epi16(ymm_odd, ymm_odd);
4,514✔
5210
                        ymm_sumsquare =
5211
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
4,514✔
5212

5213
                        // Now compute the sums
5214
                        ymm_sum = GDALmm256_add_epi32(
4,514✔
5215
                            ymm_sum,
5216
                            GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
5217
                    }
5218
                }
5219

5220
                if constexpr (COMPUTE_OTHER_STATS)
5221
                {
5222
                    GUInt32 *panCoutNoDataMul255 = panSum;
33✔
5223
                    GDALmm256_store_si256(
33✔
5224
                        reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
5225
                        ymm_count_nodata_mul_255);
5226

5227
                    nSampleCount += (i - iInit);
33✔
5228

5229
                    nValidCount +=
33✔
5230
                        (i - iInit) -
33✔
5231
                        (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
33✔
5232
                         panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
33✔
5233
                            255;
5234

5235
                    GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
33✔
5236
                                          ymm_sum);
5237
                    GDALmm256_store_si256(
33✔
5238
                        reinterpret_cast<GDALm256i *>(panSumSquare),
5239
                        ymm_sumsquare);
5240
                    nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
33✔
5241
                    nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
33✔
5242
                                  panSumSquare[1] + panSumSquare[2] +
33✔
5243
                                  panSumSquare[3] + panSumSquare[4] +
33✔
5244
                                  panSumSquare[5] + panSumSquare[6] +
33✔
5245
                                  panSumSquare[7];
5246
                }
5247
            }
5248

5249
            if (bComputeMinMax)
1,240✔
5250
            {
5251
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
1,209✔
5252
                                      ymm_min);
5253
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
1,209✔
5254
                                      ymm_max);
5255
                for (int j = 0; j < 32; j++)
39,897✔
5256
                {
5257
                    if (pabyMin[j] < nMin)
38,688✔
5258
                        nMin = pabyMin[j];
32✔
5259
                    if (pabyMax[j] > nMax)
38,688✔
5260
                        nMax = pabyMax[j];
157✔
5261
                }
5262
            }
5263

5264
            if constexpr (COMPUTE_OTHER_STATS)
5265
            {
5266
                nSampleCount += nBlockPixels - i;
33✔
5267
            }
5268
            for (; i < nBlockPixels; i++)
29,810✔
5269
            {
5270
                const GUInt32 nValue = pData[i];
28,570✔
5271
                if (nValue == nNoDataValue)
28,570✔
5272
                    continue;
24,923✔
5273
                if (nValue < nMin)
3,647✔
5274
                    nMin = nValue;
1✔
5275
                if (nValue > nMax)
3,647✔
5276
                    nMax = nValue;
13✔
5277
                if constexpr (COMPUTE_OTHER_STATS)
5278
                {
5279
                    nValidCount++;
110✔
5280
                    nSum += nValue;
110✔
5281
                    nSumSquare +=
110✔
5282
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
110✔
5283
                        nValue;
110✔
5284
                }
5285
            }
1,240✔
5286
        }
5287
        else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
26,573✔
5288
        {
5289
            if (nMin > 0)
14,941✔
5290
            {
5291
                if (nMax < 255)
1,993✔
5292
                {
5293
                    ComputeStatisticsByteNoNodata<true, true,
5294
                                                  COMPUTE_OTHER_STATS>(
1,464✔
5295
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5296
                        nSampleCount, nValidCount);
5297
                }
5298
                else
5299
                {
5300
                    ComputeStatisticsByteNoNodata<true, false,
5301
                                                  COMPUTE_OTHER_STATS>(
529✔
5302
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5303
                        nSampleCount, nValidCount);
5304
                }
5305
            }
5306
            else
5307
            {
5308
                if (nMax < 255)
12,948✔
5309
                {
5310
                    ComputeStatisticsByteNoNodata<false, true,
5311
                                                  COMPUTE_OTHER_STATS>(
9,481✔
5312
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5313
                        nSampleCount, nValidCount);
5314
                }
5315
                else
5316
                {
5317
                    ComputeStatisticsByteNoNodata<false, false,
5318
                                                  COMPUTE_OTHER_STATS>(
3,467✔
5319
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
5320
                        nSampleCount, nValidCount);
5321
                }
5322
            }
5323
        }
5324
        else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
10,407✔
5325
                 (nBlockXSize % 32) == 0)
27✔
5326
        {
5327
            for (int iY = 0; iY < nYCheck; iY++)
3,983✔
5328
            {
5329
                ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
3,956✔
5330
                    nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
3,956✔
5331
                    nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5332
            }
27✔
5333
        }
5334
        else
5335
        {
5336
            ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
11,605✔
5337
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5338
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5339
        }
5340
    }
27,813✔
5341
};
5342

5343
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
5344
static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
286✔
5345
                             GUIntBig i)
5346
{
5347
    nSumSquare += 32768 * (2 * nSumThis - i * 32768);
286✔
5348
}
286✔
5349

5350
// AVX2/SSE2 optimization for GUInt16 case
5351
template <bool COMPUTE_OTHER_STATS>
5352
struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
5353
{
5354
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
1,227✔
5355
                  // assumed to be aligned on 128 bits
5356
                  const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
5357
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5358
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5359
                  GUIntBig &nValidCount)
5360
    {
5361
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
1,227✔
5362
        if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
1,227✔
5363
        {
5364
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
1,048✔
5365

5366
            GPtrDiff_t i = 0;
1,048✔
5367
            // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
5368
            // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
5369
            // Furthermore the shift is also needed to use madd_epi16
5370
            const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
1,048✔
5371
            GDALm256i ymm_min = GDALmm256_load_si256(
1,048✔
5372
                reinterpret_cast<const GDALm256i *>(pData + i));
1,048✔
5373
            ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
1,048✔
5374
            GDALm256i ymm_max = ymm_min;
1,048✔
5375
            [[maybe_unused]] GDALm256i ymm_sumsquare =
5376
                ZERO256;  // holds 4 uint64 sums
1,048✔
5377

5378
            // Make sure that sum can fit on uint32
5379
            // * 8 since we can hold 8 sums per vector register
5380
            const int nMaxIterationsPerInnerLoop =
1,048✔
5381
                8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
5382
            GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
1,048✔
5383
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
1,048✔
5384
                nOuterLoops++;
1,048✔
5385

5386
            const bool bComputeMinMax = nMin > 0 || nMax < 65535;
1,048✔
5387
            [[maybe_unused]] const auto ymm_mask_16bits =
5388
                GDALmm256_set1_epi32(0xFFFF);
1,048✔
5389
            [[maybe_unused]] const auto ymm_mask_32bits =
5390
                GDALmm256_set1_epi64x(0xFFFFFFFF);
1,048✔
5391

5392
            GUIntBig nSumThis = 0;
1,048✔
5393
            for (int k = 0; k < nOuterLoops; k++)
2,120✔
5394
            {
5395
                const auto iMax =
1,072✔
5396
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
1,072✔
5397

5398
                [[maybe_unused]] GDALm256i ymm_sum =
5399
                    ZERO256;  // holds 8 uint32 sums
1,072✔
5400
                for (; i + 15 < iMax; i += 16)
957,276✔
5401
                {
5402
                    const GDALm256i ymm = GDALmm256_load_si256(
956,204✔
5403
                        reinterpret_cast<const GDALm256i *>(pData + i));
956,204✔
5404
                    const GDALm256i ymm_shifted =
5405
                        GDALmm256_add_epi16(ymm, ymm_m32768);
956,204✔
5406
                    if (bComputeMinMax)
956,204✔
5407
                    {
5408
                        ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
947,185✔
5409
                        ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
947,185✔
5410
                    }
5411

5412
                    if constexpr (COMPUTE_OTHER_STATS)
5413
                    {
5414
                        // Note: the int32 range can overflow for (0-32768)^2 +
5415
                        // (0-32768)^2 = 0x80000000, but as we know the result
5416
                        // is positive, this is OK as we interpret is a uint32.
5417
                        const GDALm256i ymm_square =
5418
                            GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
97,378✔
5419
                        ymm_sumsquare = GDALmm256_add_epi64(
97,378✔
5420
                            ymm_sumsquare,
5421
                            GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
5422
                        ymm_sumsquare = GDALmm256_add_epi64(
97,378✔
5423
                            ymm_sumsquare,
5424
                            GDALmm256_srli_epi64(ymm_square, 32));
5425

5426
                        // Now compute the sums
5427
                        ymm_sum = GDALmm256_add_epi32(
97,378✔
5428
                            ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
5429
                        ymm_sum = GDALmm256_add_epi32(
97,378✔
5430
                            ymm_sum, GDALmm256_srli_epi32(ymm, 16));
5431
                    }
5432
                }
5433

5434
                if constexpr (COMPUTE_OTHER_STATS)
5435
                {
5436
                    GUInt32 anSum[8];
5437
                    GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
286✔
5438
                                           ymm_sum);
5439
                    nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
286✔
5440
                                anSum[2] + anSum[3] + anSum[4] + anSum[5] +
286✔
5441
                                anSum[6] + anSum[7];
286✔
5442
                }
5443
            }
5444

5445
            if (bComputeMinMax)
1,048✔
5446
            {
5447
                GUInt16 anMin[16];
5448
                GUInt16 anMax[16];
5449

5450
                // Unshift the result
5451
                ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
1,007✔
5452
                ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
1,007✔
5453
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
1,007✔
5454
                                       ymm_min);
5455
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
1,007✔
5456
                                       ymm_max);
5457
                for (int j = 0; j < 16; j++)
17,119✔
5458
                {
5459
                    if (anMin[j] < nMin)
16,112✔
5460
                        nMin = anMin[j];
339✔
5461
                    if (anMax[j] > nMax)
16,112✔
5462
                        nMax = anMax[j];
479✔
5463
                }
5464
            }
5465

5466
            if constexpr (COMPUTE_OTHER_STATS)
5467
            {
5468
                GUIntBig anSumSquare[4];
5469
                GDALmm256_storeu_si256(
286✔
5470
                    reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
5471
                nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
286✔
5472
                              anSumSquare[3];
5473

5474
                // Unshift the sum of squares
5475
                UnshiftSumSquare(nSumSquare, nSumThis,
286✔
5476
                                 static_cast<GUIntBig>(i));
5477

5478
                nSum += nSumThis;
286✔
5479

5480
                for (; i < nBlockPixels; i++)
608✔
5481
                {
5482
                    const GUInt32 nValue = pData[i];
322✔
5483
                    if (nValue < nMin)
322✔
5484
                        nMin = nValue;
1✔
5485
                    if (nValue > nMax)
322✔
5486
                        nMax = nValue;
1✔
5487
                    nSum += nValue;
322✔
5488
                    nSumSquare +=
322✔
5489
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
322✔
5490
                        nValue;
322✔
5491
                }
5492

5493
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
286✔
5494
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
286✔
5495
            }
1,048✔
5496
        }
5497
        else
5498
        {
5499
            ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
179✔
5500
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5501
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5502
        }
5503
    }
1,227✔
5504
};
5505

5506
#endif
5507
// (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
5508
// defined(_MSC_VER))
5509

5510
#endif  // CPL_HAS_GINT64
5511

5512
/************************************************************************/
5513
/*                          GetPixelValue()                             */
5514
/************************************************************************/
5515

5516
static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
19,828,500✔
5517
                                   const void *pData, GPtrDiff_t iOffset,
5518
                                   bool bGotNoDataValue, double dfNoDataValue,
5519
                                   bool bGotFloatNoDataValue,
5520
                                   float fNoDataValue, bool &bValid)
5521
{
5522
    bValid = true;
19,828,500✔
5523
    double dfValue = 0;
19,828,500✔
5524
    switch (eDataType)
19,828,500✔
5525
    {
5526
        case GDT_Byte:
1,413,670✔
5527
        {
5528
            if (bSignedByte)
1,413,670✔
5529
                dfValue = static_cast<const signed char *>(pData)[iOffset];
192✔
5530
            else
5531
                dfValue = static_cast<const GByte *>(pData)[iOffset];
1,413,480✔
5532
            break;
1,413,670✔
5533
        }
5534
        case GDT_Int8:
10,405✔
5535
            dfValue = static_cast<const GInt8 *>(pData)[iOffset];
10,405✔
5536
            break;
10,405✔
5537
        case GDT_UInt16:
4,000✔
5538
            dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
4,000✔
5539
            break;
4,000✔
5540
        case GDT_Int16:
60,192✔
5541
            dfValue = static_cast<const GInt16 *>(pData)[iOffset];
60,192✔
5542
            break;
60,192✔
5543
        case GDT_UInt32:
27,596✔
5544
            dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
27,596✔
5545
            break;
27,596✔
5546
        case GDT_Int32:
460,158✔
5547
            dfValue = static_cast<const GInt32 *>(pData)[iOffset];
460,158✔
5548
            break;
460,158✔
5549
        case GDT_UInt64:
2,598✔
5550
            dfValue = static_cast<double>(
2,598✔
5551
                static_cast<const std::uint64_t *>(pData)[iOffset]);
2,598✔
5552
            break;
2,598✔
5553
        case GDT_Int64:
2,598✔
5554
            dfValue = static_cast<double>(
2,598✔
5555
                static_cast<const std::int64_t *>(pData)[iOffset]);
2,598✔
5556
            break;
2,598✔
5557
        case GDT_Float32:
17,482,900✔
5558
        {
5559
            const float fValue = static_cast<const float *>(pData)[iOffset];
17,482,900✔
5560
            if (CPLIsNan(fValue) ||
30,693,000✔
5561
                (bGotFloatNoDataValue && ARE_REAL_EQUAL(fValue, fNoDataValue)))
13,210,000✔
5562
            {
5563
                bValid = false;
119,858✔
5564
                return 0.0;
119,858✔
5565
            }
5566
            dfValue = fValue;
17,363,100✔
5567
            return dfValue;
17,363,100✔
5568
        }
5569
        case GDT_Float64:
347,293✔
5570
            dfValue = static_cast<const double *>(pData)[iOffset];
347,293✔
5571
            if (CPLIsNan(dfValue))
347,293✔
5572
            {
5573
                bValid = false;
50✔
5574
                return 0.0;
50✔
5575
            }
5576
            break;
347,243✔
5577
        case GDT_CInt16:
2,692✔
5578
            dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
2,692✔
5579
            break;
2,692✔
5580
        case GDT_CInt32:
2,692✔
5581
            dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
2,692✔
5582
            break;
2,692✔
5583
        case GDT_CFloat32:
5,812✔
5584
            dfValue = static_cast<const float *>(pData)[iOffset * 2];
5,812✔
5585
            if (CPLIsNan(dfValue))
5,812✔
5586
            {
5587
                bValid = false;
×
5588
                return 0.0;
×
5589
            }
5590
            break;
5,812✔
5591
        case GDT_CFloat64:
5,892✔
5592
            dfValue = static_cast<const double *>(pData)[iOffset * 2];
5,892✔
5593
            if (CPLIsNan(dfValue))
5,892✔
5594
            {
5595
                bValid = false;
×
5596
                return 0.0;
×
5597
            }
5598
            break;
5,892✔
5599
        case GDT_Unknown:
×
5600
        case GDT_TypeCount:
5601
            CPLAssert(false);
×
5602
            break;
5603
    }
5604

5605
    if (bGotNoDataValue && ARE_REAL_EQUAL(dfValue, dfNoDataValue))
2,345,550✔
5606
    {
5607
        bValid = false;
28,624✔
5608
        return 0.0;
28,624✔
5609
    }
5610
    return dfValue;
2,316,920✔
5611
}
5612

5613
/************************************************************************/
5614
/*                         SetValidPercent()                            */
5615
/************************************************************************/
5616

5617
//! @cond Doxygen_Suppress
5618
/**
5619
 * \brief Set percentage of valid (not nodata) pixels.
5620
 *
5621
 * Stores the percentage of valid pixels in the metadata item
5622
 * STATISTICS_VALID_PERCENT
5623
 *
5624
 * @param nSampleCount Number of sampled pixels.
5625
 *
5626
 * @param nValidCount Number of valid pixels.
5627
 */
5628

5629
void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
455✔
5630
                                     GUIntBig nValidCount)
5631
{
5632
    if (nValidCount == 0)
455✔
5633
    {
5634
        SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
12✔
5635
    }
5636
    else if (nValidCount == nSampleCount)
443✔
5637
    {
5638
        SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
402✔
5639
    }
5640
    else /* nValidCount < nSampleCount */
5641
    {
5642
        char szValue[128] = {0};
41✔
5643

5644
        /* percentage is only an indicator: limit precision */
5645
        CPLsnprintf(szValue, sizeof(szValue), "%.4g",
41✔
5646
                    100. * static_cast<double>(nValidCount) / nSampleCount);
41✔
5647

5648
        if (EQUAL(szValue, "100"))
41✔
5649
        {
5650
            /* don't set 100 percent valid
5651
             * because some of the sampled pixels were nodata */
5652
            SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
×
5653
        }
5654
        else
5655
        {
5656
            SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
41✔
5657
        }
5658
    }
5659
}
455✔
5660

5661
//! @endcond
5662

5663
/************************************************************************/
5664
/*                         ComputeStatistics()                          */
5665
/************************************************************************/
5666

5667
/**
5668
 * \brief Compute image statistics.
5669
 *
5670
 * Returns the minimum, maximum, mean and standard deviation of all
5671
 * pixel values in this band.  If approximate statistics are sufficient,
5672
 * the bApproxOK flag can be set to true in which case overviews, or a
5673
 * subset of image tiles may be used in computing the statistics.
5674
 *
5675
 * Once computed, the statistics will generally be "set" back on the
5676
 * raster band using SetStatistics().
5677
 *
5678
 * Cached statistics can be cleared with GDALDataset::ClearStatistics().
5679
 *
5680
 * This method is the same as the C function GDALComputeRasterStatistics().
5681
 *
5682
 * @param bApproxOK If TRUE statistics may be computed based on overviews
5683
 * or a subset of all tiles.
5684
 *
5685
 * @param pdfMin Location into which to load image minimum (may be NULL).
5686
 *
5687
 * @param pdfMax Location into which to load image maximum (may be NULL).-
5688
 *
5689
 * @param pdfMean Location into which to load image mean (may be NULL).
5690
 *
5691
 * @param pdfStdDev Location into which to load image standard deviation
5692
 * (may be NULL).
5693
 *
5694
 * @param pfnProgress a function to call to report progress, or NULL.
5695
 *
5696
 * @param pProgressData application data to pass to the progress function.
5697
 *
5698
 * @return CE_None on success, or CE_Failure if an error occurs or processing
5699
 * is terminated by the user.
5700
 */
5701

5702
CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
440✔
5703
                                         double *pdfMax, double *pdfMean,
5704
                                         double *pdfStdDev,
5705
                                         GDALProgressFunc pfnProgress,
5706
                                         void *pProgressData)
5707

5708
{
5709
    if (pfnProgress == nullptr)
440✔
5710
        pfnProgress = GDALDummyProgress;
151✔
5711

5712
    /* -------------------------------------------------------------------- */
5713
    /*      If we have overview bands, use them for statistics.             */
5714
    /* -------------------------------------------------------------------- */
5715
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
440✔
5716
    {
5717
        GDALRasterBand *poBand =
5718
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
3✔
5719

5720
        if (poBand != this)
3✔
5721
        {
5722
            CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6✔
5723
                                                    pdfMean, pdfStdDev,
5724
                                                    pfnProgress, pProgressData);
3✔
5725
            if (eErr == CE_None)
3✔
5726
            {
5727
                if (pdfMin && pdfMax && pdfMean && pdfStdDev)
3✔
5728
                {
5729
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
3✔
5730
                    SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
3✔
5731
                }
5732

5733
                /* transfer metadata from overview band to this */
5734
                const char *pszPercentValid =
5735
                    poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
3✔
5736

5737
                if (pszPercentValid != nullptr)
3✔
5738
                {
5739
                    SetMetadataItem("STATISTICS_VALID_PERCENT",
3✔
5740
                                    pszPercentValid);
3✔
5741
                }
5742
            }
5743
            return eErr;
3✔
5744
        }
5745
    }
5746

5747
    if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
437✔
5748
    {
5749
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
×
5750
        return CE_Failure;
×
5751
    }
5752

5753
    /* -------------------------------------------------------------------- */
5754
    /*      Read actual data and compute statistics.                        */
5755
    /* -------------------------------------------------------------------- */
5756
    // Using Welford algorithm:
5757
    // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
5758
    // to compute standard deviation in a more numerically robust way than
5759
    // the difference of the sum of square values with the square of the sum.
5760
    // dfMean and dfM2 are updated at each sample.
5761
    // dfM2 is the sum of square of differences to the current mean.
5762
    double dfMin = std::numeric_limits<double>::max();
437✔
5763
    double dfMax = -std::numeric_limits<double>::max();
437✔
5764
    double dfMean = 0.0;
437✔
5765
    double dfM2 = 0.0;
437✔
5766

5767
    GDALRasterIOExtraArg sExtraArg;
5768
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
437✔
5769

5770
    int bGotNoDataValue = FALSE;
437✔
5771
    const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
437✔
5772
    bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
437✔
5773
    bool bGotFloatNoDataValue = false;
437✔
5774
    float fNoDataValue = 0.0f;
437✔
5775
    ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
437✔
5776
                            fNoDataValue, bGotFloatNoDataValue);
5777

5778
    GDALRasterBand *poMaskBand = nullptr;
437✔
5779
    if (!bGotNoDataValue)
437✔
5780
    {
5781
        const int l_nMaskFlags = GetMaskFlags();
412✔
5782
        if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
428✔
5783
            GetColorInterpretation() != GCI_AlphaBand)
16✔
5784
        {
5785
            poMaskBand = GetMaskBand();
16✔
5786
        }
5787
    }
5788

5789
    bool bSignedByte = false;
437✔
5790
    if (eDataType == GDT_Byte)
437✔
5791
    {
5792
        EnablePixelTypeSignedByteWarning(false);
191✔
5793
        const char *pszPixelType =
5794
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
191✔
5795
        EnablePixelTypeSignedByteWarning(true);
191✔
5796
        bSignedByte =
191✔
5797
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
191✔
5798
    }
5799

5800
    GUIntBig nSampleCount = 0;
437✔
5801
    GUIntBig nValidCount = 0;
437✔
5802

5803
    if (bApproxOK && HasArbitraryOverviews())
437✔
5804
    {
5805
        /* --------------------------------------------------------------------
5806
         */
5807
        /*      Figure out how much the image should be reduced to get an */
5808
        /*      approximate value. */
5809
        /* --------------------------------------------------------------------
5810
         */
5811
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
×
5812
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
×
5813

5814
        int nXReduced = nRasterXSize;
×
5815
        int nYReduced = nRasterYSize;
×
5816
        if (dfReduction > 1.0)
×
5817
        {
5818
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
×
5819
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
×
5820

5821
            // Catch the case of huge resizing ratios here
5822
            if (nXReduced == 0)
×
5823
                nXReduced = 1;
×
5824
            if (nYReduced == 0)
×
5825
                nYReduced = 1;
×
5826
        }
5827

5828
        void *pData = CPLMalloc(cpl::fits_on<int>(
×
5829
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
×
5830

5831
        const CPLErr eErr =
5832
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
×
5833
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
×
5834
        if (eErr != CE_None)
×
5835
        {
5836
            CPLFree(pData);
×
5837
            return eErr;
×
5838
        }
5839

5840
        GByte *pabyMaskData = nullptr;
×
5841
        if (poMaskBand)
×
5842
        {
5843
            pabyMaskData =
5844
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
×
5845
            if (!pabyMaskData)
×
5846
            {
5847
                CPLFree(pData);
×
5848
                return CE_Failure;
×
5849
            }
5850

5851
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
×
5852
                                     pabyMaskData, nXReduced, nYReduced,
5853
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
×
5854
            {
5855
                CPLFree(pData);
×
5856
                CPLFree(pabyMaskData);
×
5857
                return CE_Failure;
×
5858
            }
5859
        }
5860

5861
        /* this isn't the fastest way to do this, but is easier for now */
5862
        for (int iY = 0; iY < nYReduced; iY++)
×
5863
        {
5864
            for (int iX = 0; iX < nXReduced; iX++)
×
5865
            {
5866
                const int iOffset = iX + iY * nXReduced;
×
5867
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
×
5868
                    continue;
×
5869

5870
                bool bValid = true;
×
5871
                double dfValue =
5872
                    GetPixelValue(eDataType, bSignedByte, pData, iOffset,
×
5873
                                  CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
×
5874
                                  bGotFloatNoDataValue, fNoDataValue, bValid);
×
5875
                if (!bValid)
×
5876
                    continue;
×
5877

5878
                dfMin = std::min(dfMin, dfValue);
×
5879
                dfMax = std::max(dfMax, dfValue);
×
5880

5881
                nValidCount++;
×
5882
                const double dfDelta = dfValue - dfMean;
×
5883
                dfMean += dfDelta / nValidCount;
×
5884
                dfM2 += dfDelta * (dfValue - dfMean);
×
5885
            }
5886
        }
5887

5888
        nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
×
5889

5890
        CPLFree(pData);
×
5891
        CPLFree(pabyMaskData);
×
5892
    }
5893

5894
    else  // No arbitrary overviews.
5895
    {
5896
        if (!InitBlockInfo())
437✔
5897
            return CE_Failure;
×
5898

5899
        /* --------------------------------------------------------------------
5900
         */
5901
        /*      Figure out the ratio of blocks we will read to get an */
5902
        /*      approximate value. */
5903
        /* --------------------------------------------------------------------
5904
         */
5905
        int nSampleRate = 1;
437✔
5906
        if (bApproxOK)
437✔
5907
        {
5908
            nSampleRate = static_cast<int>(std::max(
40✔
5909
                1.0,
80✔
5910
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
40✔
5911
            // We want to avoid probing only the first column of blocks for
5912
            // a square shaped raster, because it is not unlikely that it may
5913
            // be padding only (#6378)
5914
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
40✔
5915
                nSampleRate += 1;
2✔
5916
        }
5917
        if (nSampleRate == 1)
437✔
5918
            bApproxOK = false;
404✔
5919

5920
#ifdef CPL_HAS_GINT64
5921
        // Particular case for GDT_Byte that only use integral types for all
5922
        // intermediate computations. Only possible if the number of pixels
5923
        // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
5924
        // can fit on a uint64. Should be 99.99999% of cases.
5925
        // For GUInt16, this limits to raster of 4 giga pixels
5926
        if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
437✔
5927
             static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
176✔
5928
                     nSampleRate <
176✔
5929
                 GUINTBIG_MAX / (255U * 255U) /
176✔
5930
                     (static_cast<GUInt64>(nBlockXSize) *
176✔
5931
                      static_cast<GUInt64>(nBlockYSize))) ||
176✔
5932
            (eDataType == GDT_UInt16 &&
261✔
5933
             static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
25✔
5934
                     nSampleRate <
25✔
5935
                 GUINTBIG_MAX / (65535U * 65535U) /
25✔
5936
                     (static_cast<GUInt64>(nBlockXSize) *
25✔
5937
                      static_cast<GUInt64>(nBlockYSize))))
25✔
5938
        {
5939
            const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
201✔
5940
            GUInt32 nMin = nMaxValueType;
201✔
5941
            GUInt32 nMax = 0;
201✔
5942
            GUIntBig nSum = 0;
201✔
5943
            GUIntBig nSumSquare = 0;
201✔
5944
            // If no valid nodata, map to invalid value (256 for Byte)
5945
            const GUInt32 nNoDataValue =
201✔
5946
                (bGotNoDataValue && dfNoDataValue >= 0 &&
21✔
5947
                 dfNoDataValue <= nMaxValueType &&
21✔
5948
                 fabs(dfNoDataValue -
21✔
5949
                      static_cast<GUInt32>(dfNoDataValue + 1e-10)) < 1e-10)
21✔
5950
                    ? static_cast<GUInt32>(dfNoDataValue + 1e-10)
222✔
5951
                    : nMaxValueType + 1;
5952

5953
            for (int iSampleBlock = 0;
201✔
5954
                 iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
12,380✔
5955
                 iSampleBlock += nSampleRate)
12,179✔
5956
            {
5957
                const int iYBlock = iSampleBlock / nBlocksPerRow;
12,179✔
5958
                const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
12,179✔
5959

5960
                GDALRasterBlock *const poBlock =
5961
                    GetLockedBlockRef(iXBlock, iYBlock);
12,179✔
5962
                if (poBlock == nullptr)
12,179✔
5963
                    return CE_Failure;
×
5964

5965
                void *const pData = poBlock->GetDataRef();
12,179✔
5966

5967
                int nXCheck = 0, nYCheck = 0;
12,179✔
5968
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
12,179✔
5969

5970
                if (eDataType == GDT_Byte)
12,179✔
5971
                {
5972
                    ComputeStatisticsInternal<
5973
                        GByte, /* COMPUTE_OTHER_STATS = */ true>::
5974
                        f(nXCheck, nBlockXSize, nYCheck,
11,842✔
5975
                          static_cast<const GByte *>(pData),
5976
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
5977
                          nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5978
                }
5979
                else
5980
                {
5981
                    ComputeStatisticsInternal<
5982
                        GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
5983
                        f(nXCheck, nBlockXSize, nYCheck,
337✔
5984
                          static_cast<const GUInt16 *>(pData),
5985
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
5986
                          nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5987
                }
5988

5989
                poBlock->DropLock();
12,179✔
5990

5991
                if (!pfnProgress(iSampleBlock /
12,179✔
5992
                                     static_cast<double>(nBlocksPerRow *
12,179✔
5993
                                                         nBlocksPerColumn),
12,179✔
5994
                                 "Compute Statistics", pProgressData))
5995
                {
5996
                    ReportError(CE_Failure, CPLE_UserInterrupt,
×
5997
                                "User terminated");
5998
                    return CE_Failure;
×
5999
                }
6000
            }
6001

6002
            if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
201✔
6003
            {
6004
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
×
6005
                return CE_Failure;
×
6006
            }
6007

6008
            /* --------------------------------------------------------------------
6009
             */
6010
            /*      Save computed information. */
6011
            /* --------------------------------------------------------------------
6012
             */
6013
            if (nValidCount)
201✔
6014
                dfMean = static_cast<double>(nSum) / nValidCount;
192✔
6015

6016
            // To avoid potential precision issues when doing the difference,
6017
            // we need to do that computation on 128 bit rather than casting
6018
            // to double
6019
            const GDALUInt128 nTmpForStdDev(
6020
                GDALUInt128::Mul(nSumSquare, nValidCount) -
201✔
6021
                GDALUInt128::Mul(nSum, nSum));
402✔
6022
            const double dfStdDev =
6023
                nValidCount > 0
201✔
6024
                    ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
201✔
6025
                    : 0.0;
201✔
6026

6027
            if (nValidCount > 0)
201✔
6028
            {
6029
                if (bApproxOK)
192✔
6030
                {
6031
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
23✔
6032
                }
6033
                else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
169✔
6034
                {
6035
                    SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
3✔
6036
                }
6037
                SetStatistics(nMin, nMax, dfMean, dfStdDev);
192✔
6038
            }
6039

6040
            SetValidPercent(nSampleCount, nValidCount);
201✔
6041

6042
            /* --------------------------------------------------------------------
6043
             */
6044
            /*      Record results. */
6045
            /* --------------------------------------------------------------------
6046
             */
6047
            if (pdfMin != nullptr)
201✔
6048
                *pdfMin = nValidCount ? nMin : 0;
198✔
6049
            if (pdfMax != nullptr)
201✔
6050
                *pdfMax = nValidCount ? nMax : 0;
198✔
6051

6052
            if (pdfMean != nullptr)
201✔
6053
                *pdfMean = dfMean;
194✔
6054

6055
            if (pdfStdDev != nullptr)
201✔
6056
                *pdfStdDev = dfStdDev;
194✔
6057

6058
            if (nValidCount > 0)
201✔
6059
                return CE_None;
192✔
6060

6061
            ReportError(CE_Failure, CPLE_AppDefined,
9✔
6062
                        "Failed to compute statistics, no valid pixels found "
6063
                        "in sampling.");
6064
            return CE_Failure;
9✔
6065
        }
6066
#endif
6067

6068
        GByte *pabyMaskData = nullptr;
236✔
6069
        if (poMaskBand)
236✔
6070
        {
6071
            pabyMaskData = static_cast<GByte *>(
6072
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
16✔
6073
            if (!pabyMaskData)
16✔
6074
            {
6075
                return CE_Failure;
×
6076
            }
6077
        }
6078

6079
        for (int iSampleBlock = 0;
236✔
6080
             iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
5,483✔
6081
             iSampleBlock += nSampleRate)
5,247✔
6082
        {
6083
            const int iYBlock = iSampleBlock / nBlocksPerRow;
5,247✔
6084
            const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
5,247✔
6085

6086
            GDALRasterBlock *const poBlock =
6087
                GetLockedBlockRef(iXBlock, iYBlock);
5,247✔
6088
            if (poBlock == nullptr)
5,247✔
6089
            {
6090
                CPLFree(pabyMaskData);
×
6091
                return CE_Failure;
×
6092
            }
6093

6094
            void *const pData = poBlock->GetDataRef();
5,247✔
6095

6096
            int nXCheck = 0, nYCheck = 0;
5,247✔
6097
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
5,247✔
6098

6099
            if (poMaskBand &&
5,348✔
6100
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
101✔
6101
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
101✔
6102
                                     pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6103
                                     0, nBlockXSize, nullptr) != CE_None)
101✔
6104
            {
6105
                CPLFree(pabyMaskData);
×
6106
                poBlock->DropLock();
×
6107
                return CE_Failure;
×
6108
            }
6109

6110
            // This isn't the fastest way to do this, but is easier for now.
6111
            for (int iY = 0; iY < nYCheck; iY++)
10,678✔
6112
            {
6113
                for (int iX = 0; iX < nXCheck; iX++)
4,342,130✔
6114
                {
6115
                    const GPtrDiff_t iOffset =
4,336,700✔
6116
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4,336,700✔
6117
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
4,336,700✔
6118
                        continue;
109,939✔
6119

6120
                    bool bValid = true;
4,326,820✔
6121
                    double dfValue = GetPixelValue(
4,326,820✔
6122
                        eDataType, bSignedByte, pData, iOffset,
6123
                        CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
4,326,820✔
6124
                        bGotFloatNoDataValue, fNoDataValue, bValid);
4,326,820✔
6125

6126
                    if (!bValid)
4,326,820✔
6127
                        continue;
100,068✔
6128

6129
                    dfMin = std::min(dfMin, dfValue);
4,226,760✔
6130
                    dfMax = std::max(dfMax, dfValue);
4,226,760✔
6131

6132
                    nValidCount++;
4,226,760✔
6133
                    const double dfDelta = dfValue - dfMean;
4,226,760✔
6134
                    dfMean += dfDelta / nValidCount;
4,226,760✔
6135
                    dfM2 += dfDelta * (dfValue - dfMean);
4,226,760✔
6136
                }
6137
            }
6138

6139
            nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5,247✔
6140

6141
            poBlock->DropLock();
5,247✔
6142

6143
            if (!pfnProgress(
5,247✔
6144
                    iSampleBlock /
6145
                        static_cast<double>(nBlocksPerRow * nBlocksPerColumn),
5,247✔
6146
                    "Compute Statistics", pProgressData))
6147
            {
6148
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
×
6149
                CPLFree(pabyMaskData);
×
6150
                return CE_Failure;
×
6151
            }
6152
        }
6153

6154
        CPLFree(pabyMaskData);
236✔
6155
    }
6156

6157
    if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
236✔
6158
    {
6159
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
×
6160
        return CE_Failure;
×
6161
    }
6162

6163
    /* -------------------------------------------------------------------- */
6164
    /*      Save computed information.                                      */
6165
    /* -------------------------------------------------------------------- */
6166
    const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
236✔
6167

6168
    if (nValidCount > 0)
236✔
6169
    {
6170
        if (bApproxOK)
235✔
6171
        {
6172
            SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
8✔
6173
        }
6174
        else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
227✔
6175
        {
6176
            SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
2✔
6177
        }
6178
        SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
235✔
6179
    }
6180
    else
6181
    {
6182
        dfMin = 0.0;
1✔
6183
        dfMax = 0.0;
1✔
6184
    }
6185

6186
    SetValidPercent(nSampleCount, nValidCount);
236✔
6187

6188
    /* -------------------------------------------------------------------- */
6189
    /*      Record results.                                                 */
6190
    /* -------------------------------------------------------------------- */
6191
    if (pdfMin != nullptr)
236✔
6192
        *pdfMin = dfMin;
233✔
6193
    if (pdfMax != nullptr)
236✔
6194
        *pdfMax = dfMax;
233✔
6195

6196
    if (pdfMean != nullptr)
236✔
6197
        *pdfMean = dfMean;
231✔
6198

6199
    if (pdfStdDev != nullptr)
236✔
6200
        *pdfStdDev = dfStdDev;
231✔
6201

6202
    if (nValidCount > 0)
236✔
6203
        return CE_None;
235✔
6204

6205
    ReportError(
1✔
6206
        CE_Failure, CPLE_AppDefined,
6207
        "Failed to compute statistics, no valid pixels found in sampling.");
6208
    return CE_Failure;
1✔
6209
}
6210

6211
/************************************************************************/
6212
/*                    GDALComputeRasterStatistics()                     */
6213
/************************************************************************/
6214

6215
/**
6216
 * \brief Compute image statistics.
6217
 *
6218
 * @see GDALRasterBand::ComputeStatistics()
6219
 */
6220

6221
CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
137✔
6222
                                               int bApproxOK, double *pdfMin,
6223
                                               double *pdfMax, double *pdfMean,
6224
                                               double *pdfStdDev,
6225
                                               GDALProgressFunc pfnProgress,
6226
                                               void *pProgressData)
6227

6228
{
6229
    VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
137✔
6230

6231
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
137✔
6232

6233
    return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
137✔
6234
                                     pdfStdDev, pfnProgress, pProgressData);
137✔
6235
}
6236

6237
/************************************************************************/
6238
/*                           SetStatistics()                            */
6239
/************************************************************************/
6240

6241
/**
6242
 * \brief Set statistics on band.
6243
 *
6244
 * This method can be used to store min/max/mean/standard deviation
6245
 * statistics on a raster band.
6246
 *
6247
 * The default implementation stores them as metadata, and will only work
6248
 * on formats that can save arbitrary metadata.  This method cannot detect
6249
 * whether metadata will be properly saved and so may return CE_None even
6250
 * if the statistics will never be saved.
6251
 *
6252
 * This method is the same as the C function GDALSetRasterStatistics().
6253
 *
6254
 * @param dfMin minimum pixel value.
6255
 *
6256
 * @param dfMax maximum pixel value.
6257
 *
6258
 * @param dfMean mean (average) of all pixel values.
6259
 *
6260
 * @param dfStdDev Standard deviation of all pixel values.
6261
 *
6262
 * @return CE_None on success or CE_Failure on failure.
6263
 */
6264

6265
CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
453✔
6266
                                     double dfStdDev)
6267

6268
{
6269
    char szValue[128] = {0};
453✔
6270

6271
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
453✔
6272
    SetMetadataItem("STATISTICS_MINIMUM", szValue);
453✔
6273

6274
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
453✔
6275
    SetMetadataItem("STATISTICS_MAXIMUM", szValue);
453✔
6276

6277
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
453✔
6278
    SetMetadataItem("STATISTICS_MEAN", szValue);
453✔
6279

6280
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
453✔
6281
    SetMetadataItem("STATISTICS_STDDEV", szValue);
453✔
6282

6283
    return CE_None;
453✔
6284
}
6285

6286
/************************************************************************/
6287
/*                      GDALSetRasterStatistics()                       */
6288
/************************************************************************/
6289

6290
/**
6291
 * \brief Set statistics on band.
6292
 *
6293
 * @see GDALRasterBand::SetStatistics()
6294
 */
6295

6296
CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
2✔
6297
                                           double dfMax, double dfMean,
6298
                                           double dfStdDev)
6299

6300
{
6301
    VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
2✔
6302

6303
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2✔
6304
    return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
2✔
6305
}
6306

6307
/************************************************************************/
6308
/*                        ComputeRasterMinMax()                         */
6309
/************************************************************************/
6310

6311
template <class T, bool HAS_NODATA>
6312
static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
133,584✔
6313
                          T *pMax)
6314
{
6315
    T min0 = *pMin;
133,584✔
6316
    T max0 = *pMax;
133,584✔
6317
    T min1 = *pMin;
133,584✔
6318
    T max1 = *pMax;
133,584✔
6319
    size_t i;
6320
    for (i = 0; i + 1 < nElts; i += 2)
950,452✔
6321
    {
6322
        if (!HAS_NODATA || buffer[i] != nodataValue)
804,394✔
6323
        {
6324
            min0 = std::min(min0, buffer[i]);
815,689✔
6325
            max0 = std::max(max0, buffer[i]);
815,689✔
6326
        }
6327
        if (!HAS_NODATA || buffer[i + 1] != nodataValue)
804,394✔
6328
        {
6329
            min1 = std::min(min1, buffer[i + 1]);
815,902✔
6330
            max1 = std::max(max1, buffer[i + 1]);
815,902✔
6331
        }
6332
    }
6333
    T min = std::min(min0, min1);
133,584✔
6334
    T max = std::max(max0, max1);
133,584✔
6335
    if (i < nElts)
133,584✔
6336
    {
6337
        if (!HAS_NODATA || buffer[i] != nodataValue)
118,171✔
6338
        {
6339
            min = std::min(min, buffer[i]);
118,171✔
6340
            max = std::max(max, buffer[i]);
118,171✔
6341
        }
6342
    }
6343
    *pMin = min;
133,584✔
6344
    *pMax = max;
133,584✔
6345
}
133,584✔
6346

6347
template <GDALDataType eDataType, bool bSignedByte>
6348
static void ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
9,390✔
6349
                                 int nBlockXSize, bool bGotNoDataValue,
6350
                                 double dfNoDataValue,
6351
                                 bool bGotFloatNoDataValue, float fNoDataValue,
6352
                                 const GByte *pabyMaskData, double &dfMin,
6353
                                 double &dfMax)
6354
{
6355
    double dfLocalMin = dfMin;
9,390✔
6356
    double dfLocalMax = dfMax;
9,390✔
6357

6358
    for (int iY = 0; iY < nYCheck; iY++)
38,900✔
6359
    {
6360
        for (int iX = 0; iX < nXCheck; iX++)
15,625,520✔
6361
        {
6362
            const GPtrDiff_t iOffset =
15,595,996✔
6363
                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
15,595,996✔
6364
            if (pabyMaskData && pabyMaskData[iOffset] == 0)
15,595,996✔
6365
                continue;
142,705✔
6366
            bool bValid = true;
15,501,755✔
6367
            double dfValue = GetPixelValue(
15,501,755✔
6368
                eDataType, bSignedByte, pData, iOffset, bGotNoDataValue,
6369
                dfNoDataValue, bGotFloatNoDataValue, fNoDataValue, bValid);
6370
            if (!bValid)
15,501,755✔
6371
                continue;
48,464✔
6372

6373
            dfLocalMin = std::min(dfLocalMin, dfValue);
15,453,245✔
6374
            dfLocalMax = std::max(dfLocalMax, dfValue);
15,453,245✔
6375
        }
6376
    }
6377

6378
    dfMin = dfLocalMin;
9,390✔
6379
    dfMax = dfLocalMax;
9,390✔
6380
}
9,390✔
6381

6382
static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
9,390✔
6383
                                 bool bSignedByte, int nXCheck, int nYCheck,
6384
                                 int nBlockXSize, bool bGotNoDataValue,
6385
                                 double dfNoDataValue,
6386
                                 bool bGotFloatNoDataValue, float fNoDataValue,
6387
                                 const GByte *pabyMaskData, double &dfMin,
6388
                                 double &dfMax)
6389
{
6390
    switch (eDataType)
9,390✔
6391
    {
6392
        case GDT_Unknown:
×
6393
            CPLAssert(false);
×
6394
            break;
6395
        case GDT_Byte:
672✔
6396
            if (bSignedByte)
672✔
6397
            {
6398
                ComputeMinMaxGeneric<GDT_Byte, true>(
3✔
6399
                    pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6400
                    dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6401
            }
6402
            else
6403
            {
6404
                ComputeMinMaxGeneric<GDT_Byte, false>(
669✔
6405
                    pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6406
                    dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6407
            }
6408
            break;
672✔
6409
        case GDT_Int8:
102✔
6410
            ComputeMinMaxGeneric<GDT_Int8, false>(
102✔
6411
                pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6412
                dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6413
            break;
102✔
6414
        case GDT_UInt16:
200✔
6415
            ComputeMinMaxGeneric<GDT_UInt16, false>(
200✔
6416
                pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6417
                dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6418
            break;
200✔
6419
        case GDT_Int16:
1✔
6420
            ComputeMinMaxGeneric<GDT_Int16, false>(
1✔
6421
                pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6422
                dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6423
            break;
1✔
6424
        case GDT_UInt32:
197✔
6425
            ComputeMinMaxGeneric<GDT_UInt32, false>(
197✔
6426
                pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6427
                dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6428
            break;
197✔
6429
        case GDT_Int32:
1,105✔
6430
            ComputeMinMaxGeneric<GDT_Int32, false>(
1,105✔
6431
                pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6432
                dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6433
            break;
1,105✔
6434
        case GDT_UInt64:
12✔
6435
            ComputeMinMaxGeneric<GDT_UInt64, false>(
12✔
6436
                pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6437
                dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6438
            break;
12✔
6439
        case GDT_Int64:
12✔
6440
            ComputeMinMaxGeneric<GDT_Int64, false>(
12✔
6441
                pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6442
                dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6443
            break;
12✔
6444
        case GDT_Float32:
5,664✔
6445
            ComputeMinMaxGeneric<GDT_Float32, false>(
5,664✔
6446
                pData, nXCheck, nYCheck, nBlockXSize, false, 0,
6447
                bGotFloatNoDataValue, fNoDataValue, pabyMaskData, dfMin, dfMax);
6448
            break;
5,664✔
6449
        case GDT_Float64:
1,315✔
6450
            ComputeMinMaxGeneric<GDT_Float64, false>(
1,315✔
6451
                pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6452
                dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6453
            break;
1,315✔
6454
        case GDT_CInt16:
9✔
6455
            ComputeMinMaxGeneric<GDT_CInt16, false>(
9✔
6456
                pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6457
                dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6458
            break;
9✔
6459
        case GDT_CInt32:
9✔
6460
            ComputeMinMaxGeneric<GDT_CInt32, false>(
9✔
6461
                pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6462
                dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6463
            break;
9✔
6464
        case GDT_CFloat32:
75✔
6465
            ComputeMinMaxGeneric<GDT_CFloat32, false>(
75✔
6466
                pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6467
                dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6468
            break;
75✔
6469
        case GDT_CFloat64:
17✔
6470
            ComputeMinMaxGeneric<GDT_CFloat64, false>(
17✔
6471
                pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
6472
                dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
6473
            break;
17✔
6474
        case GDT_TypeCount:
×
6475
            CPLAssert(false);
×
6476
            break;
6477
    }
6478
}
9,390✔
6479

6480
static bool ComputeMinMaxGenericIterBlocks(
675✔
6481
    GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
6482
    int nTotalBlocks, int nSampleRate, int nBlocksPerRow, bool bGotNoDataValue,
6483
    double dfNoDataValue, bool bGotFloatNoDataValue, float fNoDataValue,
6484
    GDALRasterBand *poMaskBand, double &dfMin, double &dfMax)
6485

6486
{
6487
    GByte *pabyMaskData = nullptr;
675✔
6488
    int nBlockXSize, nBlockYSize;
6489
    poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
675✔
6490

6491
    if (poMaskBand)
675✔
6492
    {
6493
        pabyMaskData =
6494
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
40✔
6495
        if (!pabyMaskData)
40✔
6496
        {
6497
            return false;
×
6498
        }
6499
    }
6500

6501
    for (int iSampleBlock = 0; iSampleBlock < nTotalBlocks;
10,065✔
6502
         iSampleBlock += nSampleRate)
9,390✔
6503
    {
6504
        const int iYBlock = iSampleBlock / nBlocksPerRow;
9,390✔
6505
        const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
9,390✔
6506

6507
        GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
9,390✔
6508
        if (poBlock == nullptr)
9,390✔
6509
        {
6510
            CPLFree(pabyMaskData);
×
6511
            return false;
×
6512
        }
6513

6514
        void *const pData = poBlock->GetDataRef();
9,390✔
6515

6516
        int nXCheck = 0, nYCheck = 0;
9,390✔
6517
        poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
9,390✔
6518

6519
        if (poMaskBand &&
10,261✔
6520
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
871✔
6521
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
6522
                                 pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
6523
                                 nBlockXSize, nullptr) != CE_None)
6524
        {
6525
            poBlock->DropLock();
×
6526
            CPLFree(pabyMaskData);
×
6527
            return false;
×
6528
        }
6529

6530
        ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
9,390✔
6531
                             nBlockXSize, CPL_TO_BOOL(bGotNoDataValue),
9,390✔
6532
                             dfNoDataValue, bGotFloatNoDataValue, fNoDataValue,
6533
                             pabyMaskData, dfMin, dfMax);
6534

6535
        poBlock->DropLock();
9,390✔
6536
    }
6537

6538
    CPLFree(pabyMaskData);
675✔
6539
    return true;
675✔
6540
}
6541

6542
/**
6543
 * \brief Compute the min/max values for a band.
6544
 *
6545
 * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
6546
 * be trusted.  If it doesn't work, a subsample of blocks will be read to
6547
 * get an approximate min/max.  If the band has a nodata value it will
6548
 * be excluded from the minimum and maximum.
6549
 *
6550
 * If bApprox is FALSE, then all pixels will be read and used to compute
6551
 * an exact range.
6552
 *
6553
 * This method is the same as the C function GDALComputeRasterMinMax().
6554
 *
6555
 * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
6556
 * FALSE.
6557
 * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
6558
 * maximum (adfMinMax[1]) are returned.
6559
 *
6560
 * @return CE_None on success or CE_Failure on failure.
6561
 */
6562

6563
CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
1,487✔
6564
{
6565
    /* -------------------------------------------------------------------- */
6566
    /*      Does the driver already know the min/max?                       */
6567
    /* -------------------------------------------------------------------- */
6568
    if (bApproxOK)
1,487✔
6569
    {
6570
        int bSuccessMin = FALSE;
12✔
6571
        int bSuccessMax = FALSE;
12✔
6572

6573
        double dfMin = GetMinimum(&bSuccessMin);
12✔
6574
        double dfMax = GetMaximum(&bSuccessMax);
12✔
6575

6576
        if (bSuccessMin && bSuccessMax)
12✔
6577
        {
6578
            adfMinMax[0] = dfMin;
1✔
6579
            adfMinMax[1] = dfMax;
1✔
6580
            return CE_None;
1✔
6581
        }
6582
    }
6583

6584
    /* -------------------------------------------------------------------- */
6585
    /*      If we have overview bands, use them for min/max.                */
6586
    /* -------------------------------------------------------------------- */
6587
    // cppcheck-suppress knownConditionTrueFalse
6588
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
1,486✔
6589
    {
6590
        GDALRasterBand *poBand =
6591
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
×
6592

6593
        if (poBand != this)
×
6594
            return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
×
6595
    }
6596

6597
    /* -------------------------------------------------------------------- */
6598
    /*      Read actual data and compute minimum and maximum.               */
6599
    /* -------------------------------------------------------------------- */
6600
    int bGotNoDataValue = FALSE;
1,486✔
6601
    const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
1,486✔
6602
    bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
1,486✔
6603
    bool bGotFloatNoDataValue = false;
1,486✔
6604
    float fNoDataValue = 0.0f;
1,486✔
6605
    ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
1,486✔
6606
                            fNoDataValue, bGotFloatNoDataValue);
6607

6608
    GDALRasterBand *poMaskBand = nullptr;
1,486✔
6609
    if (!bGotNoDataValue)
1,486✔
6610
    {
6611
        const int l_nMaskFlags = GetMaskFlags();
1,233✔
6612
        if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
1,273✔
6613
            GetColorInterpretation() != GCI_AlphaBand)
40✔
6614
        {
6615
            poMaskBand = GetMaskBand();
40✔
6616
        }
6617
    }
6618

6619
    bool bSignedByte = false;
1,486✔
6620
    if (eDataType == GDT_Byte)
1,486✔
6621
    {
6622
        EnablePixelTypeSignedByteWarning(false);
610✔
6623
        const char *pszPixelType =
6624
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
610✔
6625
        EnablePixelTypeSignedByteWarning(true);
610✔
6626
        bSignedByte =
610✔
6627
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
610✔
6628
    }
6629

6630
    GDALRasterIOExtraArg sExtraArg;
6631
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
1,486✔
6632

6633
    GUInt32 nMin = (eDataType == GDT_Byte)
2,972✔
6634
                       ? 255
1,486✔
6635
                       : 65535;  // used for GByte & GUInt16 cases
6636
    GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
1,486✔
6637
    GInt16 nMinInt16 =
1,486✔
6638
        std::numeric_limits<GInt16>::max();  // used for GInt16 case
6639
    GInt16 nMaxInt16 =
1,486✔
6640
        std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
6641
    double dfMin =
1,486✔
6642
        std::numeric_limits<double>::max();  // used for generic code path
6643
    double dfMax =
1,486✔
6644
        -std::numeric_limits<double>::max();  // used for generic code path
6645
    const bool bUseOptimizedPath =
1,486✔
6646
        !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
2,353✔
6647
                        eDataType == GDT_Int16 || eDataType == GDT_UInt16);
867✔
6648

6649
    const auto ComputeMinMaxForBlock =
6650
        [this, bSignedByte, bGotNoDataValue, dfNoDataValue, &nMin, &nMax,
18,348✔
6651
         &nMinInt16, &nMaxInt16](const void *pData, int nXCheck,
6652
                                 int nBufferWidth, int nYCheck)
239,679✔
6653
    {
6654
        if (eDataType == GDT_Byte && !bSignedByte)
18,348✔
6655
        {
6656
            const bool bHasNoData =
6657
                bGotNoDataValue && GDALIsValueInRange<GByte>(dfNoDataValue) &&
25,472✔
6658
                static_cast<GByte>(dfNoDataValue) == dfNoDataValue;
9,501✔
6659
            const GUInt32 nNoDataValue =
15,971✔
6660
                bHasNoData ? static_cast<GByte>(dfNoDataValue) : 0;
15,971✔
6661
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
6662
            ComputeStatisticsInternal<GByte,
6663
                                      /* COMPUTE_OTHER_STATS = */ false>::
6664
                f(nXCheck, nBufferWidth, nYCheck,
15,971✔
6665
                  static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
6666
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
15,971✔
6667
        }
6668
        else if (eDataType == GDT_UInt16)
2,377✔
6669
        {
6670
            const bool bHasNoData =
6671
                bGotNoDataValue && GDALIsValueInRange<GUInt16>(dfNoDataValue) &&
973✔
6672
                static_cast<GUInt16>(dfNoDataValue) == dfNoDataValue;
83✔
6673
            const GUInt32 nNoDataValue =
890✔
6674
                bHasNoData ? static_cast<GUInt16>(dfNoDataValue) : 0;
890✔
6675
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
6676
            ComputeStatisticsInternal<GUInt16,
6677
                                      /* COMPUTE_OTHER_STATS = */ false>::
6678
                f(nXCheck, nBufferWidth, nYCheck,
890✔
6679
                  static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
6680
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6681
        }
6682
        else if (eDataType == GDT_Int16)
1,487✔
6683
        {
6684
            const bool bHasNoData =
6685
                bGotNoDataValue && GDALIsValueInRange<int16_t>(dfNoDataValue) &&
2,804✔
6686
                static_cast<int16_t>(dfNoDataValue) == dfNoDataValue;
1,317✔
6687
            if (bHasNoData)
1,487✔
6688
            {
6689
                const int16_t nNoDataValue =
1,317✔
6690
                    static_cast<int16_t>(dfNoDataValue);
6691
                for (int iY = 0; iY < nYCheck; iY++)
133,629✔
6692
                {
6693
                    ComputeMinMax<int16_t, true>(
132,312✔
6694
                        static_cast<const int16_t *>(pData) +
132,312✔
6695
                            static_cast<size_t>(iY) * nBufferWidth,
132,312✔
6696
                        nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
6697
                }
6698
            }
6699
            else
6700
            {
6701
                for (int iY = 0; iY < nYCheck; iY++)
1,442✔
6702
                {
6703
                    ComputeMinMax<int16_t, false>(
1,272✔
6704
                        static_cast<const int16_t *>(pData) +
1,272✔
6705
                            static_cast<size_t>(iY) * nBufferWidth,
1,272✔
6706
                        nXCheck, 0, &nMinInt16, &nMaxInt16);
6707
                }
6708
            }
6709
        }
6710
    };
18,348✔
6711

6712
    if (bApproxOK && HasArbitraryOverviews())
1,486✔
6713
    {
6714
        /* --------------------------------------------------------------------
6715
         */
6716
        /*      Figure out how much the image should be reduced to get an */
6717
        /*      approximate value. */
6718
        /* --------------------------------------------------------------------
6719
         */
6720
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
×
6721
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
×
6722

6723
        int nXReduced = nRasterXSize;
×
6724
        int nYReduced = nRasterYSize;
×
6725
        if (dfReduction > 1.0)
×
6726
        {
6727
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
×
6728
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
×
6729

6730
            // Catch the case of huge resizing ratios here
6731
            if (nXReduced == 0)
×
6732
                nXReduced = 1;
×
6733
            if (nYReduced == 0)
×
6734
                nYReduced = 1;
×
6735
        }
6736

6737
        void *const pData = CPLMalloc(cpl::fits_on<int>(
×
6738
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
×
6739

6740
        const CPLErr eErr =
6741
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
×
6742
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
×
6743
        if (eErr != CE_None)
×
6744
        {
6745
            CPLFree(pData);
×
6746
            return eErr;
×
6747
        }
6748

6749
        GByte *pabyMaskData = nullptr;
×
6750
        if (poMaskBand)
×
6751
        {
6752
            pabyMaskData =
6753
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
×
6754
            if (!pabyMaskData)
×
6755
            {
6756
                CPLFree(pData);
×
6757
                return CE_Failure;
×
6758
            }
6759

6760
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
×
6761
                                     pabyMaskData, nXReduced, nYReduced,
6762
                                     GDT_Byte, 0, 0, nullptr) != CE_None)
×
6763
            {
6764
                CPLFree(pData);
×
6765
                CPLFree(pabyMaskData);
×
6766
                return CE_Failure;
×
6767
            }
6768
        }
6769

6770
        if (bUseOptimizedPath)
×
6771
        {
6772
            ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
×
6773
        }
6774
        else
6775
        {
6776
            ComputeMinMaxGeneric(
×
6777
                pData, eDataType, bSignedByte, nXReduced, nYReduced, nXReduced,
6778
                CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
×
6779
                bGotFloatNoDataValue, fNoDataValue, pabyMaskData, dfMin, dfMax);
6780
        }
6781

6782
        CPLFree(pData);
×
6783
        CPLFree(pabyMaskData);
×
6784
    }
6785

6786
    else  // No arbitrary overviews
6787
    {
6788
        if (!InitBlockInfo())
1,486✔
6789
            return CE_Failure;
×
6790

6791
        /* --------------------------------------------------------------------
6792
         */
6793
        /*      Figure out the ratio of blocks we will read to get an */
6794
        /*      approximate value. */
6795
        /* --------------------------------------------------------------------
6796
         */
6797
        int nSampleRate = 1;
1,486✔
6798

6799
        if (bApproxOK)
1,486✔
6800
        {
6801
            nSampleRate = static_cast<int>(std::max(
11✔
6802
                1.0,
22✔
6803
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
11✔
6804
            // We want to avoid probing only the first column of blocks for
6805
            // a square shaped raster, because it is not unlikely that it may
6806
            // be padding only (#6378).
6807
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
11✔
6808
                nSampleRate += 1;
×
6809
        }
6810

6811
        if (bUseOptimizedPath)
1,486✔
6812
        {
6813
            for (int iSampleBlock = 0;
811✔
6814
                 iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
19,086✔
6815
                 iSampleBlock += nSampleRate)
18,275✔
6816
            {
6817
                const int iYBlock = iSampleBlock / nBlocksPerRow;
18,348✔
6818
                const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
18,348✔
6819

6820
                GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
18,348✔
6821
                if (poBlock == nullptr)
18,348✔
6822
                    return CE_Failure;
×
6823

6824
                void *const pData = poBlock->GetDataRef();
18,348✔
6825

6826
                int nXCheck = 0, nYCheck = 0;
18,348✔
6827
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
18,348✔
6828

6829
                ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
18,348✔
6830

6831
                poBlock->DropLock();
18,348✔
6832

6833
                if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
18,348✔
6834
                    nMax == 255)
4,086✔
6835
                    break;
73✔
6836
            }
6837
        }
6838
        else
6839
        {
6840
            const int nTotalBlocks = nBlocksPerRow * nBlocksPerColumn;
675✔
6841
            if (!ComputeMinMaxGenericIterBlocks(
675✔
6842
                    this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
6843
                    nBlocksPerRow, CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
675✔
6844
                    bGotFloatNoDataValue, fNoDataValue, poMaskBand, dfMin,
6845
                    dfMax))
6846
            {
6847
                return CE_Failure;
×
6848
            }
6849
        }
6850
    }
6851

6852
    if (bUseOptimizedPath)
1,486✔
6853
    {
6854
        if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
811✔
6855
        {
6856
            dfMin = nMin;
709✔
6857
            dfMax = nMax;
709✔
6858
        }
6859
        else if (eDataType == GDT_Int16)
102✔
6860
        {
6861
            dfMin = nMinInt16;
102✔
6862
            dfMax = nMaxInt16;
102✔
6863
        }
6864
    }
6865

6866
    if (dfMin > dfMax)
1,486✔
6867
    {
6868
        adfMinMax[0] = 0;
4✔
6869
        adfMinMax[1] = 0;
4✔
6870
        ReportError(
4✔
6871
            CE_Failure, CPLE_AppDefined,
6872
            "Failed to compute min/max, no valid pixels found in sampling.");
6873
        return CE_Failure;
4✔
6874
    }
6875

6876
    adfMinMax[0] = dfMin;
1,482✔
6877
    adfMinMax[1] = dfMax;
1,482✔
6878

6879
    return CE_None;
1,482✔
6880
}
6881

6882
/************************************************************************/
6883
/*                      GDALComputeRasterMinMax()                       */
6884
/************************************************************************/
6885

6886
/**
6887
 * \brief Compute the min/max values for a band.
6888
 *
6889
 * @see GDALRasterBand::ComputeRasterMinMax()
6890
 *
6891
 * @note Prior to GDAL 3.6, this function returned void
6892
 */
6893

6894
CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
1,409✔
6895
                                           double adfMinMax[2])
6896

6897
{
6898
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
1,409✔
6899

6900
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1,409✔
6901
    return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
1,409✔
6902
}
6903

6904
/************************************************************************/
6905
/*                        SetDefaultHistogram()                         */
6906
/************************************************************************/
6907

6908
/* FIXME : add proper documentation */
6909
/**
6910
 * \brief Set default histogram.
6911
 *
6912
 * This method is the same as the C function GDALSetDefaultHistogram() and
6913
 * GDALSetDefaultHistogramEx()
6914
 */
6915
CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
×
6916
                                           double /* dfMax */,
6917
                                           int /* nBuckets */,
6918
                                           GUIntBig * /* panHistogram */)
6919

6920
{
6921
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
×
6922
        ReportError(CE_Failure, CPLE_NotSupported,
×
6923
                    "SetDefaultHistogram() not implemented for this format.");
6924

6925
    return CE_Failure;
×
6926
}
6927

6928
/************************************************************************/
6929
/*                      GDALSetDefaultHistogram()                       */
6930
/************************************************************************/
6931

6932
/**
6933
 * \brief Set default histogram.
6934
 *
6935
 * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
6936
 * 2 billion.
6937
 *
6938
 * @see GDALRasterBand::SetDefaultHistogram()
6939
 * @see GDALSetRasterHistogramEx()
6940
 */
6941

6942
CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
×
6943
                                           double dfMax, int nBuckets,
6944
                                           int *panHistogram)
6945

6946
{
6947
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
×
6948

6949
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
×
6950

6951
    GUIntBig *panHistogramTemp =
6952
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
×
6953
    if (panHistogramTemp == nullptr)
×
6954
    {
6955
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
×
6956
                            "Out of memory in GDALSetDefaultHistogram().");
6957
        return CE_Failure;
×
6958
    }
6959

6960
    for (int i = 0; i < nBuckets; ++i)
×
6961
    {
6962
        panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
×
6963
    }
6964

6965
    const CPLErr eErr =
6966
        poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
×
6967

6968
    CPLFree(panHistogramTemp);
×
6969

6970
    return eErr;
×
6971
}
6972

6973
/************************************************************************/
6974
/*                     GDALSetDefaultHistogramEx()                      */
6975
/************************************************************************/
6976

6977
/**
6978
 * \brief Set default histogram.
6979
 *
6980
 * @see GDALRasterBand::SetDefaultHistogram()
6981
 *
6982
 * @since GDAL 2.0
6983
 */
6984

6985
CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
5✔
6986
                                             double dfMin, double dfMax,
6987
                                             int nBuckets,
6988
                                             GUIntBig *panHistogram)
6989

6990
{
6991
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
5✔
6992

6993
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5✔
6994
    return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
5✔
6995
}
6996

6997
/************************************************************************/
6998
/*                           GetDefaultRAT()                            */
6999
/************************************************************************/
7000

7001
/**
7002
 * \brief Fetch default Raster Attribute Table.
7003
 *
7004
 * A RAT will be returned if there is a default one associated with the
7005
 * band, otherwise NULL is returned.  The returned RAT is owned by the
7006
 * band and should not be deleted by the application.
7007
 *
7008
 * This method is the same as the C function GDALGetDefaultRAT().
7009
 *
7010
 * @return NULL, or a pointer to an internal RAT owned by the band.
7011
 */
7012

7013
GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
92✔
7014

7015
{
7016
    return nullptr;
92✔
7017
}
7018

7019
/************************************************************************/
7020
/*                         GDALGetDefaultRAT()                          */
7021
/************************************************************************/
7022

7023
/**
7024
 * \brief Fetch default Raster Attribute Table.
7025
 *
7026
 * @see GDALRasterBand::GetDefaultRAT()
7027
 */
7028

7029
GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
894✔
7030

7031
{
7032
    VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
894✔
7033

7034
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
894✔
7035
    return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
894✔
7036
}
7037

7038
/************************************************************************/
7039
/*                           SetDefaultRAT()                            */
7040
/************************************************************************/
7041

7042
/**
7043
 * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
7044
 * \brief Set default Raster Attribute Table.
7045
 *
7046
 * Associates a default RAT with the band.  If not implemented for the
7047
 * format a CPLE_NotSupported error will be issued.  If successful a copy
7048
 * of the RAT is made, the original remains owned by the caller.
7049
 *
7050
 * This method is the same as the C function GDALSetDefaultRAT().
7051
 *
7052
 * @param poRAT the RAT to assign to the band.
7053
 *
7054
 * @return CE_None on success or CE_Failure if unsupported or otherwise
7055
 * failing.
7056
 */
7057

7058
/**/
7059
/**/
7060

7061
CPLErr
7062
GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
×
7063
{
7064
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
×
7065
    {
7066
        CPLPushErrorHandler(CPLQuietErrorHandler);
×
7067
        ReportError(CE_Failure, CPLE_NotSupported,
×
7068
                    "SetDefaultRAT() not implemented for this format.");
7069
        CPLPopErrorHandler();
×
7070
    }
7071
    return CE_Failure;
×
7072
}
7073

7074
/************************************************************************/
7075
/*                         GDALSetDefaultRAT()                          */
7076
/************************************************************************/
7077

7078
/**
7079
 * \brief Set default Raster Attribute Table.
7080
 *
7081
 * @see GDALRasterBand::GDALSetDefaultRAT()
7082
 */
7083

7084
CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
17✔
7085
                                     GDALRasterAttributeTableH hRAT)
7086

7087
{
7088
    VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
17✔
7089

7090
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
17✔
7091

7092
    return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
17✔
7093
}
7094

7095
/************************************************************************/
7096
/*                            GetMaskBand()                             */
7097
/************************************************************************/
7098

7099
/**
7100
 * \brief Return the mask band associated with the band.
7101
 *
7102
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
7103
 * that returns one of four default implementations : <ul> <li>If a
7104
 * corresponding .msk file exists it will be used for the mask band.</li> <li>If
7105
 * the dataset has a NODATA_VALUES metadata item, an instance of the new
7106
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
7107
 * GMF_NODATA | GMF_PER_DATASET. @since GDAL 1.6.0</li> <li>If the band has a
7108
 * nodata value set, an instance of the new GDALNodataMaskRasterBand class will
7109
 * be returned. GetMaskFlags() will return GMF_NODATA.</li> <li>If there is no
7110
 * nodata value, but the dataset has an alpha band that seems to apply to this
7111
 * band (specific rules yet to be determined) and that is of type GDT_Byte then
7112
 * that alpha band will be returned, and the flags GMF_PER_DATASET and GMF_ALPHA
7113
 * will be returned in the flags.</li> <li>If neither of the above apply, an
7114
 * instance of the new GDALAllValidRasterBand class will be returned that has
7115
 * 255 values for all pixels. The null flags will return GMF_ALL_VALID.</li>
7116
 * </ul>
7117
 *
7118
 * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
7119
 * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
7120
 *
7121
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
7122
 * dataset, with the same name as the main dataset and suffixed with .msk,
7123
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
7124
 * main dataset.
7125
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
7126
 * level, where xx matches the band number of a band of the main dataset. The
7127
 * value of those items is a combination of the flags GMF_ALL_VALID,
7128
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
7129
 * a band, then the other rules explained above will be used to generate a
7130
 * on-the-fly mask band.
7131
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
7132
 *
7133
 * This method is the same as the C function GDALGetMaskBand().
7134
 *
7135
 * @return a valid mask band.
7136
 *
7137
 * @since GDAL 1.5.0
7138
 *
7139
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
7140
 *
7141
 */
7142
GDALRasterBand *GDALRasterBand::GetMaskBand()
28,500✔
7143

7144
{
7145
    const auto HasNoData = [this]()
83,246✔
7146
    {
7147
        int bHaveNoDataRaw = FALSE;
27,509✔
7148
        bool bHaveNoData = false;
27,509✔
7149
        if (eDataType == GDT_Int64)
27,509✔
7150
        {
7151
            CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
23✔
7152
            bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
23✔
7153
        }
7154
        else if (eDataType == GDT_UInt64)
27,486✔
7155
        {
7156
            CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
22✔
7157
            bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
22✔
7158
        }
7159
        else
7160
        {
7161
            const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
27,464✔
7162
            if (bHaveNoDataRaw &&
27,459✔
7163
                GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
27,459✔
7164
            {
7165
                bHaveNoData = true;
713✔
7166
            }
7167
        }
7168
        return bHaveNoData;
27,500✔
7169
    };
28,500✔
7170

7171
    if (poMask != nullptr)
28,500✔
7172
    {
7173
        if (poMask.IsOwned())
6,217✔
7174
        {
7175
            if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
5,644✔
7176
            {
7177
                if (HasNoData())
5,310✔
7178
                {
7179
                    InvalidateMaskBand();
3✔
7180
                }
7181
            }
7182
            else if (auto poNoDataMaskBand =
335✔
7183
                         dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
339✔
7184
            {
7185
                int bHaveNoDataRaw = FALSE;
135✔
7186
                bool bIsSame = false;
135✔
7187
                if (eDataType == GDT_Int64)
135✔
7188
                    bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
4✔
7189
                                  GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
5✔
7190
                              bHaveNoDataRaw;
1✔
7191
                else if (eDataType == GDT_UInt64)
131✔
7192
                    bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
4✔
7193
                                  GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
5✔
7194
                              bHaveNoDataRaw;
1✔
7195
                else
7196
                {
7197
                    const double dfNoDataValue =
7198
                        GetNoDataValue(&bHaveNoDataRaw);
127✔
7199
                    if (bHaveNoDataRaw)
127✔
7200
                    {
7201
                        bIsSame =
126✔
7202
                            std::isnan(dfNoDataValue)
126✔
7203
                                ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
126✔
7204
                                : poNoDataMaskBand->m_dfNoDataValue ==
118✔
7205
                                      dfNoDataValue;
7206
                    }
7207
                }
7208
                if (!bIsSame)
135✔
7209
                    InvalidateMaskBand();
9✔
7210
            }
7211
        }
7212

7213
        if (poMask)
6,203✔
7214
            return poMask.get();
6,194✔
7215
    }
7216

7217
    /* -------------------------------------------------------------------- */
7218
    /*      Check for a mask in a .msk file.                                */
7219
    /* -------------------------------------------------------------------- */
7220
    if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
22,291✔
7221
    {
7222
        poMask.reset(poDS->oOvManager.GetMaskBand(nBand), false);
46✔
7223
        if (poMask != nullptr)
46✔
7224
        {
7225
            nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
44✔
7226
            return poMask.get();
44✔
7227
        }
7228
    }
7229

7230
    /* -------------------------------------------------------------------- */
7231
    /*      Check for NODATA_VALUES metadata.                               */
7232
    /* -------------------------------------------------------------------- */
7233
    if (poDS != nullptr)
22,247✔
7234
    {
7235
        const char *pszNoDataValues = poDS->GetMetadataItem("NODATA_VALUES");
22,236✔
7236
        if (pszNoDataValues != nullptr)
22,236✔
7237
        {
7238
            char **papszNoDataValues =
7239
                CSLTokenizeStringComplex(pszNoDataValues, " ", FALSE, FALSE);
56✔
7240

7241
            // Make sure we have as many values as bands.
7242
            if (CSLCount(papszNoDataValues) == poDS->GetRasterCount() &&
112✔
7243
                poDS->GetRasterCount() != 0)
56✔
7244
            {
7245
                // Make sure that all bands have the same data type
7246
                // This is clearly not a fundamental condition, just a
7247
                // condition to make implementation easier.
7248
                GDALDataType eDT = GDT_Unknown;
56✔
7249
                int i = 0;  // Used after for.
56✔
7250
                for (; i < poDS->GetRasterCount(); ++i)
224✔
7251
                {
7252
                    if (i == 0)
168✔
7253
                        eDT = poDS->GetRasterBand(1)->GetRasterDataType();
56✔
7254
                    else if (eDT !=
112✔
7255
                             poDS->GetRasterBand(i + 1)->GetRasterDataType())
112✔
7256
                    {
7257
                        break;
×
7258
                    }
7259
                }
7260
                if (i == poDS->GetRasterCount())
56✔
7261
                {
7262
                    nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
56✔
7263
                    try
7264
                    {
7265
                        poMask.reset(new GDALNoDataValuesMaskBand(poDS), true);
56✔
7266
                    }
7267
                    catch (const std::bad_alloc &)
×
7268
                    {
7269
                        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
×
7270
                        poMask.reset();
×
7271
                    }
7272
                    CSLDestroy(papszNoDataValues);
56✔
7273
                    return poMask.get();
56✔
7274
                }
7275
                else
7276
                {
7277
                    ReportError(CE_Warning, CPLE_AppDefined,
×
7278
                                "All bands should have the same type in "
7279
                                "order the NODATA_VALUES metadata item "
7280
                                "to be used as a mask.");
7281
                }
7282
            }
7283
            else
7284
            {
7285
                ReportError(
×
7286
                    CE_Warning, CPLE_AppDefined,
7287
                    "NODATA_VALUES metadata item doesn't have the same number "
7288
                    "of values as the number of bands.  "
7289
                    "Ignoring it for mask.");
7290
            }
7291

7292
            CSLDestroy(papszNoDataValues);
×
7293
        }
7294
    }
7295

7296
    /* -------------------------------------------------------------------- */
7297
    /*      Check for nodata case.                                          */
7298
    /* -------------------------------------------------------------------- */
7299
    if (HasNoData())
22,191✔
7300
    {
7301
        nMaskFlags = GMF_NODATA;
727✔
7302
        try
7303
        {
7304
            poMask.reset(new GDALNoDataMaskBand(this), true);
727✔
7305
        }
7306
        catch (const std::bad_alloc &)
×
7307
        {
7308
            CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
×
7309
            poMask.reset();
×
7310
        }
7311
        return poMask.get();
727✔
7312
    }
7313

7314
    /* -------------------------------------------------------------------- */
7315
    /*      Check for alpha case.                                           */
7316
    /* -------------------------------------------------------------------- */
7317
    if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
21,454✔
7318
        this == poDS->GetRasterBand(1) &&
43,430✔
7319
        poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
512✔
7320
    {
7321
        if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
186✔
7322
        {
7323
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
142✔
7324
            poMask.reset(poDS->GetRasterBand(2), false);
142✔
7325
            return poMask.get();
142✔
7326
        }
7327
        else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
44✔
7328
        {
7329
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
23✔
7330
            try
7331
            {
7332
                poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(2)),
23✔
7333
                             true);
7334
            }
7335
            catch (const std::bad_alloc &)
×
7336
            {
7337
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
×
7338
                poMask.reset();
×
7339
            }
7340
            return poMask.get();
23✔
7341
        }
7342
    }
7343

7344
    if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
21,289✔
7345
        (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
2,574✔
7346
         this == poDS->GetRasterBand(3)) &&
43,206✔
7347
        poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
2,006✔
7348
    {
7349
        if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
1,136✔
7350
        {
7351
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
1,089✔
7352
            poMask.reset(poDS->GetRasterBand(4), false);
1,089✔
7353
            return poMask.get();
1,089✔
7354
        }
7355
        else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
47✔
7356
        {
7357
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
35✔
7358
            try
7359
            {
7360
                poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(4)),
35✔
7361
                             true);
7362
            }
7363
            catch (const std::bad_alloc &)
×
7364
            {
7365
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
×
7366
                poMask.reset();
×
7367
            }
7368
            return poMask.get();
35✔
7369
        }
7370
    }
7371

7372
    /* -------------------------------------------------------------------- */
7373
    /*      Fallback to all valid case.                                     */
7374
    /* -------------------------------------------------------------------- */
7375
    nMaskFlags = GMF_ALL_VALID;
20,175✔
7376
    try
7377
    {
7378
        poMask.reset(new GDALAllValidMaskBand(this), true);
20,175✔
7379
    }
7380
    catch (const std::bad_alloc &)
×
7381
    {
7382
        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
×
7383
        poMask.reset();
×
7384
    }
7385

7386
    return poMask.get();
20,175✔
7387
}
7388

7389
/************************************************************************/
7390
/*                          GDALGetMaskBand()                           */
7391
/************************************************************************/
7392

7393
/**
7394
 * \brief Return the mask band associated with the band.
7395
 *
7396
 * @see GDALRasterBand::GetMaskBand()
7397
 */
7398

7399
GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
825✔
7400

7401
{
7402
    VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
825✔
7403

7404
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
825✔
7405
    return poBand->GetMaskBand();
825✔
7406
}
7407

7408
/************************************************************************/
7409
/*                            GetMaskFlags()                            */
7410
/************************************************************************/
7411

7412
/**
7413
 * \brief Return the status flags of the mask band associated with the band.
7414
 *
7415
 * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
7416
 * the following available definitions that may be extended in the future:
7417
 * <ul>
7418
 * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
7419
 * 255. When used this will normally be the only flag set.</li>
7420
 * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
7421
 * dataset.</li> <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
7422
 * and may have values other than 0 and 255.</li> <li>GMF_NODATA(0x08):
7423
 * Indicates the mask is actually being generated from nodata values. (mutually
7424
 * exclusive of GMF_ALPHA)</li>
7425
 * </ul>
7426
 *
7427
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
7428
 * that returns one of four default implementations : <ul> <li>If a
7429
 * corresponding .msk file exists it will be used for the mask band.</li> <li>If
7430
 * the dataset has a NODATA_VALUES metadata item, an instance of the new
7431
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
7432
 * GMF_NODATA | GMF_PER_DATASET. @since GDAL 1.6.0</li> <li>If the band has a
7433
 * nodata value set, an instance of the new GDALNodataMaskRasterBand class will
7434
 * be returned. GetMaskFlags() will return GMF_NODATA.</li> <li>If there is no
7435
 * nodata value, but the dataset has an alpha band that seems to apply to this
7436
 * band (specific rules yet to be determined) and that is of type GDT_Byte then
7437
 * that alpha band will be returned, and the flags GMF_PER_DATASET and GMF_ALPHA
7438
 * will be returned in the flags.</li> <li>If neither of the above apply, an
7439
 * instance of the new GDALAllValidRasterBand class will be returned that has
7440
 * 255 values for all pixels. The null flags will return GMF_ALL_VALID.</li>
7441
 * </ul>
7442
 *
7443
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
7444
 * dataset, with the same name as the main dataset and suffixed with .msk,
7445
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
7446
 * main dataset.
7447
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
7448
 * level, where xx matches the band number of a band of the main dataset. The
7449
 * value of those items is a combination of the flags GMF_ALL_VALID,
7450
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
7451
 * a band, then the other rules explained above will be used to generate a
7452
 * on-the-fly mask band.
7453
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
7454
 *
7455
 * This method is the same as the C function GDALGetMaskFlags().
7456
 *
7457
 * @since GDAL 1.5.0
7458
 *
7459
 * @return a valid mask band.
7460
 *
7461
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
7462
 *
7463
 */
7464
int GDALRasterBand::GetMaskFlags()
62,562✔
7465

7466
{
7467
    // If we don't have a band yet, force this now so that the masks value
7468
    // will be initialized.
7469

7470
    if (poMask == nullptr)
62,562✔
7471
        GetMaskBand();
21,311✔
7472

7473
    return nMaskFlags;
62,555✔
7474
}
7475

7476
/************************************************************************/
7477
/*                          GDALGetMaskFlags()                          */
7478
/************************************************************************/
7479

7480
/**
7481
 * \brief Return the status flags of the mask band associated with the band.
7482
 *
7483
 * @see GDALRasterBand::GetMaskFlags()
7484
 */
7485

7486
int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
5,900✔
7487

7488
{
7489
    VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
5,900✔
7490

7491
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5,900✔
7492
    return poBand->GetMaskFlags();
5,900✔
7493
}
7494

7495
/************************************************************************/
7496
/*                         InvalidateMaskBand()                         */
7497
/************************************************************************/
7498

7499
//! @cond Doxygen_Suppress
7500
void GDALRasterBand::InvalidateMaskBand()
1,040,880✔
7501
{
7502
    poMask.reset();
1,040,880✔
7503
    nMaskFlags = 0;
1,040,880✔
7504
}
1,040,880✔
7505

7506
//! @endcond
7507

7508
/************************************************************************/
7509
/*                           CreateMaskBand()                           */
7510
/************************************************************************/
7511

7512
/**
7513
 * \brief Adds a mask band to the current band
7514
 *
7515
 * The default implementation of the CreateMaskBand() method is implemented
7516
 * based on similar rules to the .ovr handling implemented using the
7517
 * GDALDefaultOverviews object. A TIFF file with the extension .msk will
7518
 * be created with the same basename as the original file, and it will have
7519
 * as many bands as the original image (or just one for GMF_PER_DATASET).
7520
 * The mask images will be deflate compressed tiled images with the same
7521
 * block size as the original image if possible.
7522
 * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
7523
 * level, where xx matches the band number of a band of the main dataset. The
7524
 * value of those items will be the one of the nFlagsIn parameter.
7525
 *
7526
 * Note that if you got a mask band with a previous call to GetMaskBand(),
7527
 * it might be invalidated by CreateMaskBand(). So you have to call
7528
 * GetMaskBand() again.
7529
 *
7530
 * This method is the same as the C function GDALCreateMaskBand().
7531
 *
7532
 * @since GDAL 1.5.0
7533
 *
7534
 * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
7535
 *
7536
 * @return CE_None on success or CE_Failure on an error.
7537
 *
7538
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
7539
 * @see GDALDataset::CreateMaskBand()
7540
 *
7541
 */
7542

7543
CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9✔
7544

7545
{
7546
    if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9✔
7547
    {
7548
        const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9✔
7549
        if (eErr != CE_None)
9✔
7550
            return eErr;
1✔
7551

7552
        InvalidateMaskBand();
8✔
7553

7554
        return CE_None;
8✔
7555
    }
7556

7557
    ReportError(CE_Failure, CPLE_NotSupported,
×
7558
                "CreateMaskBand() not supported for this band.");
7559

7560
    return CE_Failure;
×
7561
}
7562

7563
/************************************************************************/
7564
/*                         GDALCreateMaskBand()                         */
7565
/************************************************************************/
7566

7567
/**
7568
 * \brief Adds a mask band to the current band
7569
 *
7570
 * @see GDALRasterBand::CreateMaskBand()
7571
 */
7572

7573
CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
31✔
7574

7575
{
7576
    VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
31✔
7577

7578
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
31✔
7579
    return poBand->CreateMaskBand(nFlags);
31✔
7580
}
7581

7582
/************************************************************************/
7583
/*                            IsMaskBand()                              */
7584
/************************************************************************/
7585

7586
/**
7587
 * \brief Returns whether a band is a mask band.
7588
 *
7589
 * Mask band must be understood in the broad term: it can be a per-dataset
7590
 * mask band, an alpha band, or an implicit mask band.
7591
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
7592
 *
7593
 * This method is the same as the C function GDALIsMaskBand().
7594
 *
7595
 * @return true if the band is a mask band.
7596
 *
7597
 * @see GDALDataset::CreateMaskBand()
7598
 *
7599
 * @since GDAL 3.5.0
7600
 *
7601
 */
7602

7603
bool GDALRasterBand::IsMaskBand() const
325✔
7604
{
7605
    // The GeoTIFF driver, among others, override this method to
7606
    // also handle external .msk bands.
7607
    return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
325✔
7608
           GCI_AlphaBand;
325✔
7609
}
7610

7611
/************************************************************************/
7612
/*                            GDALIsMaskBand()                          */
7613
/************************************************************************/
7614

7615
/**
7616
 * \brief Returns whether a band is a mask band.
7617
 *
7618
 * Mask band must be understood in the broad term: it can be a per-dataset
7619
 * mask band, an alpha band, or an implicit mask band.
7620
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
7621
 *
7622
 * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
7623
 *
7624
 * @return true if the band is a mask band.
7625
 *
7626
 * @see GDALRasterBand::IsMaskBand()
7627
 *
7628
 * @since GDAL 3.5.0
7629
 *
7630
 */
7631

7632
bool GDALIsMaskBand(GDALRasterBandH hBand)
34✔
7633

7634
{
7635
    VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
34✔
7636

7637
    const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
34✔
7638
    return poBand->IsMaskBand();
34✔
7639
}
7640

7641
/************************************************************************/
7642
/*                         GetMaskValueRange()                          */
7643
/************************************************************************/
7644

7645
/**
7646
 * \brief Returns the range of values that a mask band can take.
7647
 *
7648
 * @return the range of values that a mask band can take.
7649
 *
7650
 * @since GDAL 3.5.0
7651
 *
7652
 */
7653

7654
GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
×
7655
{
7656
    return GMVR_UNKNOWN;
×
7657
}
7658

7659
/************************************************************************/
7660
/*                    GetIndexColorTranslationTo()                      */
7661
/************************************************************************/
7662

7663
/**
7664
 * \brief Compute translation table for color tables.
7665
 *
7666
 * When the raster band has a palette index, it may be useful to compute
7667
 * the "translation" of this palette to the palette of another band.
7668
 * The translation tries to do exact matching first, and then approximate
7669
 * matching if no exact matching is possible.
7670
 * This method returns a table such that table[i] = j where i is an index
7671
 * of the 'this' rasterband and j the corresponding index for the reference
7672
 * rasterband.
7673
 *
7674
 * This method is thought as internal to GDAL and is used for drivers
7675
 * like RPFTOC.
7676
 *
7677
 * The implementation only supports 1-byte palette rasterbands.
7678
 *
7679
 * @param poReferenceBand the raster band
7680
 * @param pTranslationTable an already allocated translation table (at least 256
7681
 * bytes), or NULL to let the method allocate it
7682
 * @param pApproximateMatching a pointer to a flag that is set if the matching
7683
 *                              is approximate. May be NULL.
7684
 *
7685
 * @return a translation table if the two bands are palette index and that they
7686
 * do not match or NULL in other cases. The table must be freed with CPLFree if
7687
 * NULL was passed for pTranslationTable.
7688
 */
7689

7690
unsigned char *
7691
GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
4✔
7692
                                           unsigned char *pTranslationTable,
7693
                                           int *pApproximateMatching)
7694
{
7695
    if (poReferenceBand == nullptr)
4✔
7696
        return nullptr;
×
7697

7698
    // cppcheck-suppress knownConditionTrueFalse
7699
    if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
4✔
7700
        // cppcheck-suppress knownConditionTrueFalse
7701
        GetColorInterpretation() == GCI_PaletteIndex &&
4✔
7702
        poReferenceBand->GetRasterDataType() == GDT_Byte &&
12✔
7703
        GetRasterDataType() == GDT_Byte)
4✔
7704
    {
7705
        const GDALColorTable *srcColorTable = GetColorTable();
4✔
7706
        GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
4✔
7707
        if (srcColorTable != nullptr && destColorTable != nullptr)
4✔
7708
        {
7709
            const int nEntries = srcColorTable->GetColorEntryCount();
4✔
7710
            const int nRefEntries = destColorTable->GetColorEntryCount();
4✔
7711

7712
            int bHasNoDataValueSrc = FALSE;
4✔
7713
            double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
4✔
7714
            if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
4✔
7715
                  dfNoDataValueSrc <= 255 &&
3✔
7716
                  dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
3✔
7717
                bHasNoDataValueSrc = FALSE;
1✔
7718
            const int noDataValueSrc =
4✔
7719
                bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
4✔
7720

7721
            int bHasNoDataValueRef = FALSE;
4✔
7722
            const double dfNoDataValueRef =
7723
                poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
4✔
7724
            if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
4✔
7725
                  dfNoDataValueRef <= 255 &&
2✔
7726
                  dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
2✔
7727
                bHasNoDataValueRef = FALSE;
2✔
7728
            const int noDataValueRef =
4✔
7729
                bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
4✔
7730

7731
            bool samePalette = false;
4✔
7732

7733
            if (pApproximateMatching)
4✔
7734
                *pApproximateMatching = FALSE;
2✔
7735

7736
            if (nEntries == nRefEntries &&
4✔
7737
                bHasNoDataValueSrc == bHasNoDataValueRef &&
3✔
7738
                (bHasNoDataValueSrc == FALSE ||
3✔
7739
                 noDataValueSrc == noDataValueRef))
7740
            {
7741
                samePalette = true;
3✔
7742
                for (int i = 0; i < nEntries; ++i)
693✔
7743
                {
7744
                    if (noDataValueSrc == i)
690✔
7745
                        continue;
3✔
7746
                    const GDALColorEntry *entry =
7747
                        srcColorTable->GetColorEntry(i);
687✔
7748
                    const GDALColorEntry *entryRef =
7749
                        destColorTable->GetColorEntry(i);
687✔
7750
                    if (entry->c1 != entryRef->c1 ||
687✔
7751
                        entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
687✔
7752
                    {
7753
                        samePalette = false;
×
7754
                    }
7755
                }
7756
            }
7757

7758
            if (!samePalette)
4✔
7759
            {
7760
                if (pTranslationTable == nullptr)
1✔
7761
                {
7762
                    pTranslationTable = static_cast<unsigned char *>(
7763
                        VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
1✔
7764
                    if (pTranslationTable == nullptr)
1✔
7765
                        return nullptr;
1✔
7766
                }
7767

7768
                // Trying to remap the product palette on the subdataset
7769
                // palette.
7770
                for (int i = 0; i < nEntries; ++i)
5✔
7771
                {
7772
                    if (bHasNoDataValueSrc && bHasNoDataValueRef &&
4✔
7773
                        noDataValueSrc == i)
7774
                        continue;
×
7775
                    const GDALColorEntry *entry =
7776
                        srcColorTable->GetColorEntry(i);
4✔
7777
                    bool bMatchFound = false;
4✔
7778
                    for (int j = 0; j < nRefEntries; ++j)
13✔
7779
                    {
7780
                        if (bHasNoDataValueRef && noDataValueRef == j)
10✔
7781
                            continue;
×
7782
                        const GDALColorEntry *entryRef =
7783
                            destColorTable->GetColorEntry(j);
10✔
7784
                        if (entry->c1 == entryRef->c1 &&
10✔
7785
                            entry->c2 == entryRef->c2 &&
2✔
7786
                            entry->c3 == entryRef->c3)
2✔
7787
                        {
7788
                            pTranslationTable[i] =
1✔
7789
                                static_cast<unsigned char>(j);
7790
                            bMatchFound = true;
1✔
7791
                            break;
1✔
7792
                        }
7793
                    }
7794
                    if (!bMatchFound)
4✔
7795
                    {
7796
                        // No exact match. Looking for closest color now.
7797
                        int best_j = 0;
3✔
7798
                        int best_distance = 0;
3✔
7799
                        if (pApproximateMatching)
3✔
7800
                            *pApproximateMatching = TRUE;
×
7801
                        for (int j = 0; j < nRefEntries; ++j)
12✔
7802
                        {
7803
                            const GDALColorEntry *entryRef =
7804
                                destColorTable->GetColorEntry(j);
9✔
7805
                            int distance = (entry->c1 - entryRef->c1) *
9✔
7806
                                               (entry->c1 - entryRef->c1) +
9✔
7807
                                           (entry->c2 - entryRef->c2) *
9✔
7808
                                               (entry->c2 - entryRef->c2) +
9✔
7809
                                           (entry->c3 - entryRef->c3) *
9✔
7810
                                               (entry->c3 - entryRef->c3);
9✔
7811
                            if (j == 0 || distance < best_distance)
9✔
7812
                            {
7813
                                best_j = j;
7✔
7814
                                best_distance = distance;
7✔
7815
                            }
7816
                        }
7817
                        pTranslationTable[i] =
3✔
7818
                            static_cast<unsigned char>(best_j);
7819
                    }
7820
                }
7821
                if (bHasNoDataValueRef && bHasNoDataValueSrc)
1✔
7822
                    pTranslationTable[noDataValueSrc] =
×
7823
                        static_cast<unsigned char>(noDataValueRef);
7824

7825
                return pTranslationTable;
1✔
7826
            }
7827
        }
7828
    }
7829
    return nullptr;
3✔
7830
}
7831

7832
/************************************************************************/
7833
/*                         SetFlushBlockErr()                           */
7834
/************************************************************************/
7835

7836
/**
7837
 * \brief Store that an error occurred while writing a dirty block.
7838
 *
7839
 * This function stores the fact that an error occurred while writing a dirty
7840
 * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
7841
 * flushed when the block cache get full, it is not convenient/possible to
7842
 * report that a dirty block could not be written correctly. This function
7843
 * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
7844
 * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
7845
 * places where the user can easily match the error with the relevant dataset.
7846
 */
7847

7848
void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
4✔
7849
{
7850
    eFlushBlockErr = eErr;
4✔
7851
}
4✔
7852

7853
/************************************************************************/
7854
/*                         IncDirtyBlocks()                             */
7855
/************************************************************************/
7856

7857
/**
7858
 * \brief Increment/decrement the number of dirty blocks
7859
 */
7860

7861
void GDALRasterBand::IncDirtyBlocks(int nInc)
488,693✔
7862
{
7863
    if (poBandBlockCache)
488,693✔
7864
        poBandBlockCache->IncDirtyBlocks(nInc);
488,709✔
7865
}
488,694✔
7866

7867
/************************************************************************/
7868
/*                            ReportError()                             */
7869
/************************************************************************/
7870

7871
#ifndef DOXYGEN_XML
7872
/**
7873
 * \brief Emits an error related to a raster band.
7874
 *
7875
 * This function is a wrapper for regular CPLError(). The only difference
7876
 * with CPLError() is that it prepends the error message with the dataset
7877
 * name and the band number.
7878
 *
7879
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
7880
 * @param err_no the error number (CPLE_*) from cpl_error.h.
7881
 * @param fmt a printf() style format string.  Any additional arguments
7882
 * will be treated as arguments to fill in this format in a manner
7883
 * similar to printf().
7884
 *
7885
 * @since GDAL 1.9.0
7886
 */
7887

7888
void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
2,440✔
7889
                                 const char *fmt, ...)
7890
{
7891
    va_list args;
7892

7893
    va_start(args, fmt);
2,440✔
7894

7895
    const char *pszDSName = poDS ? poDS->GetDescription() : "";
2,440✔
7896
    pszDSName = CPLGetFilename(pszDSName);
2,440✔
7897
    if (pszDSName[0] != '\0')
2,440✔
7898
    {
7899
        CPLError(eErrClass, err_no, "%s",
2,389✔
7900
                 CPLString()
4,778✔
7901
                     .Printf("%s, band %d: ", pszDSName, GetBand())
2,389✔
7902
                     .append(CPLString().vPrintf(fmt, args))
4,778✔
7903
                     .c_str());
7904
    }
7905
    else
7906
    {
7907
        CPLErrorV(eErrClass, err_no, fmt, args);
51✔
7908
    }
7909

7910
    va_end(args);
2,440✔
7911
}
2,440✔
7912
#endif
7913

7914
/************************************************************************/
7915
/*                           GetVirtualMemAuto()                        */
7916
/************************************************************************/
7917

7918
/** \brief Create a CPLVirtualMem object from a GDAL raster band object.
7919
 *
7920
 * Only supported on Linux and Unix systems with mmap() for now.
7921
 *
7922
 * This method allows creating a virtual memory object for a GDALRasterBand,
7923
 * that exposes the whole image data as a virtual array.
7924
 *
7925
 * The default implementation relies on GDALRasterBandGetVirtualMem(), but
7926
 * specialized implementation, such as for raw files, may also directly use
7927
 * mechanisms of the operating system to create a view of the underlying file
7928
 * into virtual memory ( CPLVirtualMemFileMapNew() )
7929
 *
7930
 * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
7931
 * offer a specialized implementation with direct file mapping, provided that
7932
 * some requirements are met :
7933
 *   - for all drivers, the dataset must be backed by a "real" file in the file
7934
 *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
7935
 *     must match the native ordering of the CPU.
7936
 *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
7937
 * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
7938
 * the file in sequential order, and be equally spaced (which is generally the
7939
 * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
7940
 * GDT_Int16/GDT_UInt16, 32 for GDT_Float32 and 64 for GDT_Float64)
7941
 *
7942
 * The pointer returned remains valid until CPLVirtualMemFree() is called.
7943
 * CPLVirtualMemFree() must be called before the raster band object is
7944
 * destroyed.
7945
 *
7946
 * If p is such a pointer and base_type the type matching
7947
 * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
7948
 * accessed with
7949
 * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
7950
 *
7951
 * This method is the same as the C GDALGetVirtualMemAuto() function.
7952
 *
7953
 * @param eRWFlag Either GF_Read to read the band, or GF_Write to
7954
 * read/write the band.
7955
 *
7956
 * @param pnPixelSpace Output parameter giving the byte offset from the start of
7957
 * one pixel value in the buffer to the start of the next pixel value within a
7958
 * scanline.
7959
 *
7960
 * @param pnLineSpace Output parameter giving the byte offset from the start of
7961
 * one scanline in the buffer to the start of the next.
7962
 *
7963
 * @param papszOptions NULL terminated list of options.
7964
 *                     If a specialized implementation exists, defining
7965
 * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
7966
 * used. On the contrary, starting with GDAL 2.2, defining
7967
 * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
7968
 * being used (thus only allowing efficient implementations to be used). When
7969
 * requiring or falling back to the default implementation, the following
7970
 *                     options are available : CACHE_SIZE (in bytes, defaults to
7971
 * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
7972
 * to FALSE)
7973
 *
7974
 * @return a virtual memory object that must be unreferenced by
7975
 * CPLVirtualMemFree(), or NULL in case of failure.
7976
 *
7977
 * @since GDAL 1.11
7978
 */
7979

7980
CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9✔
7981
                                                 int *pnPixelSpace,
7982
                                                 GIntBig *pnLineSpace,
7983
                                                 char **papszOptions)
7984
{
7985
    const char *pszImpl = CSLFetchNameValueDef(
9✔
7986
        papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
7987
    if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9✔
7988
        EQUAL(pszImpl, "FALSE"))
8✔
7989
    {
7990
        return nullptr;
1✔
7991
    }
7992

7993
    const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
8✔
7994
    const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
8✔
7995
    if (pnPixelSpace)
8✔
7996
        *pnPixelSpace = nPixelSpace;
8✔
7997
    if (pnLineSpace)
8✔
7998
        *pnLineSpace = nLineSpace;
8✔
7999
    const size_t nCacheSize =
8000
        atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
8✔
8001
    const size_t nPageSizeHint =
8002
        atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
8✔
8003
    const bool bSingleThreadUsage = CPLTestBool(
8✔
8004
        CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
8005
    return GDALRasterBandGetVirtualMem(
8✔
8006
        GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
8007
        nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
8008
        nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
8009
        papszOptions);
8✔
8010
}
8011

8012
/************************************************************************/
8013
/*                         GDALGetVirtualMemAuto()                      */
8014
/************************************************************************/
8015

8016
/**
8017
 * \brief Create a CPLVirtualMem object from a GDAL raster band object.
8018
 *
8019
 * @see GDALRasterBand::GetVirtualMemAuto()
8020
 */
8021

8022
CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
30✔
8023
                                     int *pnPixelSpace, GIntBig *pnLineSpace,
8024
                                     CSLConstList papszOptions)
8025
{
8026
    VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
30✔
8027

8028
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
30✔
8029

8030
    return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
30✔
8031
                                     const_cast<char **>(papszOptions));
30✔
8032
}
8033

8034
/************************************************************************/
8035
/*                        GDALGetDataCoverageStatus()                   */
8036
/************************************************************************/
8037

8038
/**
8039
 * \brief Get the coverage status of a sub-window of the raster.
8040
 *
8041
 * Returns whether a sub-window of the raster contains only data, only empty
8042
 * blocks or a mix of both. This function can be used to determine quickly
8043
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
8044
 * be sparse.
8045
 *
8046
 * Empty blocks are blocks that are generally not physically present in the
8047
 * file, and when read through GDAL, contain only pixels whose value is the
8048
 * nodata value when it is set, or whose value is 0 when the nodata value is
8049
 * not set.
8050
 *
8051
 * The query is done in an efficient way without reading the actual pixel
8052
 * values. If not possible, or not implemented at all by the driver,
8053
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
8054
 * be returned.
8055
 *
8056
 * The values that can be returned by the function are the following,
8057
 * potentially combined with the binary or operator :
8058
 * <ul>
8059
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
8060
 * GetDataCoverageStatus(). This flag should be returned together with
8061
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
8062
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
8063
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
8064
 * the queried window. This is typically identified by the concept of missing
8065
 * block in formats that supports it.
8066
 * </li>
8067
 * </ul>
8068
 *
8069
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
8070
 * should be interpreted more as hint of potential presence of data. For example
8071
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
8072
 * nodata value), instead of using the missing block mechanism,
8073
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
8074
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
8075
 *
8076
 * The nMaskFlagStop should be generally set to 0. It can be set to a
8077
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
8078
 * the function as soon as the computed mask matches the nMaskFlagStop. For
8079
 * example, you can issue a request on the whole raster with nMaskFlagStop =
8080
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
8081
 * the function will exit, so that you can potentially refine the requested area
8082
 * to find which particular region(s) have missing blocks.
8083
 *
8084
 * @see GDALRasterBand::GetDataCoverageStatus()
8085
 *
8086
 * @param hBand raster band
8087
 *
8088
 * @param nXOff The pixel offset to the top left corner of the region
8089
 * of the band to be queried. This would be zero to start from the left side.
8090
 *
8091
 * @param nYOff The line offset to the top left corner of the region
8092
 * of the band to be queried. This would be zero to start from the top.
8093
 *
8094
 * @param nXSize The width of the region of the band to be queried in pixels.
8095
 *
8096
 * @param nYSize The height of the region of the band to be queried in lines.
8097
 *
8098
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
8099
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8100
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
8101
 * as the computation of the coverage matches the mask, the computation will be
8102
 * stopped. *pdfDataPct will not be valid in that case.
8103
 *
8104
 * @param pdfDataPct Optional output parameter whose pointed value will be set
8105
 * to the (approximate) percentage in [0,100] of pixels in the queried
8106
 * sub-window that have valid values. The implementation might not always be
8107
 * able to compute it, in which case it will be set to a negative value.
8108
 *
8109
 * @return a binary-or'ed combination of possible values
8110
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8111
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
8112
 *
8113
 * @note Added in GDAL 2.2
8114
 */
8115

8116
int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
8✔
8117
                                          int nYOff, int nXSize, int nYSize,
8118
                                          int nMaskFlagStop, double *pdfDataPct)
8119
{
8120
    VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
8✔
8121
                      GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
8122

8123
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8✔
8124

8125
    return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
8✔
8126
                                         nMaskFlagStop, pdfDataPct);
8✔
8127
}
8128

8129
/************************************************************************/
8130
/*                          GetDataCoverageStatus()                     */
8131
/************************************************************************/
8132

8133
/**
8134
 * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
8135
 *                                           int nYOff,
8136
 *                                           int nXSize,
8137
 *                                           int nYSize,
8138
 *                                           int nMaskFlagStop,
8139
 *                                           double* pdfDataPct)
8140
 * \brief Get the coverage status of a sub-window of the raster.
8141
 *
8142
 * Returns whether a sub-window of the raster contains only data, only empty
8143
 * blocks or a mix of both. This function can be used to determine quickly
8144
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
8145
 * be sparse.
8146
 *
8147
 * Empty blocks are blocks that contain only pixels whose value is the nodata
8148
 * value when it is set, or whose value is 0 when the nodata value is not set.
8149
 *
8150
 * The query is done in an efficient way without reading the actual pixel
8151
 * values. If not possible, or not implemented at all by the driver,
8152
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
8153
 * be returned.
8154
 *
8155
 * The values that can be returned by the function are the following,
8156
 * potentially combined with the binary or operator :
8157
 * <ul>
8158
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
8159
 * GetDataCoverageStatus(). This flag should be returned together with
8160
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
8161
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
8162
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
8163
 * the queried window. This is typically identified by the concept of missing
8164
 * block in formats that supports it.
8165
 * </li>
8166
 * </ul>
8167
 *
8168
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
8169
 * should be interpreted more as hint of potential presence of data. For example
8170
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
8171
 * nodata value), instead of using the missing block mechanism,
8172
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
8173
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
8174
 *
8175
 * The nMaskFlagStop should be generally set to 0. It can be set to a
8176
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
8177
 * the function as soon as the computed mask matches the nMaskFlagStop. For
8178
 * example, you can issue a request on the whole raster with nMaskFlagStop =
8179
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
8180
 * the function will exit, so that you can potentially refine the requested area
8181
 * to find which particular region(s) have missing blocks.
8182
 *
8183
 * @see GDALGetDataCoverageStatus()
8184
 *
8185
 * @param nXOff The pixel offset to the top left corner of the region
8186
 * of the band to be queried. This would be zero to start from the left side.
8187
 *
8188
 * @param nYOff The line offset to the top left corner of the region
8189
 * of the band to be queried. This would be zero to start from the top.
8190
 *
8191
 * @param nXSize The width of the region of the band to be queried in pixels.
8192
 *
8193
 * @param nYSize The height of the region of the band to be queried in lines.
8194
 *
8195
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
8196
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8197
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
8198
 * as the computation of the coverage matches the mask, the computation will be
8199
 * stopped. *pdfDataPct will not be valid in that case.
8200
 *
8201
 * @param pdfDataPct Optional output parameter whose pointed value will be set
8202
 * to the (approximate) percentage in [0,100] of pixels in the queried
8203
 * sub-window that have valid values. The implementation might not always be
8204
 * able to compute it, in which case it will be set to a negative value.
8205
 *
8206
 * @return a binary-or'ed combination of possible values
8207
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8208
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
8209
 *
8210
 * @note Added in GDAL 2.2
8211
 */
8212

8213
/**
8214
 * \brief Get the coverage status of a sub-window of the raster.
8215
 *
8216
 * Returns whether a sub-window of the raster contains only data, only empty
8217
 * blocks or a mix of both. This function can be used to determine quickly
8218
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
8219
 * be sparse.
8220
 *
8221
 * Empty blocks are blocks that contain only pixels whose value is the nodata
8222
 * value when it is set, or whose value is 0 when the nodata value is not set.
8223
 *
8224
 * The query is done in an efficient way without reading the actual pixel
8225
 * values. If not possible, or not implemented at all by the driver,
8226
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
8227
 * be returned.
8228
 *
8229
 * The values that can be returned by the function are the following,
8230
 * potentially combined with the binary or operator :
8231
 * <ul>
8232
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
8233
 * GetDataCoverageStatus(). This flag should be returned together with
8234
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
8235
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
8236
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
8237
 * the queried window. This is typically identified by the concept of missing
8238
 * block in formats that supports it.
8239
 * </li>
8240
 * </ul>
8241
 *
8242
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
8243
 * should be interpreted more as hint of potential presence of data. For example
8244
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
8245
 * nodata value), instead of using the missing block mechanism,
8246
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
8247
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
8248
 *
8249
 * The nMaskFlagStop should be generally set to 0. It can be set to a
8250
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
8251
 * the function as soon as the computed mask matches the nMaskFlagStop. For
8252
 * example, you can issue a request on the whole raster with nMaskFlagStop =
8253
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
8254
 * the function will exit, so that you can potentially refine the requested area
8255
 * to find which particular region(s) have missing blocks.
8256
 *
8257
 * @see GDALGetDataCoverageStatus()
8258
 *
8259
 * @param nXOff The pixel offset to the top left corner of the region
8260
 * of the band to be queried. This would be zero to start from the left side.
8261
 *
8262
 * @param nYOff The line offset to the top left corner of the region
8263
 * of the band to be queried. This would be zero to start from the top.
8264
 *
8265
 * @param nXSize The width of the region of the band to be queried in pixels.
8266
 *
8267
 * @param nYSize The height of the region of the band to be queried in lines.
8268
 *
8269
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
8270
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8271
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
8272
 * as the computation of the coverage matches the mask, the computation will be
8273
 * stopped. *pdfDataPct will not be valid in that case.
8274
 *
8275
 * @param pdfDataPct Optional output parameter whose pointed value will be set
8276
 * to the (approximate) percentage in [0,100] of pixels in the queried
8277
 * sub-window that have valid values. The implementation might not always be
8278
 * able to compute it, in which case it will be set to a negative value.
8279
 *
8280
 * @return a binary-or'ed combination of possible values
8281
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
8282
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
8283
 *
8284
 * @note Added in GDAL 2.2
8285
 */
8286

8287
int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
1,349✔
8288
                                          int nYSize, int nMaskFlagStop,
8289
                                          double *pdfDataPct)
8290
{
8291
    if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
1,349✔
8292
        nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
1,349✔
8293
        nYOff + nYSize > nRasterYSize)
1,349✔
8294
    {
8295
        CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
×
8296
        if (pdfDataPct)
×
8297
            *pdfDataPct = 0.0;
×
8298
        return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
8299
               GDAL_DATA_COVERAGE_STATUS_EMPTY;
×
8300
    }
8301
    return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
1,349✔
8302
                                  pdfDataPct);
1,349✔
8303
}
8304

8305
/************************************************************************/
8306
/*                         IGetDataCoverageStatus()                     */
8307
/************************************************************************/
8308

8309
int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
342✔
8310
                                           int /*nXSize*/, int /*nYSize*/,
8311
                                           int /*nMaskFlagStop*/,
8312
                                           double *pdfDataPct)
8313
{
8314
    if (pdfDataPct != nullptr)
342✔
8315
        *pdfDataPct = 100.0;
×
8316
    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
8317
           GDAL_DATA_COVERAGE_STATUS_DATA;
342✔
8318
}
8319

8320
//! @cond Doxygen_Suppress
8321
/************************************************************************/
8322
/*                          EnterReadWrite()                            */
8323
/************************************************************************/
8324

8325
int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
5,749,500✔
8326
{
8327
    if (poDS != nullptr)
5,749,500✔
8328
        return poDS->EnterReadWrite(eRWFlag);
5,733,250✔
8329
    return FALSE;
16,247✔
8330
}
8331

8332
/************************************************************************/
8333
/*                         LeaveReadWrite()                             */
8334
/************************************************************************/
8335

8336
void GDALRasterBand::LeaveReadWrite()
594,206✔
8337
{
8338
    if (poDS != nullptr)
594,206✔
8339
        poDS->LeaveReadWrite();
594,211✔
8340
}
594,204✔
8341

8342
/************************************************************************/
8343
/*                           InitRWLock()                               */
8344
/************************************************************************/
8345

8346
void GDALRasterBand::InitRWLock()
3,618,850✔
8347
{
8348
    if (poDS != nullptr)
3,618,850✔
8349
        poDS->InitRWLock();
3,618,450✔
8350
}
3,618,850✔
8351

8352
//! @endcond
8353

8354
/**
8355
 * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char *
8356
 * pszDomain) \brief Set metadata.
8357
 *
8358
 * CAUTION: depending on the format, older values of the updated information
8359
 * might still be found in the file in a "ghost" state, even if no longer
8360
 * accessible through the GDAL API. This is for example the case of the GTiff
8361
 * format (this is not a exhaustive list)
8362
 *
8363
 * The C function GDALSetMetadata() does the same thing as this method.
8364
 *
8365
 * @param papszMetadata the metadata in name=value string list format to
8366
 * apply.
8367
 * @param pszDomain the domain of interest.  Use "" or NULL for the default
8368
 * domain.
8369
 * @return CE_None on success, CE_Failure on failure and CE_Warning if the
8370
 * metadata has been accepted, but is likely not maintained persistently
8371
 * by the underlying object between sessions.
8372
 */
8373

8374
/**
8375
 * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char *
8376
 * pszValue, const char * pszDomain) \brief Set single metadata item.
8377
 *
8378
 * CAUTION: depending on the format, older values of the updated information
8379
 * might still be found in the file in a "ghost" state, even if no longer
8380
 * accessible through the GDAL API. This is for example the case of the GTiff
8381
 * format (this is not a exhaustive list)
8382
 *
8383
 * The C function GDALSetMetadataItem() does the same thing as this method.
8384
 *
8385
 * @param pszName the key for the metadata item to fetch.
8386
 * @param pszValue the value to assign to the key.
8387
 * @param pszDomain the domain to set within, use NULL for the default domain.
8388
 *
8389
 * @return CE_None on success, or an error code on failure.
8390
 */
8391

8392
//! @cond Doxygen_Suppress
8393
/************************************************************************/
8394
/*                    EnablePixelTypeSignedByteWarning()                */
8395
/************************************************************************/
8396

8397
void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
18,765✔
8398
{
8399
    m_bEnablePixelTypeSignedByteWarning = b;
18,765✔
8400
}
18,765✔
8401

8402
void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
6,588✔
8403
{
8404
    GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
6,588✔
8405
}
6,588✔
8406

8407
//! @endcond
8408

8409
/************************************************************************/
8410
/*                           GetMetadataItem()                          */
8411
/************************************************************************/
8412

8413
const char *GDALRasterBand::GetMetadataItem(const char *pszName,
46,669✔
8414
                                            const char *pszDomain)
8415
{
8416
    // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
8417
    if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
46,669✔
8418
        pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
25,927✔
8419
        EQUAL(pszName, "PIXELTYPE"))
11,710✔
8420
    {
8421
        CPLError(CE_Warning, CPLE_AppDefined,
2✔
8422
                 "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
8423
                 "used to signal signed 8-bit raster. Change your code to "
8424
                 "test for the new GDT_Int8 data type instead.");
8425
    }
8426
    return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
46,669✔
8427
}
8428

8429
/************************************************************************/
8430
/*                     GDALMDArrayFromRasterBand                        */
8431
/************************************************************************/
8432

8433
class GDALMDArrayFromRasterBand final : public GDALMDArray
8434
{
8435
    CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
8436

8437
    GDALDataset *m_poDS;
8438
    GDALRasterBand *m_poBand;
8439
    GDALExtendedDataType m_dt;
8440
    std::vector<std::shared_ptr<GDALDimension>> m_dims{};
8441
    std::string m_osUnit;
8442
    std::vector<GByte> m_pabyNoData{};
8443
    std::shared_ptr<GDALMDArray> m_varX{};
8444
    std::shared_ptr<GDALMDArray> m_varY{};
8445
    std::string m_osFilename{};
8446

8447
    bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
8448
                   const size_t *count, const GInt64 *arrayStep,
8449
                   const GPtrDiff_t *bufferStride,
8450
                   const GDALExtendedDataType &bufferDataType,
8451
                   void *pBuffer) const;
8452

8453
  protected:
8454
    GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
23✔
8455
        : GDALAbstractMDArray(std::string(),
46✔
8456
                              std::string(poDS->GetDescription()) +
46✔
8457
                                  CPLSPrintf(" band %d", poBand->GetBand())),
8458
          GDALMDArray(std::string(),
46✔
8459
                      std::string(poDS->GetDescription()) +
46✔
8460
                          CPLSPrintf(" band %d", poBand->GetBand())),
8461
          m_poDS(poDS), m_poBand(poBand),
8462
          m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
8463
          m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
115✔
8464
    {
8465
        m_poDS->Reference();
23✔
8466

8467
        int bHasNoData = false;
23✔
8468
        if (m_poBand->GetRasterDataType() == GDT_Int64)
23✔
8469
        {
8470
            const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
×
8471
            if (bHasNoData)
×
8472
            {
8473
                m_pabyNoData.resize(m_dt.GetSize());
×
8474
                GDALCopyWords(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
×
8475
                              m_dt.GetNumericDataType(), 0, 1);
8476
            }
8477
        }
8478
        else if (m_poBand->GetRasterDataType() == GDT_UInt64)
23✔
8479
        {
8480
            const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
×
8481
            if (bHasNoData)
×
8482
            {
8483
                m_pabyNoData.resize(m_dt.GetSize());
×
8484
                GDALCopyWords(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
×
8485
                              m_dt.GetNumericDataType(), 0, 1);
8486
            }
8487
        }
8488
        else
8489
        {
8490
            const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
23✔
8491
            if (bHasNoData)
23✔
8492
            {
8493
                m_pabyNoData.resize(m_dt.GetSize());
1✔
8494
                GDALCopyWords(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
1✔
8495
                              m_dt.GetNumericDataType(), 0, 1);
8496
            }
8497
        }
8498

8499
        const int nXSize = poBand->GetXSize();
23✔
8500
        const int nYSize = poBand->GetYSize();
23✔
8501

8502
        auto poSRS = m_poDS->GetSpatialRef();
23✔
8503
        std::string osTypeY;
46✔
8504
        std::string osTypeX;
46✔
8505
        std::string osDirectionY;
46✔
8506
        std::string osDirectionX;
46✔
8507
        if (poSRS && poSRS->GetAxesCount() == 2)
23✔
8508
        {
8509
            const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
21✔
8510
            OGRAxisOrientation eOrientation1 = OAO_Other;
21✔
8511
            poSRS->GetAxis(nullptr, 0, &eOrientation1);
21✔
8512
            OGRAxisOrientation eOrientation2 = OAO_Other;
21✔
8513
            poSRS->GetAxis(nullptr, 1, &eOrientation2);
21✔
8514
            if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
21✔
8515
            {
8516
                if (mapping == std::vector<int>{1, 2})
5✔
8517
                {
8518
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
5✔
8519
                    osDirectionY = "NORTH";
5✔
8520
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
5✔
8521
                    osDirectionX = "EAST";
5✔
8522
                }
8523
            }
8524
            else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
16✔
8525
            {
8526
                if (mapping == std::vector<int>{2, 1})
16✔
8527
                {
8528
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
16✔
8529
                    osDirectionY = "NORTH";
16✔
8530
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
16✔
8531
                    osDirectionX = "EAST";
16✔
8532
                }
8533
            }
8534
        }
8535

8536
        m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
115✔
8537
                      "/", "Y", osTypeY, osDirectionY, nYSize),
8538
                  std::make_shared<GDALDimensionWeakIndexingVar>(
46✔
8539
                      "/", "X", osTypeX, osDirectionX, nXSize)};
69✔
8540

8541
        double adfGeoTransform[6];
8542
        if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
23✔
8543
            adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
23✔
8544
        {
8545
            m_varX = GDALMDArrayRegularlySpaced::Create(
44✔
8546
                "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
22✔
8547
                0.5);
22✔
8548
            m_dims[1]->SetIndexingVariable(m_varX);
22✔
8549

8550
            m_varY = GDALMDArrayRegularlySpaced::Create(
44✔
8551
                "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
22✔
8552
                0.5);
22✔
8553
            m_dims[0]->SetIndexingVariable(m_varY);
22✔
8554
        }
8555
    }
23✔
8556

8557
    bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
32✔
8558
               const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
8559
               const GDALExtendedDataType &bufferDataType,
8560
               void *pDstBuffer) const override
8561
    {
8562
        return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
32✔
8563
                         bufferDataType, pDstBuffer);
32✔
8564
    }
8565

8566
    bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
1✔
8567
                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
8568
                const GDALExtendedDataType &bufferDataType,
8569
                const void *pSrcBuffer) override
8570
    {
8571
        return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
1✔
8572
                         bufferStride, bufferDataType,
8573
                         const_cast<void *>(pSrcBuffer));
1✔
8574
    }
8575

8576
  public:
8577
    ~GDALMDArrayFromRasterBand()
46✔
8578
    {
23✔
8579
        m_poDS->ReleaseRef();
23✔
8580
    }
46✔
8581

8582
    static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
23✔
8583
                                               GDALRasterBand *poBand)
8584
    {
8585
        auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
8586
            new GDALMDArrayFromRasterBand(poDS, poBand)));
46✔
8587
        array->SetSelf(array);
23✔
8588
        return array;
46✔
8589
    }
8590

8591
    bool IsWritable() const override
2✔
8592
    {
8593
        return m_poDS->GetAccess() == GA_Update;
2✔
8594
    }
8595

8596
    const std::string &GetFilename() const override
97✔
8597
    {
8598
        return m_osFilename;
97✔
8599
    }
8600

8601
    const std::vector<std::shared_ptr<GDALDimension>> &
8602
    GetDimensions() const override
300✔
8603
    {
8604
        return m_dims;
300✔
8605
    }
8606

8607
    const GDALExtendedDataType &GetDataType() const override
139✔
8608
    {
8609
        return m_dt;
139✔
8610
    }
8611

8612
    const std::string &GetUnit() const override
3✔
8613
    {
8614
        return m_osUnit;
3✔
8615
    }
8616

8617
    const void *GetRawNoDataValue() const override
29✔
8618
    {
8619
        return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
29✔
8620
    }
8621

8622
    double GetOffset(bool *pbHasOffset,
2✔
8623
                     GDALDataType *peStorageType) const override
8624
    {
8625
        int bHasOffset = false;
2✔
8626
        double dfRes = m_poBand->GetOffset(&bHasOffset);
2✔
8627
        if (pbHasOffset)
2✔
8628
            *pbHasOffset = CPL_TO_BOOL(bHasOffset);
2✔
8629
        if (peStorageType)
2✔
8630
            *peStorageType = GDT_Unknown;
1✔
8631
        return dfRes;
2✔
8632
    }
8633

8634
    double GetScale(bool *pbHasScale,
2✔
8635
                    GDALDataType *peStorageType) const override
8636
    {
8637
        int bHasScale = false;
2✔
8638
        double dfRes = m_poBand->GetScale(&bHasScale);
2✔
8639
        if (pbHasScale)
2✔
8640
            *pbHasScale = CPL_TO_BOOL(bHasScale);
2✔
8641
        if (peStorageType)
2✔
8642
            *peStorageType = GDT_Unknown;
1✔
8643
        return dfRes;
2✔
8644
    }
8645

8646
    std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
84✔
8647
    {
8648
        auto poSrcSRS = m_poDS->GetSpatialRef();
84✔
8649
        if (!poSrcSRS)
84✔
8650
            return nullptr;
2✔
8651
        auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
164✔
8652

8653
        auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
164✔
8654
        constexpr int iYDim = 0;
82✔
8655
        constexpr int iXDim = 1;
82✔
8656
        for (auto &m : axisMapping)
246✔
8657
        {
8658
            if (m == 1)
164✔
8659
                m = iXDim + 1;
82✔
8660
            else if (m == 2)
82✔
8661
                m = iYDim + 1;
82✔
8662
            else
8663
                m = 0;
×
8664
        }
8665
        poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
82✔
8666
        return poSRS;
82✔
8667
    }
8668

8669
    std::vector<GUInt64> GetBlockSize() const override
29✔
8670
    {
8671
        int nBlockXSize = 0;
29✔
8672
        int nBlockYSize = 0;
29✔
8673
        m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
29✔
8674
        return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
29✔
8675
                                    static_cast<GUInt64>(nBlockXSize)};
29✔
8676
    }
8677

8678
    class MDIAsAttribute : public GDALAttribute
8679
    {
8680
        std::vector<std::shared_ptr<GDALDimension>> m_dims{};
8681
        const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
8682
        std::string m_osValue;
8683

8684
      public:
8685
        MDIAsAttribute(const std::string &name, const std::string &value)
2✔
8686
            : GDALAbstractMDArray(std::string(), name),
2✔
8687
              GDALAttribute(std::string(), name), m_osValue(value)
4✔
8688
        {
8689
        }
2✔
8690

8691
        const std::vector<std::shared_ptr<GDALDimension>> &
8692
        GetDimensions() const override
3✔
8693
        {
8694
            return m_dims;
3✔
8695
        }
8696

8697
        const GDALExtendedDataType &GetDataType() const override
2✔
8698
        {
8699
            return m_dt;
2✔
8700
        }
8701

8702
        bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
1✔
8703
                   const GPtrDiff_t *,
8704
                   const GDALExtendedDataType &bufferDataType,
8705
                   void *pDstBuffer) const override
8706
        {
8707
            const char *pszStr = m_osValue.c_str();
1✔
8708
            GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
1✔
8709
                                            bufferDataType);
8710
            return true;
1✔
8711
        }
8712
    };
8713

8714
    std::vector<std::shared_ptr<GDALAttribute>>
8715
    GetAttributes(CSLConstList) const override
14✔
8716
    {
8717
        std::vector<std::shared_ptr<GDALAttribute>> res;
14✔
8718
        auto papszMD = m_poBand->GetMetadata();
14✔
8719
        for (auto iter = papszMD; iter && iter[0]; ++iter)
16✔
8720
        {
8721
            char *pszKey = nullptr;
2✔
8722
            const char *pszValue = CPLParseNameValue(*iter, &pszKey);
2✔
8723
            if (pszKey && pszValue)
2✔
8724
            {
8725
                res.emplace_back(
8726
                    std::make_shared<MDIAsAttribute>(pszKey, pszValue));
2✔
8727
            }
8728
            CPLFree(pszKey);
2✔
8729
        }
8730
        return res;
14✔
8731
    }
8732
};
8733

8734
/************************************************************************/
8735
/*                            ReadWrite()                               */
8736
/************************************************************************/
8737

8738
bool GDALMDArrayFromRasterBand::ReadWrite(
33✔
8739
    GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
8740
    const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
8741
    const GDALExtendedDataType &bufferDataType, void *pBuffer) const
8742
{
8743
    constexpr size_t iDimX = 1;
33✔
8744
    constexpr size_t iDimY = 0;
33✔
8745
    return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
33✔
8746
                                  arrayStartIdx, count, arrayStep, bufferStride,
8747
                                  bufferDataType, pBuffer);
33✔
8748
}
8749

8750
/************************************************************************/
8751
/*                       GDALMDRasterIOFromBand()                       */
8752
/************************************************************************/
8753

8754
bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
66✔
8755
                            size_t iDimX, size_t iDimY,
8756
                            const GUInt64 *arrayStartIdx, const size_t *count,
8757
                            const GInt64 *arrayStep,
8758
                            const GPtrDiff_t *bufferStride,
8759
                            const GDALExtendedDataType &bufferDataType,
8760
                            void *pBuffer)
8761
{
8762
    const auto eDT(bufferDataType.GetNumericDataType());
66✔
8763
    const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
66✔
8764
    const int nX =
66✔
8765
        arrayStep[iDimX] > 0
66✔
8766
            ? static_cast<int>(arrayStartIdx[iDimX])
66✔
8767
            : static_cast<int>(arrayStartIdx[iDimX] -
2✔
8768
                               (count[iDimX] - 1) * -arrayStep[iDimX]);
2✔
8769
    const int nY =
66✔
8770
        arrayStep[iDimY] > 0
66✔
8771
            ? static_cast<int>(arrayStartIdx[iDimY])
66✔
8772
            : static_cast<int>(arrayStartIdx[iDimY] -
2✔
8773
                               (count[iDimY] - 1) * -arrayStep[iDimY]);
2✔
8774
    const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
66✔
8775
    const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
66✔
8776
    GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
66✔
8777
    int nStrideXSign = 1;
66✔
8778
    if (arrayStep[iDimX] < 0)
66✔
8779
    {
8780
        pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
2✔
8781
        nStrideXSign = -1;
2✔
8782
    }
8783
    int nStrideYSign = 1;
66✔
8784
    if (arrayStep[iDimY] < 0)
66✔
8785
    {
8786
        pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
2✔
8787
        nStrideYSign = -1;
2✔
8788
    }
8789

8790
    return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
132✔
8791
                            static_cast<int>(count[iDimX]),
66✔
8792
                            static_cast<int>(count[iDimY]), eDT,
66✔
8793
                            static_cast<GSpacing>(
8794
                                nStrideXSign * bufferStride[iDimX] * nDTSize),
66✔
8795
                            static_cast<GSpacing>(
8796
                                nStrideYSign * bufferStride[iDimY] * nDTSize),
66✔
8797
                            nullptr) == CE_None;
66✔
8798
}
8799

8800
/************************************************************************/
8801
/*                            AsMDArray()                               */
8802
/************************************************************************/
8803

8804
/** Return a view of this raster band as a 2D multidimensional GDALMDArray.
8805
 *
8806
 * The band must be linked to a GDALDataset. If this dataset is not already
8807
 * marked as shared, it will be, so that the returned array holds a reference
8808
 * to it.
8809
 *
8810
 * If the dataset has a geotransform attached, the X and Y dimensions of the
8811
 * returned array will have an associated indexing variable.
8812
 *
8813
 * This is the same as the C function GDALRasterBandAsMDArray().
8814
 *
8815
 * The "reverse" method is GDALMDArray::AsClassicDataset().
8816
 *
8817
 * @return a new array, or nullptr.
8818
 *
8819
 * @since GDAL 3.1
8820
 */
8821
std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
23✔
8822
{
8823
    if (!poDS)
23✔
8824
    {
8825
        CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
×
8826
        return nullptr;
×
8827
    }
8828
    if (!poDS->GetShared())
23✔
8829
    {
8830
        poDS->MarkAsShared();
23✔
8831
    }
8832
    return GDALMDArrayFromRasterBand::Create(
8833
        poDS, const_cast<GDALRasterBand *>(this));
23✔
8834
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc