Coverage Report

Created: 2025-06-13 06:29

/src/gdal/gcore/rawdataset.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  Generic Raw Binary Driver
4
 * Purpose:  Implementation of RawDataset and RawRasterBand classes.
5
 * Author:   Frank Warmerdam, warmerda@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1999, Frank Warmerdam
9
 * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "cpl_vax.h"
16
#include "rawdataset.h"
17
18
#include <climits>
19
#include <cmath>
20
#include <cstddef>
21
#include <cstdint>
22
#include <cstdlib>
23
#include <cstring>
24
#if HAVE_FCNTL_H
25
#include <fcntl.h>
26
#endif
27
#include <algorithm>
28
#include <limits>
29
#include <vector>
30
31
#include "cpl_conv.h"
32
#include "cpl_error.h"
33
#include "cpl_progress.h"
34
#include "cpl_string.h"
35
#include "cpl_virtualmem.h"
36
#include "cpl_vsi.h"
37
#include "cpl_safemaths.hpp"
38
#include "gdal.h"
39
#include "gdal_priv.h"
40
41
/************************************************************************/
42
/*                           RawRasterBand()                            */
43
/************************************************************************/
44
45
RawRasterBand::RawRasterBand(GDALDataset *poDSIn, int nBandIn,
46
                             VSILFILE *fpRawLIn, vsi_l_offset nImgOffsetIn,
47
                             int nPixelOffsetIn, int nLineOffsetIn,
48
                             GDALDataType eDataTypeIn, int bNativeOrderIn,
49
                             OwnFP bOwnsFPIn)
50
0
    : RawRasterBand(poDSIn, nBandIn, fpRawLIn, nImgOffsetIn, nPixelOffsetIn,
51
0
                    nLineOffsetIn, eDataTypeIn,
52
0
#ifdef CPL_LSB
53
0
                    bNativeOrderIn ? ByteOrder::ORDER_LITTLE_ENDIAN
54
0
                                   : ByteOrder::ORDER_BIG_ENDIAN,
55
#else
56
                    bNativeOrderIn ? ByteOrder::ORDER_BIG_ENDIAN
57
                                   : ByteOrder::ORDER_LITTLE_ENDIAN,
58
#endif
59
0
                    bOwnsFPIn)
60
0
{
61
0
}
62
63
/************************************************************************/
64
/*                           RawRasterBand()                            */
65
/************************************************************************/
66
67
RawRasterBand::RawRasterBand(GDALDataset *poDSIn, int nBandIn,
68
                             VSILFILE *fpRawLIn, vsi_l_offset nImgOffsetIn,
69
                             int nPixelOffsetIn, int nLineOffsetIn,
70
                             GDALDataType eDataTypeIn, ByteOrder eByteOrderIn,
71
                             OwnFP bOwnsFPIn)
72
0
    : fpRawL(fpRawLIn), nImgOffset(nImgOffsetIn), nPixelOffset(nPixelOffsetIn),
73
0
      nLineOffset(nLineOffsetIn), eByteOrder(eByteOrderIn),
74
0
      bOwnsFP(bOwnsFPIn == OwnFP::YES)
75
0
{
76
0
    poDS = poDSIn;
77
0
    nBand = nBandIn;
78
0
    eDataType = eDataTypeIn;
79
0
    nRasterXSize = poDSIn->GetRasterXSize();
80
0
    nRasterYSize = poDSIn->GetRasterYSize();
81
82
0
    CPLDebug("GDALRaw",
83
0
             "RawRasterBand(%p,%d,%p,\n"
84
0
             "              Off=%d,PixOff=%d,LineOff=%d,%s,%d)",
85
0
             poDS, nBand, fpRawL, static_cast<unsigned int>(nImgOffset),
86
0
             nPixelOffset, nLineOffset, GDALGetDataTypeName(eDataType),
87
0
             static_cast<int>(eByteOrder));
88
89
    // Treat one scanline as the block size.
90
0
    nBlockXSize = poDS->GetRasterXSize();
91
0
    nBlockYSize = 1;
92
93
    // Initialize other fields, and setup the line buffer.
94
0
    Initialize();
95
0
}
96
97
/************************************************************************/
98
/*                          RawRasterBand::Create()                     */
99
/************************************************************************/
100
101
std::unique_ptr<RawRasterBand>
102
RawRasterBand::Create(GDALDataset *poDSIn, int nBandIn, VSILFILE *fpRawLIn,
103
                      vsi_l_offset nImgOffsetIn, int nPixelOffsetIn,
104
                      int nLineOffsetIn, GDALDataType eDataTypeIn,
105
                      ByteOrder eByteOrderIn, OwnFP bOwnsFPIn)
106
0
{
107
0
    auto poBand = std::make_unique<RawRasterBand>(
108
0
        poDSIn, nBandIn, fpRawLIn, nImgOffsetIn, nPixelOffsetIn, nLineOffsetIn,
109
0
        eDataTypeIn, eByteOrderIn, bOwnsFPIn);
110
0
    if (!poBand->IsValid())
111
0
        return nullptr;
112
0
    return poBand;
113
0
}
114
115
/************************************************************************/
116
/*                           RawRasterBand()                            */
117
/************************************************************************/
118
119
RawRasterBand::RawRasterBand(VSILFILE *fpRawLIn, vsi_l_offset nImgOffsetIn,
120
                             int nPixelOffsetIn, int nLineOffsetIn,
121
                             GDALDataType eDataTypeIn, int bNativeOrderIn,
122
                             int nXSize, int nYSize, OwnFP bOwnsFPIn)
123
0
    : RawRasterBand(fpRawLIn, nImgOffsetIn, nPixelOffsetIn, nLineOffsetIn,
124
0
                    eDataTypeIn,
125
0
#ifdef CPL_LSB
126
0
                    bNativeOrderIn ? ByteOrder::ORDER_LITTLE_ENDIAN
127
0
                                   : ByteOrder::ORDER_BIG_ENDIAN,
128
#else
129
                    bNativeOrderIn ? ByteOrder::ORDER_BIG_ENDIAN
130
                                   : ByteOrder::ORDER_LITTLE_ENDIAN,
131
#endif
132
0
                    nXSize, nYSize, bOwnsFPIn)
133
0
{
134
0
}
135
136
/************************************************************************/
137
/*                          RawRasterBand::Create()                     */
138
/************************************************************************/
139
140
std::unique_ptr<RawRasterBand>
141
RawRasterBand::Create(VSILFILE *fpRawIn, vsi_l_offset nImgOffsetIn,
142
                      int nPixelOffsetIn, int nLineOffsetIn,
143
                      GDALDataType eDataTypeIn, ByteOrder eByteOrderIn,
144
                      int nXSizeIn, int nYSizeIn, OwnFP bOwnsFPIn)
145
0
{
146
0
    auto poBand = std::make_unique<RawRasterBand>(
147
0
        fpRawIn, nImgOffsetIn, nPixelOffsetIn, nLineOffsetIn, eDataTypeIn,
148
0
        eByteOrderIn, nXSizeIn, nYSizeIn, bOwnsFPIn);
149
0
    if (!poBand->IsValid())
150
0
        return nullptr;
151
0
    return poBand;
152
0
}
153
154
/************************************************************************/
155
/*                           RawRasterBand()                            */
156
/************************************************************************/
157
158
RawRasterBand::RawRasterBand(VSILFILE *fpRawLIn, vsi_l_offset nImgOffsetIn,
159
                             int nPixelOffsetIn, int nLineOffsetIn,
160
                             GDALDataType eDataTypeIn, ByteOrder eByteOrderIn,
161
                             int nXSize, int nYSize, OwnFP bOwnsFPIn)
162
0
    : fpRawL(fpRawLIn), nImgOffset(nImgOffsetIn), nPixelOffset(nPixelOffsetIn),
163
0
      nLineOffset(nLineOffsetIn), eByteOrder(eByteOrderIn),
164
0
      bOwnsFP(bOwnsFPIn == OwnFP::YES)
165
0
{
166
0
    poDS = nullptr;
167
0
    nBand = 1;
168
0
    eDataType = eDataTypeIn;
169
170
0
    CPLDebug("GDALRaw",
171
0
             "RawRasterBand(floating,Off=%d,PixOff=%d,LineOff=%d,%s,%d)",
172
0
             static_cast<unsigned int>(nImgOffset), nPixelOffset, nLineOffset,
173
0
             GDALGetDataTypeName(eDataType), static_cast<int>(eByteOrder));
174
175
    // Treat one scanline as the block size.
176
0
    nBlockXSize = nXSize;
177
0
    nBlockYSize = 1;
178
0
    nRasterXSize = nXSize;
179
0
    nRasterYSize = nYSize;
180
0
    if (!GDALCheckDatasetDimensions(nXSize, nYSize))
181
0
    {
182
0
        return;
183
0
    }
184
185
    // Initialize other fields, and setup the line buffer.
186
0
    Initialize();
187
0
}
188
189
/************************************************************************/
190
/*                             Initialize()                             */
191
/************************************************************************/
192
193
void RawRasterBand::Initialize()
194
195
0
{
196
0
    vsi_l_offset nSmallestOffset = nImgOffset;
197
0
    vsi_l_offset nLargestOffset = nImgOffset;
198
0
    if (nLineOffset < 0)
199
0
    {
200
0
        const auto nDelta =
201
0
            static_cast<vsi_l_offset>(-static_cast<GIntBig>(nLineOffset)) *
202
0
            (nRasterYSize - 1);
203
0
        if (nDelta > nImgOffset)
204
0
        {
205
0
            CPLError(CE_Failure, CPLE_AppDefined,
206
0
                     "Inconsistent nLineOffset, nRasterYSize and nImgOffset");
207
0
            return;
208
0
        }
209
0
        nSmallestOffset -= nDelta;
210
0
    }
211
0
    else
212
0
    {
213
0
        if (nImgOffset >
214
0
            std::numeric_limits<vsi_l_offset>::max() -
215
0
                static_cast<vsi_l_offset>(nLineOffset) * (nRasterYSize - 1))
216
0
        {
217
0
            CPLError(CE_Failure, CPLE_AppDefined,
218
0
                     "Inconsistent nLineOffset, nRasterYSize and nImgOffset");
219
0
            return;
220
0
        }
221
0
        nLargestOffset +=
222
0
            static_cast<vsi_l_offset>(nLineOffset) * (nRasterYSize - 1);
223
0
    }
224
0
    if (nPixelOffset < 0)
225
0
    {
226
0
        if (static_cast<vsi_l_offset>(-static_cast<GIntBig>(nPixelOffset)) *
227
0
                (nRasterXSize - 1) >
228
0
            nSmallestOffset)
229
0
        {
230
0
            CPLError(CE_Failure, CPLE_AppDefined,
231
0
                     "Inconsistent nPixelOffset, nRasterXSize and nImgOffset");
232
0
            return;
233
0
        }
234
0
    }
235
0
    else
236
0
    {
237
0
        if (nLargestOffset >
238
0
            std::numeric_limits<vsi_l_offset>::max() -
239
0
                static_cast<vsi_l_offset>(nPixelOffset) * (nRasterXSize - 1))
240
0
        {
241
0
            CPLError(CE_Failure, CPLE_AppDefined,
242
0
                     "Inconsistent nPixelOffset, nRasterXSize and nImgOffset");
243
0
            return;
244
0
        }
245
0
        nLargestOffset +=
246
0
            static_cast<vsi_l_offset>(nPixelOffset) * (nRasterXSize - 1);
247
0
    }
248
0
    if (nLargestOffset > static_cast<vsi_l_offset>(GINTBIG_MAX))
249
0
    {
250
0
        CPLError(CE_Failure, CPLE_AppDefined, "Too big largest offset");
251
0
        return;
252
0
    }
253
254
0
    const int nDTSize = GDALGetDataTypeSizeBytes(GetRasterDataType());
255
256
    // Allocate working scanline.
257
0
    const bool bIsBIP = IsBIP();
258
0
    if (bIsBIP)
259
0
    {
260
0
        if (nBand == 1)
261
0
        {
262
0
            nLineSize = nPixelOffset * nBlockXSize;
263
0
            pLineBuffer = VSIMalloc(nLineSize);
264
0
        }
265
0
        else
266
0
        {
267
            // Band > 1 : share the same buffer as band 1
268
0
            pLineBuffer = nullptr;
269
0
            const auto poFirstBand =
270
0
                cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(1));
271
0
            if (poFirstBand->pLineBuffer != nullptr)
272
0
                pLineStart = static_cast<char *>(poFirstBand->pLineBuffer) +
273
0
                             (nBand - 1) * nDTSize;
274
0
            return;
275
0
        }
276
0
    }
277
0
    else if (nBlockXSize <= 0 ||
278
0
             (nBlockXSize > 1 &&
279
0
              std::abs(nPixelOffset) >
280
0
                  std::numeric_limits<int>::max() / (nBlockXSize - 1)) ||
281
0
             std::abs(nPixelOffset) * (nBlockXSize - 1) >
282
0
                 std::numeric_limits<int>::max() - nDTSize)
283
0
    {
284
0
        nLineSize = 0;
285
0
        pLineBuffer = nullptr;
286
0
    }
287
0
    else
288
0
    {
289
0
        nLineSize = std::abs(nPixelOffset) * (nBlockXSize - 1) + nDTSize;
290
0
        pLineBuffer = VSIMalloc(nLineSize);
291
0
    }
292
293
0
    if (pLineBuffer == nullptr)
294
0
    {
295
0
        nLineSize = 0;
296
0
        CPLError(CE_Failure, CPLE_AppDefined,
297
0
                 "Could not allocate line buffer: "
298
0
                 "nPixelOffset=%d, nBlockXSize=%d",
299
0
                 nPixelOffset, nBlockXSize);
300
0
        return;
301
0
    }
302
303
0
    if (nPixelOffset >= 0)
304
0
        pLineStart = pLineBuffer;
305
0
    else
306
0
        pLineStart = static_cast<char *>(pLineBuffer) +
307
0
                     static_cast<std::ptrdiff_t>(std::abs(nPixelOffset)) *
308
0
                         (nBlockXSize - 1);
309
0
}
310
311
/************************************************************************/
312
/*                           ~RawRasterBand()                           */
313
/************************************************************************/
314
315
RawRasterBand::~RawRasterBand()
316
317
0
{
318
0
    if (poCT)
319
0
        delete poCT;
320
321
0
    CSLDestroy(papszCategoryNames);
322
323
0
    RawRasterBand::FlushCache(true);
324
325
0
    if (bOwnsFP)
326
0
    {
327
0
        if (VSIFCloseL(fpRawL) != 0)
328
0
        {
329
0
            CPLError(CE_Failure, CPLE_FileIO, "I/O error");
330
0
        }
331
0
    }
332
333
0
    CPLFree(pLineBuffer);
334
0
}
335
336
/************************************************************************/
337
/*                              IsBIP()                                 */
338
/************************************************************************/
339
340
bool RawRasterBand::IsBIP() const
341
0
{
342
0
    const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
343
0
    const bool bIsRawDataset = dynamic_cast<RawDataset *>(poDS) != nullptr;
344
0
    if (bIsRawDataset && nPixelOffset > nDTSize &&
345
0
        nLineOffset == static_cast<int64_t>(nPixelOffset) * nRasterXSize)
346
0
    {
347
0
        if (nBand == 1)
348
0
        {
349
0
            return true;
350
0
        }
351
0
        const auto poFirstBand =
352
0
            dynamic_cast<RawRasterBand *>(poDS->GetRasterBand(1));
353
0
        if (poFirstBand && eDataType == poFirstBand->eDataType &&
354
0
            eByteOrder == poFirstBand->eByteOrder &&
355
0
            nPixelOffset == poFirstBand->nPixelOffset &&
356
0
            nLineOffset == poFirstBand->nLineOffset &&
357
0
            nImgOffset == poFirstBand->nImgOffset +
358
0
                              static_cast<vsi_l_offset>(nBand - 1) * nDTSize)
359
0
        {
360
0
            return true;
361
0
        }
362
0
    }
363
0
    return false;
364
0
}
365
366
/************************************************************************/
367
/*                             SetAccess()                              */
368
/************************************************************************/
369
370
void RawRasterBand::SetAccess(GDALAccess eAccessIn)
371
0
{
372
0
    eAccess = eAccessIn;
373
0
}
374
375
/************************************************************************/
376
/*                             FlushCache()                             */
377
/*                                                                      */
378
/*      We override this so we have the opportunity to call             */
379
/*      fflush().  We don't want to do this all the time in the         */
380
/*      write block function as it is kind of expensive.                */
381
/************************************************************************/
382
383
CPLErr RawRasterBand::FlushCache(bool bAtClosing)
384
385
0
{
386
0
    CPLErr eErr = GDALRasterBand::FlushCache(bAtClosing);
387
0
    if (eErr != CE_None)
388
0
    {
389
0
        bNeedFileFlush = false;
390
0
        return eErr;
391
0
    }
392
393
0
    RawRasterBand *masterBand = this;
394
0
    if (nBand > 1 && poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
395
0
    {
396
        // can't be null as IsBIP() checks that the first band is not null,
397
        // which could happen during dataset destruction.
398
0
        masterBand = cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(1));
399
0
    }
400
401
0
    if (!masterBand->FlushCurrentLine(false))
402
0
    {
403
0
        masterBand->bNeedFileFlush = false;
404
0
        bNeedFileFlush = false;
405
0
        return CE_Failure;
406
0
    }
407
408
    // If we have unflushed raw, flush it to disk now.
409
0
    if (masterBand->bNeedFileFlush)
410
0
    {
411
0
        int nRet = VSIFFlushL(fpRawL);
412
413
0
        masterBand->bNeedFileFlush = false;
414
0
        bNeedFileFlush = false;
415
0
        if (nRet < 0)
416
0
            return CE_Failure;
417
0
    }
418
419
0
    bNeedFileFlush = false;
420
421
0
    return CE_None;
422
0
}
423
424
/************************************************************************/
425
/*                      NeedsByteOrderChange()                          */
426
/************************************************************************/
427
428
bool RawRasterBand::NeedsByteOrderChange() const
429
0
{
430
0
#ifdef CPL_LSB
431
0
    return eDataType != GDT_Byte &&
432
0
           eByteOrder != RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN;
433
#else
434
    return eDataType != GDT_Byte &&
435
           eByteOrder != RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN;
436
#endif
437
0
}
438
439
/************************************************************************/
440
/*                          DoByteSwap()                                */
441
/************************************************************************/
442
443
void RawRasterBand::DoByteSwap(void *pBuffer, size_t nValues, int nByteSkip,
444
                               bool bDiskToCPU) const
445
0
{
446
0
    if (eByteOrder != RawRasterBand::ByteOrder::ORDER_VAX)
447
0
    {
448
0
        if (GDALDataTypeIsComplex(eDataType))
449
0
        {
450
0
            const int nWordSize = GDALGetDataTypeSize(eDataType) / 16;
451
0
            GDALSwapWordsEx(pBuffer, nWordSize, nValues, nByteSkip);
452
0
            GDALSwapWordsEx(static_cast<GByte *>(pBuffer) + nWordSize,
453
0
                            nWordSize, nValues, nByteSkip);
454
0
        }
455
0
        else
456
0
        {
457
0
            GDALSwapWordsEx(pBuffer, GDALGetDataTypeSizeBytes(eDataType),
458
0
                            nValues, nByteSkip);
459
0
        }
460
0
    }
461
0
    else if (eDataType == GDT_Float16 || eDataType == GDT_CFloat16)
462
0
    {
463
        // No VAX support for GFloat16
464
0
        std::abort();
465
0
    }
466
0
    else if (eDataType == GDT_Float32 || eDataType == GDT_CFloat32)
467
0
    {
468
0
        GByte *pPtr = static_cast<GByte *>(pBuffer);
469
0
        for (int k = 0; k < 2; k++)
470
0
        {
471
0
            if (bDiskToCPU)
472
0
            {
473
0
                for (size_t i = 0; i < nValues; i++, pPtr += nByteSkip)
474
0
                {
475
0
                    CPLVaxToIEEEFloat(pPtr);
476
0
                }
477
0
            }
478
0
            else
479
0
            {
480
0
                for (size_t i = 0; i < nValues; i++, pPtr += nByteSkip)
481
0
                {
482
0
                    CPLIEEEToVaxFloat(pPtr);
483
0
                }
484
0
            }
485
0
            if (k == 0 && eDataType == GDT_CFloat32)
486
0
                pPtr = static_cast<GByte *>(pBuffer) + sizeof(float);
487
0
            else
488
0
                break;
489
0
        }
490
0
    }
491
0
    else if (eDataType == GDT_Float64 || eDataType == GDT_CFloat64)
492
0
    {
493
0
        GByte *pPtr = static_cast<GByte *>(pBuffer);
494
0
        for (int k = 0; k < 2; k++)
495
0
        {
496
0
            if (bDiskToCPU)
497
0
            {
498
0
                for (size_t i = 0; i < nValues; i++, pPtr += nByteSkip)
499
0
                {
500
0
                    CPLVaxToIEEEDouble(pPtr);
501
0
                }
502
0
            }
503
0
            else
504
0
            {
505
0
                for (size_t i = 0; i < nValues; i++, pPtr += nByteSkip)
506
0
                {
507
0
                    CPLIEEEToVaxDouble(pPtr);
508
0
                }
509
0
            }
510
0
            if (k == 0 && eDataType == GDT_CFloat64)
511
0
                pPtr = static_cast<GByte *>(pBuffer) + sizeof(double);
512
0
            else
513
0
                break;
514
0
        }
515
0
    }
516
0
}
517
518
/************************************************************************/
519
/*                         ComputeFileOffset()                          */
520
/************************************************************************/
521
522
vsi_l_offset RawRasterBand::ComputeFileOffset(int iLine) const
523
0
{
524
    // Write formulas such that unsigned int overflow doesn't occur
525
0
    vsi_l_offset nOffset = nImgOffset;
526
0
    if (nLineOffset >= 0)
527
0
    {
528
0
        nOffset += static_cast<GUIntBig>(nLineOffset) * iLine;
529
0
    }
530
0
    else
531
0
    {
532
0
        nOffset -=
533
0
            static_cast<GUIntBig>(-static_cast<GIntBig>(nLineOffset)) * iLine;
534
0
    }
535
0
    if (nPixelOffset < 0)
536
0
    {
537
0
        const GUIntBig nPixelOffsetToSubtract =
538
0
            static_cast<GUIntBig>(-static_cast<GIntBig>(nPixelOffset)) *
539
0
            (nBlockXSize - 1);
540
0
        nOffset -= nPixelOffsetToSubtract;
541
0
    }
542
0
    return nOffset;
543
0
}
544
545
/************************************************************************/
546
/*                             AccessLine()                             */
547
/************************************************************************/
548
549
CPLErr RawRasterBand::AccessLine(int iLine)
550
551
0
{
552
0
    if (pLineBuffer == nullptr)
553
0
    {
554
0
        if (nBand > 1 && pLineStart != nullptr)
555
0
        {
556
            // BIP interleaved
557
0
            auto poFirstBand =
558
0
                cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(1));
559
0
            CPLAssert(poFirstBand);
560
0
            return poFirstBand->AccessLine(iLine);
561
0
        }
562
0
        return CE_Failure;
563
0
    }
564
565
0
    if (nLoadedScanline == iLine)
566
0
    {
567
0
        return CE_None;
568
0
    }
569
570
0
    if (!FlushCurrentLine(false))
571
0
    {
572
0
        return CE_Failure;
573
0
    }
574
575
    // Figure out where to start reading.
576
0
    const vsi_l_offset nReadStart = ComputeFileOffset(iLine);
577
578
    // Seek to the correct line.
579
0
    if (Seek(nReadStart, SEEK_SET) == -1)
580
0
    {
581
0
        if (poDS != nullptr && poDS->GetAccess() == GA_ReadOnly)
582
0
        {
583
0
            CPLError(CE_Failure, CPLE_FileIO,
584
0
                     "Failed to seek to scanline %d @ " CPL_FRMT_GUIB ".",
585
0
                     iLine, nReadStart);
586
0
            return CE_Failure;
587
0
        }
588
0
        else
589
0
        {
590
0
            memset(pLineBuffer, 0, nLineSize);
591
0
            nLoadedScanline = iLine;
592
0
            return CE_None;
593
0
        }
594
0
    }
595
596
    // Read the line.  Take care not to request any more bytes than
597
    // are needed, and not to lose a partially successful scanline read.
598
0
    const size_t nBytesToRead = nLineSize;
599
0
    const size_t nBytesActuallyRead = Read(pLineBuffer, 1, nBytesToRead);
600
0
    if (nBytesActuallyRead < nBytesToRead)
601
0
    {
602
0
        if (poDS != nullptr && poDS->GetAccess() == GA_ReadOnly &&
603
            // ENVI datasets might be sparse (see #915)
604
0
            poDS->GetMetadata("ENVI") == nullptr)
605
0
        {
606
0
            CPLError(CE_Failure, CPLE_FileIO, "Failed to read scanline %d.",
607
0
                     iLine);
608
0
            return CE_Failure;
609
0
        }
610
0
        else
611
0
        {
612
0
            memset(static_cast<GByte *>(pLineBuffer) + nBytesActuallyRead, 0,
613
0
                   nBytesToRead - nBytesActuallyRead);
614
0
        }
615
0
    }
616
617
    // Byte swap the interesting data, if required.
618
0
    if (NeedsByteOrderChange())
619
0
    {
620
0
        if (poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
621
0
        {
622
0
            const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
623
0
            DoByteSwap(pLineBuffer,
624
0
                       static_cast<size_t>(nBlockXSize) *
625
0
                           poDS->GetRasterCount(),
626
0
                       nDTSize, true);
627
0
        }
628
0
        else
629
0
            DoByteSwap(pLineBuffer, nBlockXSize, std::abs(nPixelOffset), true);
630
0
    }
631
632
0
    nLoadedScanline = iLine;
633
634
0
    return CE_None;
635
0
}
636
637
/************************************************************************/
638
/*                             IReadBlock()                             */
639
/************************************************************************/
640
641
CPLErr RawRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
642
                                 void *pImage)
643
0
{
644
0
    CPLAssert(nBlockXOff == 0);
645
646
0
    const CPLErr eErr = AccessLine(nBlockYOff);
647
0
    if (eErr == CE_Failure)
648
0
        return eErr;
649
650
    // Copy data from disk buffer to user block buffer.
651
0
    const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
652
0
    GDALCopyWords64(pLineStart, eDataType, nPixelOffset, pImage, eDataType,
653
0
                    nDTSize, nBlockXSize);
654
655
    // Pre-cache block cache of other bands
656
0
    if (poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
657
0
    {
658
0
        for (int iBand = 1; iBand <= poDS->GetRasterCount(); iBand++)
659
0
        {
660
0
            if (iBand != nBand)
661
0
            {
662
0
                auto poOtherBand =
663
0
                    cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(iBand));
664
0
                GDALRasterBlock *poBlock =
665
0
                    poOtherBand->TryGetLockedBlockRef(0, nBlockYOff);
666
0
                if (poBlock != nullptr)
667
0
                {
668
0
                    poBlock->DropLock();
669
0
                    continue;
670
0
                }
671
0
                poBlock = poOtherBand->GetLockedBlockRef(0, nBlockYOff, true);
672
0
                if (poBlock != nullptr)
673
0
                {
674
0
                    GDALCopyWords64(poOtherBand->pLineStart, eDataType,
675
0
                                    nPixelOffset, poBlock->GetDataRef(),
676
0
                                    eDataType, nDTSize, nBlockXSize);
677
0
                    poBlock->DropLock();
678
0
                }
679
0
            }
680
0
        }
681
0
    }
682
683
0
    return eErr;
684
0
}
685
686
/************************************************************************/
687
/*                           BIPWriteBlock()                            */
688
/************************************************************************/
689
690
CPLErr RawRasterBand::BIPWriteBlock(int nBlockYOff, int nCallingBand,
691
                                    const void *pImage)
692
0
{
693
0
    if (nLoadedScanline != nBlockYOff)
694
0
    {
695
0
        if (!FlushCurrentLine(false))
696
0
            return CE_Failure;
697
0
    }
698
699
0
    const int nBands = poDS->GetRasterCount();
700
0
    std::vector<GDALRasterBlock *> apoBlocks(nBands);
701
0
    bool bAllBlocksDirty = true;
702
0
    const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
703
704
    /* -------------------------------------------------------------------- */
705
    /*     If all blocks are cached and dirty then we do not need to reload */
706
    /*     the scanline from disk                                           */
707
    /* -------------------------------------------------------------------- */
708
0
    for (int iBand = 0; iBand < nBands; ++iBand)
709
0
    {
710
0
        if (iBand + 1 != nCallingBand)
711
0
        {
712
0
            apoBlocks[iBand] =
713
0
                cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(iBand + 1))
714
0
                    ->TryGetLockedBlockRef(0, nBlockYOff);
715
716
0
            if (apoBlocks[iBand] == nullptr)
717
0
            {
718
0
                bAllBlocksDirty = false;
719
0
            }
720
0
            else if (!apoBlocks[iBand]->GetDirty())
721
0
            {
722
0
                apoBlocks[iBand]->DropLock();
723
0
                apoBlocks[iBand] = nullptr;
724
0
                bAllBlocksDirty = false;
725
0
            }
726
0
        }
727
0
        else
728
0
            apoBlocks[iBand] = nullptr;
729
0
    }
730
731
0
    if (!bAllBlocksDirty)
732
0
    {
733
        // We only to read the scanline if we don't have data for all bands.
734
0
        if (AccessLine(nBlockYOff) != CE_None)
735
0
        {
736
0
            for (int iBand = 0; iBand < nBands; ++iBand)
737
0
            {
738
0
                if (apoBlocks[iBand] != nullptr)
739
0
                    apoBlocks[iBand]->DropLock();
740
0
            }
741
0
            return CE_Failure;
742
0
        }
743
0
    }
744
745
0
    for (int iBand = 0; iBand < nBands; ++iBand)
746
0
    {
747
0
        const GByte *pabyThisImage = nullptr;
748
0
        GDALRasterBlock *poBlock = nullptr;
749
750
0
        if (iBand + 1 == nCallingBand)
751
0
        {
752
0
            pabyThisImage = static_cast<const GByte *>(pImage);
753
0
        }
754
0
        else
755
0
        {
756
0
            poBlock = apoBlocks[iBand];
757
0
            if (poBlock == nullptr)
758
0
                continue;
759
760
0
            if (!poBlock->GetDirty())
761
0
            {
762
0
                poBlock->DropLock();
763
0
                continue;
764
0
            }
765
766
0
            pabyThisImage = static_cast<const GByte *>(poBlock->GetDataRef());
767
0
        }
768
769
0
        GByte *pabyOut = static_cast<GByte *>(pLineStart) + iBand * nDTSize;
770
771
0
        GDALCopyWords64(pabyThisImage, eDataType, nDTSize, pabyOut, eDataType,
772
0
                        nPixelOffset, nBlockXSize);
773
774
0
        if (poBlock != nullptr)
775
0
        {
776
0
            poBlock->MarkClean();
777
0
            poBlock->DropLock();
778
0
        }
779
0
    }
780
781
0
    nLoadedScanline = nBlockYOff;
782
0
    bLoadedScanlineDirty = true;
783
784
0
    if (bAllBlocksDirty)
785
0
    {
786
0
        return FlushCurrentLine(true) ? CE_None : CE_Failure;
787
0
    }
788
789
0
    bNeedFileFlush = true;
790
0
    return CE_None;
791
0
}
792
793
/************************************************************************/
794
/*                            IWriteBlock()                             */
795
/************************************************************************/
796
797
CPLErr RawRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
798
                                  void *pImage)
799
0
{
800
0
    CPLAssert(nBlockXOff == 0);
801
802
0
    if (pLineBuffer == nullptr)
803
0
    {
804
0
        if (poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
805
0
        {
806
0
            auto poFirstBand =
807
0
                (nBand == 1)
808
0
                    ? this
809
0
                    : cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(1));
810
0
            CPLAssert(poFirstBand);
811
0
            return poFirstBand->BIPWriteBlock(nBlockYOff, nBand, pImage);
812
0
        }
813
814
0
        return CE_Failure;
815
0
    }
816
817
0
    if (nLoadedScanline != nBlockYOff)
818
0
    {
819
0
        if (!FlushCurrentLine(false))
820
0
            return CE_Failure;
821
0
    }
822
823
    // If the data for this band is completely contiguous, we don't
824
    // have to worry about pre-reading from disk.
825
0
    CPLErr eErr = CE_None;
826
0
    const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
827
0
    if (std::abs(nPixelOffset) > nDTSize)
828
0
        eErr = AccessLine(nBlockYOff);
829
830
    // Copy data from user buffer into disk buffer.
831
0
    GDALCopyWords64(pImage, eDataType, nDTSize, pLineStart, eDataType,
832
0
                    nPixelOffset, nBlockXSize);
833
834
0
    nLoadedScanline = nBlockYOff;
835
0
    bLoadedScanlineDirty = true;
836
837
0
    return eErr == CE_None && FlushCurrentLine(true) ? CE_None : CE_Failure;
838
0
}
839
840
/************************************************************************/
841
/*                         FlushCurrentLine()                           */
842
/************************************************************************/
843
844
bool RawRasterBand::FlushCurrentLine(bool bNeedUsableBufferAfter)
845
0
{
846
0
    if (!bLoadedScanlineDirty)
847
0
        return true;
848
849
0
    bLoadedScanlineDirty = false;
850
851
0
    bool ok = true;
852
853
    // Byte swap (if necessary) back into disk order before writing.
854
0
    if (NeedsByteOrderChange())
855
0
    {
856
0
        if (poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
857
0
        {
858
0
            const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
859
0
            DoByteSwap(pLineBuffer,
860
0
                       static_cast<size_t>(nBlockXSize) *
861
0
                           poDS->GetRasterCount(),
862
0
                       nDTSize, false);
863
0
        }
864
0
        else
865
0
            DoByteSwap(pLineBuffer, nBlockXSize, std::abs(nPixelOffset), false);
866
0
    }
867
868
    // Figure out where to start reading.
869
0
    const vsi_l_offset nWriteStart = ComputeFileOffset(nLoadedScanline);
870
871
    // Seek to correct location.
872
0
    if (Seek(nWriteStart, SEEK_SET) == -1)
873
0
    {
874
0
        CPLError(CE_Failure, CPLE_FileIO,
875
0
                 "Failed to seek to scanline %d @ " CPL_FRMT_GUIB
876
0
                 " to write to file.",
877
0
                 nLoadedScanline, nWriteStart);
878
879
0
        ok = false;
880
0
    }
881
882
    // Write data buffer.
883
0
    const int nBytesToWrite = nLineSize;
884
0
    if (ok && Write(pLineBuffer, 1, nBytesToWrite) <
885
0
                  static_cast<size_t>(nBytesToWrite))
886
0
    {
887
0
        CPLError(CE_Failure, CPLE_FileIO,
888
0
                 "Failed to write scanline %d to file.", nLoadedScanline);
889
890
0
        ok = false;
891
0
    }
892
893
    // Byte swap (if necessary) back into machine order so the
894
    // buffer is still usable for reading purposes, unless this is not needed.
895
0
    if (bNeedUsableBufferAfter && NeedsByteOrderChange())
896
0
    {
897
0
        if (poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
898
0
        {
899
0
            const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
900
0
            DoByteSwap(pLineBuffer,
901
0
                       static_cast<size_t>(nBlockXSize) *
902
0
                           poDS->GetRasterCount(),
903
0
                       nDTSize, true);
904
0
        }
905
0
        else
906
0
            DoByteSwap(pLineBuffer, nBlockXSize, std::abs(nPixelOffset), true);
907
0
    }
908
909
0
    bNeedFileFlush = true;
910
911
0
    return ok;
912
0
}
913
914
/************************************************************************/
915
/*                             AccessBlock()                            */
916
/************************************************************************/
917
918
CPLErr RawRasterBand::AccessBlock(vsi_l_offset nBlockOff, size_t nBlockSize,
919
                                  void *pData, size_t nValues)
920
0
{
921
    // Seek to the correct block.
922
0
    if (Seek(nBlockOff, SEEK_SET) == -1)
923
0
    {
924
0
        memset(pData, 0, nBlockSize);
925
0
        return CE_None;
926
0
    }
927
928
    // Read the block.
929
0
    const size_t nBytesActuallyRead = Read(pData, 1, nBlockSize);
930
0
    if (nBytesActuallyRead < nBlockSize)
931
0
    {
932
933
0
        memset(static_cast<GByte *>(pData) + nBytesActuallyRead, 0,
934
0
               nBlockSize - nBytesActuallyRead);
935
0
    }
936
937
    // Byte swap the interesting data, if required.
938
0
    if (NeedsByteOrderChange())
939
0
    {
940
0
        DoByteSwap(pData, nValues, std::abs(nPixelOffset), true);
941
0
    }
942
943
0
    return CE_None;
944
0
}
945
946
/************************************************************************/
947
/*               IsSignificantNumberOfLinesLoaded()                     */
948
/*                                                                      */
949
/*  Check if there is a significant number of scanlines (>20%) from the */
950
/*  specified block of lines already cached.                            */
951
/************************************************************************/
952
953
int RawRasterBand::IsSignificantNumberOfLinesLoaded(int nLineOff, int nLines)
954
0
{
955
0
    int nCountLoaded = 0;
956
957
0
    for (int iLine = nLineOff; iLine < nLineOff + nLines; iLine++)
958
0
    {
959
0
        GDALRasterBlock *poBlock = TryGetLockedBlockRef(0, iLine);
960
0
        if (poBlock != nullptr)
961
0
        {
962
0
            poBlock->DropLock();
963
0
            nCountLoaded++;
964
0
            if (nCountLoaded > nLines / 20)
965
0
            {
966
0
                return TRUE;
967
0
            }
968
0
        }
969
0
    }
970
971
0
    return FALSE;
972
0
}
973
974
/************************************************************************/
975
/*                           CanUseDirectIO()                           */
976
/************************************************************************/
977
978
int RawRasterBand::CanUseDirectIO(int /* nXOff */, int nYOff, int nXSize,
979
                                  int nYSize, GDALDataType /* eBufType*/,
980
                                  GDALRasterIOExtraArg *psExtraArg)
981
0
{
982
0
    bool result = FALSE;
983
984
    // Use direct IO without caching if:
985
    //
986
    // GDAL_ONE_BIG_READ is enabled
987
    //
988
    // or
989
    //
990
    // the raster width is so small that the cost of a GDALRasterBlock is
991
    // significant
992
    //
993
    // or
994
    //
995
    // the length of a scanline on disk is more than 50000 bytes, and the
996
    // width of the requested chunk is less than 40% of the whole scanline and
997
    // no significant number of requested scanlines are already in the cache.
998
999
0
    if (nPixelOffset < 0 || psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
1000
0
    {
1001
0
        return FALSE;
1002
0
    }
1003
1004
0
    RawDataset *rawDataset = dynamic_cast<RawDataset *>(this->GetDataset());
1005
0
    int oldCachedCPLOneBigReadOption = 0;
1006
0
    if (rawDataset != nullptr)
1007
0
    {
1008
0
        oldCachedCPLOneBigReadOption = rawDataset->cachedCPLOneBigReadOption;
1009
0
    }
1010
1011
0
    const char *pszGDAL_ONE_BIG_READ =
1012
0
        !(oldCachedCPLOneBigReadOption & 0xff)  // Test valid
1013
0
            ? CPLGetConfigOption("GDAL_ONE_BIG_READ", nullptr)
1014
0
            : (((oldCachedCPLOneBigReadOption >> 8) & 0xff) == 0)   ? "0"
1015
0
              : (((oldCachedCPLOneBigReadOption >> 8) & 0xff) == 1) ? "1"
1016
0
                                                                    : nullptr;
1017
0
    if (pszGDAL_ONE_BIG_READ == nullptr)
1018
0
    {
1019
0
        const int newCachedCPLOneBigReadOption = (0xff << 8) | 1;
1020
0
        if (rawDataset != nullptr)
1021
0
        {
1022
0
            rawDataset->cachedCPLOneBigReadOption.compare_exchange_strong(
1023
0
                oldCachedCPLOneBigReadOption, newCachedCPLOneBigReadOption);
1024
0
        }
1025
1026
0
        if (nRasterXSize <= 64)
1027
0
        {
1028
0
            return TRUE;
1029
0
        }
1030
1031
0
        if (nLineSize < 50000 || nXSize > nLineSize / nPixelOffset / 5 * 2 ||
1032
0
            IsSignificantNumberOfLinesLoaded(nYOff, nYSize))
1033
0
        {
1034
0
            return FALSE;
1035
0
        }
1036
0
        return TRUE;
1037
0
    }
1038
1039
0
    result = CPLTestBool(pszGDAL_ONE_BIG_READ);
1040
1041
0
    const int newCachedCPLOneBigReadOption = (result ? 1 : 0) << 8 | 1;
1042
0
    if (rawDataset != nullptr)
1043
0
    {
1044
0
        rawDataset->cachedCPLOneBigReadOption.compare_exchange_strong(
1045
0
            oldCachedCPLOneBigReadOption, newCachedCPLOneBigReadOption);
1046
0
    }
1047
1048
0
    return result;
1049
0
}
1050
1051
/************************************************************************/
1052
/*                             IRasterIO()                              */
1053
/************************************************************************/
1054
1055
CPLErr RawRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
1056
                                int nXSize, int nYSize, void *pData,
1057
                                int nBufXSize, int nBufYSize,
1058
                                GDALDataType eBufType, GSpacing nPixelSpace,
1059
                                GSpacing nLineSpace,
1060
                                GDALRasterIOExtraArg *psExtraArg)
1061
1062
0
{
1063
0
    const int nBandDataSize = GDALGetDataTypeSizeBytes(eDataType);
1064
0
#ifdef DEBUG
1065
    // Otherwise Coverity thinks that a divide by zero is possible in
1066
    // AccessBlock() in the complex data type wapping case.
1067
0
    if (nBandDataSize == 0)
1068
0
        return CE_Failure;
1069
0
#endif
1070
0
    const int nBufDataSize = GDALGetDataTypeSizeBytes(eBufType);
1071
1072
0
    if (!CanUseDirectIO(nXOff, nYOff, nXSize, nYSize, eBufType, psExtraArg))
1073
0
    {
1074
0
        return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
1075
0
                                         pData, nBufXSize, nBufYSize, eBufType,
1076
0
                                         nPixelSpace, nLineSpace, psExtraArg);
1077
0
    }
1078
1079
0
    CPLDebug("RAW", "Using direct IO implementation");
1080
1081
0
    if (pLineBuffer == nullptr)
1082
0
    {
1083
0
        if (poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
1084
0
        {
1085
0
            auto poFirstBand =
1086
0
                (nBand == 1)
1087
0
                    ? this
1088
0
                    : cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(1));
1089
0
            CPLAssert(poFirstBand);
1090
0
            if (poFirstBand->bNeedFileFlush)
1091
0
                RawRasterBand::FlushCache(false);
1092
0
        }
1093
0
    }
1094
0
    if (bNeedFileFlush)
1095
0
        RawRasterBand::FlushCache(false);
1096
1097
    // Needed for ICC fast math approximations
1098
0
    constexpr double EPS = 1e-10;
1099
1100
    // Read data.
1101
0
    if (eRWFlag == GF_Read)
1102
0
    {
1103
        // Do we have overviews that are appropriate to satisfy this request?
1104
0
        if ((nBufXSize < nXSize || nBufYSize < nYSize) &&
1105
0
            GetOverviewCount() > 0)
1106
0
        {
1107
0
            if (OverviewRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
1108
0
                                 nBufXSize, nBufYSize, eBufType, nPixelSpace,
1109
0
                                 nLineSpace, psExtraArg) == CE_None)
1110
0
                return CE_None;
1111
0
        }
1112
1113
        // 1. Simplest case when we should get contiguous block
1114
        //    of uninterleaved pixels.
1115
0
        if (nXSize == GetXSize() && nXSize == nBufXSize &&
1116
0
            nYSize == nBufYSize && eBufType == eDataType &&
1117
0
            nPixelOffset == nBandDataSize && nPixelSpace == nBufDataSize &&
1118
0
            nLineSpace == nPixelSpace * nXSize &&
1119
0
            nLineOffset == nPixelOffset * nXSize)
1120
0
        {
1121
0
            vsi_l_offset nOffset = nImgOffset;
1122
0
            if (nLineOffset >= 0)
1123
0
                nOffset += nYOff * static_cast<vsi_l_offset>(nLineOffset);
1124
0
            else
1125
0
                nOffset -= nYOff * static_cast<vsi_l_offset>(-nLineOffset);
1126
1127
0
            const size_t nValues = static_cast<size_t>(nXSize) * nYSize;
1128
0
            const size_t nBytesToRead = nValues * nBandDataSize;
1129
0
            AccessBlock(nOffset, nBytesToRead, pData, nValues);
1130
0
        }
1131
        // 2. Case when we need deinterleave and/or subsample data.
1132
0
        else
1133
0
        {
1134
0
            const double dfSrcXInc = static_cast<double>(nXSize) / nBufXSize;
1135
0
            const double dfSrcYInc = static_cast<double>(nYSize) / nBufYSize;
1136
1137
0
            const size_t nBytesToRW =
1138
0
                static_cast<size_t>(nPixelOffset) * (nXSize - 1) +
1139
0
                GDALGetDataTypeSizeBytes(eDataType);
1140
0
            GByte *pabyData =
1141
0
                static_cast<GByte *>(VSI_MALLOC_VERBOSE(nBytesToRW));
1142
0
            if (pabyData == nullptr)
1143
0
                return CE_Failure;
1144
1145
0
            for (int iLine = 0; iLine < nBufYSize; iLine++)
1146
0
            {
1147
0
                const vsi_l_offset nLine =
1148
0
                    static_cast<vsi_l_offset>(nYOff) +
1149
0
                    static_cast<vsi_l_offset>(iLine * dfSrcYInc + EPS);
1150
0
                vsi_l_offset nOffset = nImgOffset;
1151
0
                if (nLineOffset >= 0)
1152
0
                    nOffset += nLine * nLineOffset;
1153
0
                else
1154
0
                    nOffset -= nLine * static_cast<vsi_l_offset>(-nLineOffset);
1155
0
                if (nPixelOffset >= 0)
1156
0
                    nOffset += nXOff * static_cast<vsi_l_offset>(nPixelOffset);
1157
0
                else
1158
0
                    nOffset -= nXOff * static_cast<vsi_l_offset>(-nPixelOffset);
1159
0
                AccessBlock(nOffset, nBytesToRW, pabyData, nXSize);
1160
                // Copy data from disk buffer to user block buffer and
1161
                // subsample, if needed.
1162
0
                if (nXSize == nBufXSize && nYSize == nBufYSize)
1163
0
                {
1164
0
                    GDALCopyWords64(
1165
0
                        pabyData, eDataType, nPixelOffset,
1166
0
                        static_cast<GByte *>(pData) + iLine * nLineSpace,
1167
0
                        eBufType, static_cast<int>(nPixelSpace), nXSize);
1168
0
                }
1169
0
                else
1170
0
                {
1171
0
                    for (int iPixel = 0; iPixel < nBufXSize; iPixel++)
1172
0
                    {
1173
0
                        GDALCopyWords64(
1174
0
                            pabyData + static_cast<vsi_l_offset>(
1175
0
                                           iPixel * dfSrcXInc + EPS) *
1176
0
                                           nPixelOffset,
1177
0
                            eDataType, nPixelOffset,
1178
0
                            static_cast<GByte *>(pData) + iLine * nLineSpace +
1179
0
                                iPixel * nPixelSpace,
1180
0
                            eBufType, static_cast<int>(nPixelSpace), 1);
1181
0
                    }
1182
0
                }
1183
1184
0
                if (psExtraArg->pfnProgress != nullptr &&
1185
0
                    !psExtraArg->pfnProgress(1.0 * (iLine + 1) / nBufYSize, "",
1186
0
                                             psExtraArg->pProgressData))
1187
0
                {
1188
0
                    CPLFree(pabyData);
1189
0
                    return CE_Failure;
1190
0
                }
1191
0
            }
1192
1193
0
            CPLFree(pabyData);
1194
0
        }
1195
0
    }
1196
    // Write data.
1197
0
    else
1198
0
    {
1199
        // 1. Simplest case when we should write contiguous block of
1200
        //    uninterleaved pixels.
1201
0
        if (nXSize == GetXSize() && nXSize == nBufXSize &&
1202
0
            nYSize == nBufYSize && eBufType == eDataType &&
1203
0
            nPixelOffset == nBandDataSize && nPixelSpace == nBufDataSize &&
1204
0
            nLineSpace == nPixelSpace * nXSize &&
1205
0
            nLineOffset == nPixelOffset * nXSize)
1206
0
        {
1207
0
            const size_t nValues = static_cast<size_t>(nXSize) * nYSize;
1208
1209
            // Byte swap the data buffer, if required.
1210
0
            if (NeedsByteOrderChange())
1211
0
            {
1212
0
                DoByteSwap(pData, nValues, std::abs(nPixelOffset), false);
1213
0
            }
1214
1215
            // Seek to the correct block.
1216
0
            vsi_l_offset nOffset = nImgOffset;
1217
0
            if (nLineOffset >= 0)
1218
0
                nOffset += nYOff * static_cast<vsi_l_offset>(nLineOffset);
1219
0
            else
1220
0
                nOffset -= nYOff * static_cast<vsi_l_offset>(-nLineOffset);
1221
1222
0
            if (Seek(nOffset, SEEK_SET) == -1)
1223
0
            {
1224
0
                CPLError(CE_Failure, CPLE_FileIO,
1225
0
                         "Failed to seek to " CPL_FRMT_GUIB " to write data.",
1226
0
                         nOffset);
1227
1228
0
                return CE_Failure;
1229
0
            }
1230
1231
            // Write the block.
1232
0
            const size_t nBytesToRW = nValues * nBandDataSize;
1233
1234
0
            const size_t nBytesActuallyWritten = Write(pData, 1, nBytesToRW);
1235
0
            if (nBytesActuallyWritten < nBytesToRW)
1236
0
            {
1237
0
                CPLError(CE_Failure, CPLE_FileIO,
1238
0
                         "Failed to write " CPL_FRMT_GUIB
1239
0
                         " bytes to file. " CPL_FRMT_GUIB " bytes written",
1240
0
                         static_cast<GUIntBig>(nBytesToRW),
1241
0
                         static_cast<GUIntBig>(nBytesActuallyWritten));
1242
1243
0
                return CE_Failure;
1244
0
            }
1245
1246
            // Byte swap (if necessary) back into machine order so the
1247
            // buffer is still usable for reading purposes.
1248
0
            if (NeedsByteOrderChange())
1249
0
            {
1250
0
                DoByteSwap(pData, nValues, std::abs(nPixelOffset), true);
1251
0
            }
1252
0
        }
1253
        // 2. Case when we need deinterleave and/or subsample data.
1254
0
        else
1255
0
        {
1256
0
            const double dfSrcXInc = static_cast<double>(nXSize) / nBufXSize;
1257
0
            const double dfSrcYInc = static_cast<double>(nYSize) / nBufYSize;
1258
1259
0
            const size_t nBytesToRW =
1260
0
                static_cast<size_t>(nPixelOffset) * (nXSize - 1) +
1261
0
                GDALGetDataTypeSizeBytes(eDataType);
1262
0
            GByte *pabyData =
1263
0
                static_cast<GByte *>(VSI_MALLOC_VERBOSE(nBytesToRW));
1264
0
            if (pabyData == nullptr)
1265
0
                return CE_Failure;
1266
1267
0
            for (int iLine = 0; iLine < nBufYSize; iLine++)
1268
0
            {
1269
0
                const vsi_l_offset nLine =
1270
0
                    static_cast<vsi_l_offset>(nYOff) +
1271
0
                    static_cast<vsi_l_offset>(iLine * dfSrcYInc + EPS);
1272
0
                vsi_l_offset nOffset = nImgOffset;
1273
0
                if (nLineOffset >= 0)
1274
0
                    nOffset += nLine * static_cast<vsi_l_offset>(nLineOffset);
1275
0
                else
1276
0
                    nOffset -= nLine * static_cast<vsi_l_offset>(-nLineOffset);
1277
0
                if (nPixelOffset >= 0)
1278
0
                    nOffset += nXOff * static_cast<vsi_l_offset>(nPixelOffset);
1279
0
                else
1280
0
                    nOffset -= nXOff * static_cast<vsi_l_offset>(-nPixelOffset);
1281
1282
                // If the data for this band is completely contiguous we don't
1283
                // have to worry about pre-reading from disk.
1284
0
                if (nPixelOffset > nBandDataSize)
1285
0
                    AccessBlock(nOffset, nBytesToRW, pabyData, nXSize);
1286
1287
                // Copy data from user block buffer to disk buffer and
1288
                // subsample, if needed.
1289
0
                if (nXSize == nBufXSize && nYSize == nBufYSize)
1290
0
                {
1291
0
                    GDALCopyWords64(static_cast<GByte *>(pData) +
1292
0
                                        iLine * nLineSpace,
1293
0
                                    eBufType, static_cast<int>(nPixelSpace),
1294
0
                                    pabyData, eDataType, nPixelOffset, nXSize);
1295
0
                }
1296
0
                else
1297
0
                {
1298
0
                    for (int iPixel = 0; iPixel < nBufXSize; iPixel++)
1299
0
                    {
1300
0
                        GDALCopyWords64(
1301
0
                            static_cast<GByte *>(pData) + iLine * nLineSpace +
1302
0
                                iPixel * nPixelSpace,
1303
0
                            eBufType, static_cast<int>(nPixelSpace),
1304
0
                            pabyData + static_cast<vsi_l_offset>(
1305
0
                                           iPixel * dfSrcXInc + EPS) *
1306
0
                                           nPixelOffset,
1307
0
                            eDataType, nPixelOffset, 1);
1308
0
                    }
1309
0
                }
1310
1311
                // Byte swap the data buffer, if required.
1312
0
                if (NeedsByteOrderChange())
1313
0
                {
1314
0
                    if (GDALDataTypeIsComplex(eDataType))
1315
0
                    {
1316
0
                        const int nWordSize =
1317
0
                            GDALGetDataTypeSize(eDataType) / 16;
1318
0
                        GDALSwapWords(pabyData, nWordSize, nXSize,
1319
0
                                      nPixelOffset);
1320
0
                        GDALSwapWords(static_cast<GByte *>(pabyData) +
1321
0
                                          nWordSize,
1322
0
                                      nWordSize, nXSize, nPixelOffset);
1323
0
                    }
1324
0
                    else
1325
0
                    {
1326
0
                        GDALSwapWords(pabyData, nBandDataSize, nXSize,
1327
0
                                      nPixelOffset);
1328
0
                    }
1329
0
                }
1330
1331
                // Seek to the right line in block.
1332
0
                if (Seek(nOffset, SEEK_SET) == -1)
1333
0
                {
1334
0
                    CPLError(CE_Failure, CPLE_FileIO,
1335
0
                             "Failed to seek to " CPL_FRMT_GUIB " to read.",
1336
0
                             nOffset);
1337
0
                    CPLFree(pabyData);
1338
0
                    return CE_Failure;
1339
0
                }
1340
1341
                // Write the line of block.
1342
0
                const size_t nBytesActuallyWritten =
1343
0
                    Write(pabyData, 1, nBytesToRW);
1344
0
                if (nBytesActuallyWritten < nBytesToRW)
1345
0
                {
1346
0
                    CPLError(CE_Failure, CPLE_FileIO,
1347
0
                             "Failed to write " CPL_FRMT_GUIB
1348
0
                             " bytes to file. " CPL_FRMT_GUIB " bytes written",
1349
0
                             static_cast<GUIntBig>(nBytesToRW),
1350
0
                             static_cast<GUIntBig>(nBytesActuallyWritten));
1351
0
                    CPLFree(pabyData);
1352
0
                    return CE_Failure;
1353
0
                }
1354
1355
                // Byte swap (if necessary) back into machine order so the
1356
                // buffer is still usable for reading purposes.
1357
0
                if (NeedsByteOrderChange())
1358
0
                {
1359
0
                    if (GDALDataTypeIsComplex(eDataType))
1360
0
                    {
1361
0
                        const int nWordSize =
1362
0
                            GDALGetDataTypeSize(eDataType) / 16;
1363
0
                        GDALSwapWords(pabyData, nWordSize, nXSize,
1364
0
                                      nPixelOffset);
1365
0
                        GDALSwapWords(static_cast<GByte *>(pabyData) +
1366
0
                                          nWordSize,
1367
0
                                      nWordSize, nXSize, nPixelOffset);
1368
0
                    }
1369
0
                    else
1370
0
                    {
1371
0
                        GDALSwapWords(pabyData, nBandDataSize, nXSize,
1372
0
                                      nPixelOffset);
1373
0
                    }
1374
0
                }
1375
0
            }
1376
1377
0
            bNeedFileFlush = TRUE;
1378
0
            CPLFree(pabyData);
1379
0
        }
1380
0
    }
1381
1382
0
    return CE_None;
1383
0
}
1384
1385
/************************************************************************/
1386
/*                                Seek()                                */
1387
/************************************************************************/
1388
1389
int RawRasterBand::Seek(vsi_l_offset nOffset, int nSeekMode)
1390
1391
0
{
1392
0
    return VSIFSeekL(fpRawL, nOffset, nSeekMode);
1393
0
}
1394
1395
/************************************************************************/
1396
/*                                Read()                                */
1397
/************************************************************************/
1398
1399
size_t RawRasterBand::Read(void *pBuffer, size_t nSize, size_t nCount)
1400
1401
0
{
1402
0
    return VSIFReadL(pBuffer, nSize, nCount, fpRawL);
1403
0
}
1404
1405
/************************************************************************/
1406
/*                               Write()                                */
1407
/************************************************************************/
1408
1409
size_t RawRasterBand::Write(void *pBuffer, size_t nSize, size_t nCount)
1410
1411
0
{
1412
0
    return VSIFWriteL(pBuffer, nSize, nCount, fpRawL);
1413
0
}
1414
1415
/************************************************************************/
1416
/*                          StoreNoDataValue()                          */
1417
/*                                                                      */
1418
/*      This is a helper function for datasets to associate a no        */
1419
/*      data value with this band, it isn't intended to be called by    */
1420
/*      applications.                                                   */
1421
/************************************************************************/
1422
1423
void RawRasterBand::StoreNoDataValue(double dfValue)
1424
1425
0
{
1426
0
    SetNoDataValue(dfValue);
1427
0
}
1428
1429
/************************************************************************/
1430
/*                          GetCategoryNames()                          */
1431
/************************************************************************/
1432
1433
char **RawRasterBand::GetCategoryNames()
1434
0
{
1435
0
    return papszCategoryNames;
1436
0
}
1437
1438
/************************************************************************/
1439
/*                          SetCategoryNames()                          */
1440
/************************************************************************/
1441
1442
CPLErr RawRasterBand::SetCategoryNames(char **papszNewNames)
1443
1444
0
{
1445
0
    CSLDestroy(papszCategoryNames);
1446
0
    papszCategoryNames = CSLDuplicate(papszNewNames);
1447
1448
0
    return CE_None;
1449
0
}
1450
1451
/************************************************************************/
1452
/*                           SetColorTable()                            */
1453
/************************************************************************/
1454
1455
CPLErr RawRasterBand::SetColorTable(GDALColorTable *poNewCT)
1456
1457
0
{
1458
0
    if (poCT)
1459
0
        delete poCT;
1460
0
    if (poNewCT == nullptr)
1461
0
        poCT = nullptr;
1462
0
    else
1463
0
        poCT = poNewCT->Clone();
1464
1465
0
    return CE_None;
1466
0
}
1467
1468
/************************************************************************/
1469
/*                           GetColorTable()                            */
1470
/************************************************************************/
1471
1472
GDALColorTable *RawRasterBand::GetColorTable()
1473
0
{
1474
0
    return poCT;
1475
0
}
1476
1477
/************************************************************************/
1478
/*                       SetColorInterpretation()                       */
1479
/************************************************************************/
1480
1481
CPLErr RawRasterBand::SetColorInterpretation(GDALColorInterp eNewInterp)
1482
1483
0
{
1484
0
    eInterp = eNewInterp;
1485
1486
0
    return CE_None;
1487
0
}
1488
1489
/************************************************************************/
1490
/*                       GetColorInterpretation()                       */
1491
/************************************************************************/
1492
1493
GDALColorInterp RawRasterBand::GetColorInterpretation()
1494
0
{
1495
0
    return eInterp;
1496
0
}
1497
1498
/************************************************************************/
1499
/*                           GetVirtualMemAuto()                        */
1500
/************************************************************************/
1501
1502
CPLVirtualMem *RawRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
1503
                                                int *pnPixelSpace,
1504
                                                GIntBig *pnLineSpace,
1505
                                                char **papszOptions)
1506
0
{
1507
0
    CPLAssert(pnPixelSpace);
1508
0
    CPLAssert(pnLineSpace);
1509
1510
0
    const vsi_l_offset nSize =
1511
0
        static_cast<vsi_l_offset>(nRasterYSize - 1) * nLineOffset +
1512
0
        static_cast<vsi_l_offset>(nRasterXSize - 1) * nPixelOffset +
1513
0
        GDALGetDataTypeSizeBytes(eDataType);
1514
1515
0
    const char *pszImpl = CSLFetchNameValueDef(
1516
0
        papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
1517
0
    if (VSIFGetNativeFileDescriptorL(fpRawL) == nullptr ||
1518
0
        !CPLIsVirtualMemFileMapAvailable() || NeedsByteOrderChange() ||
1519
0
        static_cast<size_t>(nSize) != nSize || nPixelOffset < 0 ||
1520
0
        nLineOffset < 0 || EQUAL(pszImpl, "YES") || EQUAL(pszImpl, "ON") ||
1521
0
        EQUAL(pszImpl, "1") || EQUAL(pszImpl, "TRUE"))
1522
0
    {
1523
0
        return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace,
1524
0
                                                 pnLineSpace, papszOptions);
1525
0
    }
1526
1527
0
    FlushCache(false);
1528
1529
0
    CPLVirtualMem *pVMem = CPLVirtualMemFileMapNew(
1530
0
        fpRawL, nImgOffset, nSize,
1531
0
        (eRWFlag == GF_Write) ? VIRTUALMEM_READWRITE : VIRTUALMEM_READONLY,
1532
0
        nullptr, nullptr);
1533
0
    if (pVMem == nullptr)
1534
0
    {
1535
0
        if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") ||
1536
0
            EQUAL(pszImpl, "0") || EQUAL(pszImpl, "FALSE"))
1537
0
        {
1538
0
            return nullptr;
1539
0
        }
1540
0
        return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace,
1541
0
                                                 pnLineSpace, papszOptions);
1542
0
    }
1543
1544
0
    *pnPixelSpace = nPixelOffset;
1545
0
    *pnLineSpace = nLineOffset;
1546
0
    return pVMem;
1547
0
}
1548
1549
/************************************************************************/
1550
/* ==================================================================== */
1551
/*      RawDataset                                                      */
1552
/* ==================================================================== */
1553
/************************************************************************/
1554
1555
/************************************************************************/
1556
/*                            RawDataset()                              */
1557
/************************************************************************/
1558
1559
RawDataset::RawDataset()
1560
0
{
1561
0
}
1562
1563
/************************************************************************/
1564
/*                           ~RawDataset()                              */
1565
/************************************************************************/
1566
1567
// It's pure virtual function but must be defined, even if empty.
1568
RawDataset::~RawDataset()
1569
0
{
1570
0
}
1571
1572
/************************************************************************/
1573
/*                             IRasterIO()                              */
1574
/*                                                                      */
1575
/*      Multi-band raster io handler.                                   */
1576
/************************************************************************/
1577
1578
CPLErr RawDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
1579
                             int nXSize, int nYSize, void *pData, int nBufXSize,
1580
                             int nBufYSize, GDALDataType eBufType,
1581
                             int nBandCount, BANDMAP_TYPE panBandMap,
1582
                             GSpacing nPixelSpace, GSpacing nLineSpace,
1583
                             GSpacing nBandSpace,
1584
                             GDALRasterIOExtraArg *psExtraArg)
1585
1586
0
{
1587
0
    const char *pszInterleave = nullptr;
1588
1589
0
    this->ClearCachedConfigOption();
1590
1591
    // The default GDALDataset::IRasterIO() implementation would go to
1592
    // BlockBasedRasterIO if the dataset is interleaved. However if the
1593
    // access pattern is compatible with DirectIO() we don't want to go
1594
    // BlockBasedRasterIO, but rather used our optimized path in
1595
    // RawRasterBand::IRasterIO().
1596
0
    if (nXSize == nBufXSize && nYSize == nBufYSize && nBandCount > 1 &&
1597
0
        (pszInterleave = GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE")) !=
1598
0
            nullptr &&
1599
0
        EQUAL(pszInterleave, "PIXEL"))
1600
0
    {
1601
0
        RawRasterBand *poFirstBand = nullptr;
1602
0
        bool bCanDirectAccessToBIPDataset =
1603
0
            eRWFlag == GF_Read && nBandCount == nBands;
1604
0
        bool bCanUseDirectIO = true;
1605
0
        for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++)
1606
0
        {
1607
0
            RawRasterBand *poBand = dynamic_cast<RawRasterBand *>(
1608
0
                GetRasterBand(panBandMap[iBandIndex]));
1609
0
            if (poBand == nullptr)
1610
0
            {
1611
0
                bCanDirectAccessToBIPDataset = false;
1612
0
                bCanUseDirectIO = false;
1613
0
                break;
1614
0
            }
1615
0
            else if (!poBand->CanUseDirectIO(nXOff, nYOff, nXSize, nYSize,
1616
0
                                             eBufType, psExtraArg))
1617
0
            {
1618
0
                bCanUseDirectIO = false;
1619
0
                if (!bCanDirectAccessToBIPDataset)
1620
0
                    break;
1621
0
            }
1622
0
            if (bCanDirectAccessToBIPDataset)
1623
0
            {
1624
0
                const auto eDT = poBand->GetRasterDataType();
1625
0
                const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
1626
0
                if (poBand->bNeedFileFlush || poBand->bLoadedScanlineDirty ||
1627
0
                    poBand->HasDirtyBlocks() ||
1628
0
                    panBandMap[iBandIndex] != iBandIndex + 1 ||
1629
0
                    nPixelSpace != poBand->nPixelOffset)
1630
0
                {
1631
0
                    bCanDirectAccessToBIPDataset = false;
1632
0
                }
1633
0
                else
1634
0
                {
1635
0
                    if (poFirstBand == nullptr)
1636
0
                    {
1637
0
                        poFirstBand = poBand;
1638
0
                        bCanDirectAccessToBIPDataset =
1639
0
                            eDT == eBufType && nBandSpace == nDTSize &&
1640
0
                            poFirstBand->nPixelOffset ==
1641
0
                                cpl::fits_on<int>(nBands * nDTSize);
1642
0
                    }
1643
0
                    else
1644
0
                    {
1645
0
                        bCanDirectAccessToBIPDataset =
1646
0
                            eDT == poFirstBand->GetRasterDataType() &&
1647
0
                            poBand->fpRawL == poFirstBand->fpRawL &&
1648
0
                            poBand->nImgOffset ==
1649
0
                                poFirstBand->nImgOffset +
1650
0
                                    cpl::fits_on<int>(iBandIndex * nDTSize) &&
1651
0
                            poBand->nPixelOffset == poFirstBand->nPixelOffset &&
1652
0
                            poBand->nLineOffset == poFirstBand->nLineOffset &&
1653
0
                            poBand->eByteOrder == poFirstBand->eByteOrder;
1654
0
                    }
1655
0
                }
1656
0
            }
1657
0
        }
1658
0
        if (bCanDirectAccessToBIPDataset)
1659
0
        {
1660
0
            CPLDebugOnly("GDALRaw", "Direct access to BIP dataset");
1661
0
            const auto eDT = poFirstBand->GetRasterDataType();
1662
0
            const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
1663
0
            const bool bNeedsByteOrderChange =
1664
0
                poFirstBand->NeedsByteOrderChange();
1665
0
            for (int iY = 0; iY < nYSize; ++iY)
1666
0
            {
1667
0
                GByte *pabyOut = static_cast<GByte *>(pData) + iY * nLineSpace;
1668
0
                VSIFSeekL(poFirstBand->fpRawL,
1669
0
                          poFirstBand->nImgOffset +
1670
0
                              static_cast<vsi_l_offset>(nYOff + iY) *
1671
0
                                  poFirstBand->nLineOffset +
1672
0
                              static_cast<vsi_l_offset>(nXOff) *
1673
0
                                  poFirstBand->nPixelOffset,
1674
0
                          SEEK_SET);
1675
0
                if (VSIFReadL(pabyOut,
1676
0
                              static_cast<size_t>(nXSize * nPixelSpace), 1,
1677
0
                              poFirstBand->fpRawL) != 1)
1678
0
                {
1679
0
                    return CE_Failure;
1680
0
                }
1681
0
                if (bNeedsByteOrderChange)
1682
0
                {
1683
0
                    poFirstBand->DoByteSwap(
1684
0
                        pabyOut, static_cast<size_t>(nXSize) * nBands, nDTSize,
1685
0
                        true);
1686
0
                }
1687
0
            }
1688
0
            return CE_None;
1689
0
        }
1690
0
        else if (bCanUseDirectIO)
1691
0
        {
1692
0
            GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
1693
0
            void *pProgressDataGlobal = psExtraArg->pProgressData;
1694
1695
0
            CPLErr eErr = CE_None;
1696
0
            for (int iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
1697
0
                 iBandIndex++)
1698
0
            {
1699
0
                GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
1700
1701
0
                if (poBand == nullptr)
1702
0
                {
1703
0
                    eErr = CE_Failure;
1704
0
                    break;
1705
0
                }
1706
1707
0
                GByte *pabyBandData =
1708
0
                    static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
1709
1710
0
                psExtraArg->pfnProgress = GDALScaledProgress;
1711
0
                psExtraArg->pProgressData = GDALCreateScaledProgress(
1712
0
                    1.0 * iBandIndex / nBandCount,
1713
0
                    1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
1714
0
                    pProgressDataGlobal);
1715
1716
0
                eErr = poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
1717
0
                                        static_cast<void *>(pabyBandData),
1718
0
                                        nBufXSize, nBufYSize, eBufType,
1719
0
                                        nPixelSpace, nLineSpace, psExtraArg);
1720
1721
0
                GDALDestroyScaledProgress(psExtraArg->pProgressData);
1722
0
            }
1723
1724
0
            psExtraArg->pfnProgress = pfnProgressGlobal;
1725
0
            psExtraArg->pProgressData = pProgressDataGlobal;
1726
1727
0
            return eErr;
1728
0
        }
1729
0
    }
1730
1731
0
    return GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
1732
0
                                  nBufXSize, nBufYSize, eBufType, nBandCount,
1733
0
                                  panBandMap, nPixelSpace, nLineSpace,
1734
0
                                  nBandSpace, psExtraArg);
1735
0
}
1736
1737
/************************************************************************/
1738
/*                  RAWDatasetCheckMemoryUsage()                        */
1739
/************************************************************************/
1740
1741
bool RAWDatasetCheckMemoryUsage(int nXSize, int nYSize, int nBands, int nDTSize,
1742
                                int nPixelOffset, int nLineOffset,
1743
                                vsi_l_offset nHeaderSize,
1744
                                vsi_l_offset nBandOffset, VSILFILE *fp)
1745
0
{
1746
0
    const GIntBig nTotalBufferSize =
1747
0
        nPixelOffset == static_cast<GIntBig>(nDTSize) * nBands
1748
0
            ?  // BIP ?
1749
0
            static_cast<GIntBig>(nPixelOffset) * nXSize
1750
0
            : static_cast<GIntBig>(std::abs(nPixelOffset)) * nXSize * nBands;
1751
1752
    // Currently each RawRasterBand allocates nPixelOffset * nRasterXSize bytes
1753
    // so for a pixel interleaved scheme, this will allocate lots of memory!
1754
    // Actually this is quadratic in the number of bands!
1755
    // Do a few sanity checks to avoid excessive memory allocation on
1756
    // small files.
1757
    // But ultimately we should fix RawRasterBand to have a shared buffer
1758
    // among bands.
1759
0
    const char *pszCheck = CPLGetConfigOption("RAW_CHECK_FILE_SIZE", nullptr);
1760
0
    if ((nBands > 10 || nTotalBufferSize > 20000 ||
1761
0
         (pszCheck && CPLTestBool(pszCheck))) &&
1762
0
        !(pszCheck && !CPLTestBool(pszCheck)))
1763
0
    {
1764
0
        vsi_l_offset nExpectedFileSize;
1765
0
        try
1766
0
        {
1767
0
            nExpectedFileSize =
1768
0
                (CPLSM(static_cast<uint64_t>(nHeaderSize)) +
1769
0
                 CPLSM(static_cast<uint64_t>(nBandOffset)) *
1770
0
                     CPLSM(static_cast<uint64_t>(nBands - 1)) +
1771
0
                 (nLineOffset >= 0
1772
0
                      ? CPLSM(static_cast<uint64_t>(nYSize - 1)) *
1773
0
                            CPLSM(static_cast<uint64_t>(nLineOffset))
1774
0
                      : CPLSM(static_cast<uint64_t>(0))) +
1775
0
                 (nPixelOffset >= 0
1776
0
                      ? CPLSM(static_cast<uint64_t>(nXSize - 1)) *
1777
0
                            CPLSM(static_cast<uint64_t>(nPixelOffset))
1778
0
                      : CPLSM(static_cast<uint64_t>(0))))
1779
0
                    .v();
1780
0
        }
1781
0
        catch (...)
1782
0
        {
1783
0
            CPLError(CE_Failure, CPLE_AppDefined, "Image file is too small");
1784
0
            return false;
1785
0
        }
1786
0
        CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_END));
1787
0
        vsi_l_offset nFileSize = VSIFTellL(fp);
1788
        // Do not strictly compare against nExpectedFileSize, but use an
1789
        // arbitrary 50% margin, since some raw formats such as ENVI allow for
1790
        // sparse files (see https://github.com/OSGeo/gdal/issues/915)
1791
0
        if (nFileSize < nExpectedFileSize / 2)
1792
0
        {
1793
0
            CPLError(CE_Failure, CPLE_AppDefined, "Image file is too small");
1794
0
            return false;
1795
0
        }
1796
0
    }
1797
1798
0
#if SIZEOF_VOIDP == 8
1799
0
    const char *pszDefault = "1024";
1800
#else
1801
    const char *pszDefault = "512";
1802
#endif
1803
0
    constexpr int MB_IN_BYTES = 1024 * 1024;
1804
0
    const GIntBig nMAX_BUFFER_MEM =
1805
0
        static_cast<GIntBig>(
1806
0
            atoi(CPLGetConfigOption("RAW_MEM_ALLOC_LIMIT_MB", pszDefault))) *
1807
0
        MB_IN_BYTES;
1808
0
    if (nTotalBufferSize > nMAX_BUFFER_MEM)
1809
0
    {
1810
0
        CPLError(
1811
0
            CE_Failure, CPLE_OutOfMemory,
1812
0
            CPL_FRMT_GIB
1813
0
            " MB of RAM would be needed to open the dataset. If you are "
1814
0
            "comfortable with this, you can set the RAW_MEM_ALLOC_LIMIT_MB "
1815
0
            "configuration option to that value or above",
1816
0
            DIV_ROUND_UP(nTotalBufferSize, MB_IN_BYTES));
1817
0
        return false;
1818
0
    }
1819
1820
0
    return true;
1821
0
}
1822
1823
/************************************************************************/
1824
/*                        GetRawBinaryLayout()                          */
1825
/************************************************************************/
1826
1827
bool RawDataset::GetRawBinaryLayout(GDALDataset::RawBinaryLayout &sLayout)
1828
0
{
1829
0
    vsi_l_offset nImgOffset = 0;
1830
0
    GIntBig nBandOffset = 0;
1831
0
    int nPixelOffset = 0;
1832
0
    int nLineOffset = 0;
1833
0
    RawRasterBand::ByteOrder eByteOrder =
1834
0
        RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN;
1835
0
    GDALDataType eDT = GDT_Unknown;
1836
0
    for (int i = 1; i <= nBands; i++)
1837
0
    {
1838
0
        auto poBand = dynamic_cast<RawRasterBand *>(GetRasterBand(i));
1839
0
        if (poBand == nullptr)
1840
0
            return false;
1841
0
        if (i == 1)
1842
0
        {
1843
0
            nImgOffset = poBand->nImgOffset;
1844
0
            nPixelOffset = poBand->nPixelOffset;
1845
0
            nLineOffset = poBand->nLineOffset;
1846
0
            eByteOrder = poBand->eByteOrder;
1847
0
            if (eByteOrder == RawRasterBand::ByteOrder::ORDER_VAX)
1848
0
                return false;
1849
0
            eDT = poBand->GetRasterDataType();
1850
0
        }
1851
0
        else if (nPixelOffset != poBand->nPixelOffset ||
1852
0
                 nLineOffset != poBand->nLineOffset ||
1853
0
                 eByteOrder != poBand->eByteOrder ||
1854
0
                 eDT != poBand->GetRasterDataType())
1855
0
        {
1856
0
            return false;
1857
0
        }
1858
0
        else if (i == 2)
1859
0
        {
1860
0
            nBandOffset = static_cast<GIntBig>(poBand->nImgOffset) -
1861
0
                          static_cast<GIntBig>(nImgOffset);
1862
0
        }
1863
0
        else if (nBandOffset * (i - 1) !=
1864
0
                 static_cast<GIntBig>(poBand->nImgOffset) -
1865
0
                     static_cast<GIntBig>(nImgOffset))
1866
0
        {
1867
0
            return false;
1868
0
        }
1869
0
    }
1870
1871
0
    sLayout.eInterleaving = RawBinaryLayout::Interleaving::UNKNOWN;
1872
0
    const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
1873
0
    if (nBands > 1)
1874
0
    {
1875
0
        if (nPixelOffset == nBands * nDTSize &&
1876
0
            nLineOffset == nPixelOffset * nRasterXSize &&
1877
0
            nBandOffset == nDTSize)
1878
0
        {
1879
0
            sLayout.eInterleaving = RawBinaryLayout::Interleaving::BIP;
1880
0
        }
1881
0
        else if (nPixelOffset == nDTSize &&
1882
0
                 nLineOffset == nDTSize * nBands * nRasterXSize &&
1883
0
                 nBandOffset == static_cast<GIntBig>(nDTSize) * nRasterXSize)
1884
0
        {
1885
0
            sLayout.eInterleaving = RawBinaryLayout::Interleaving::BIL;
1886
0
        }
1887
0
        else if (nPixelOffset == nDTSize &&
1888
0
                 nLineOffset == nDTSize * nRasterXSize &&
1889
0
                 nBandOffset ==
1890
0
                     static_cast<GIntBig>(nLineOffset) * nRasterYSize)
1891
0
        {
1892
0
            sLayout.eInterleaving = RawBinaryLayout::Interleaving::BSQ;
1893
0
        }
1894
0
    }
1895
1896
0
    sLayout.eDataType = eDT;
1897
0
    sLayout.bLittleEndianOrder =
1898
0
        eByteOrder == RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN;
1899
0
    sLayout.nImageOffset = nImgOffset;
1900
0
    sLayout.nPixelOffset = nPixelOffset;
1901
0
    sLayout.nLineOffset = nLineOffset;
1902
0
    sLayout.nBandOffset = nBandOffset;
1903
1904
0
    return true;
1905
0
}
1906
1907
/************************************************************************/
1908
/*                        ClearCachedConfigOption()                     */
1909
/************************************************************************/
1910
1911
void RawDataset::ClearCachedConfigOption(void)
1912
0
{
1913
0
    cachedCPLOneBigReadOption = 0;
1914
0
}