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

Generated by: LCOV version 1.14