LCOV - code coverage report
Current view: top level - gcore - rawdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 667 802 83.2 %
Date: 2024-11-21 22:18:42 Functions: 39 42 92.9 %

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

Generated by: LCOV version 1.14