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

Generated by: LCOV version 1.14