LCOV - code coverage report
Current view: top level - gcore - rawdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 672 808 83.2 %
Date: 2025-02-20 10:14:44 Functions: 39 42 92.9 %

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

Generated by: LCOV version 1.14