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

Generated by: LCOV version 1.14