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

Generated by: LCOV version 1.14