Coverage Report

Created: 2025-08-28 06:57

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