LCOV - code coverage report
Current view: top level - frmts/mrf - mrf_band.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 488 762 64.0 %
Date: 2025-01-18 12:42:00 Functions: 32 53 60.4 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2002-2012, California Institute of Technology.
       3             :  * All rights reserved.  Based on Government Sponsored Research under contracts
       4             :  * NAS7-1407 and/or NAS7-03001.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions are met:
       8             :  *   1. Redistributions of source code must retain the above copyright notice,
       9             :  * this list of conditions and the following disclaimer.
      10             :  *   2. Redistributions in binary form must reproduce the above copyright
      11             :  * notice, this list of conditions and the following disclaimer in the
      12             :  * documentation and/or other materials provided with the distribution.
      13             :  *   3. Neither the name of the California Institute of Technology (Caltech),
      14             :  * its operating division the Jet Propulsion Laboratory (JPL), the National
      15             :  * Aeronautics and Space Administration (NASA), nor the names of its
      16             :  * contributors may be used to endorse or promote products derived from this
      17             :  * software without specific prior written permission.
      18             :  *
      19             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
      20             :  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      21             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      22             :  * ARE DISCLAIMED. IN NO EVENT SHALL THE CALIFORNIA INSTITUTE OF TECHNOLOGY BE
      23             :  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      24             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      25             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      26             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      27             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      28             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      29             :  * POSSIBILITY OF SUCH DAMAGE.
      30             :  *
      31             :  * Copyright 2014-2021 Esri
      32             :  *
      33             :  * Licensed under the Apache License, Version 2.0 (the "License");
      34             :  * you may not use this file except in compliance with the License.
      35             :  * You may obtain a copy of the License at
      36             :  *
      37             :  * http://www.apache.org/licenses/LICENSE-2.0
      38             :  *
      39             :  * Unless required by applicable law or agreed to in writing, software
      40             :  * distributed under the License is distributed on an "AS IS" BASIS,
      41             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      42             :  * See the License for the specific language governing permissions and
      43             :  * limitations under the License.
      44             :  */
      45             : 
      46             : /******************************************************************************
      47             :  *
      48             :  * Project:  Meta Raster File Format Driver Implementation, RasterBand
      49             :  * Purpose:  Implementation of MRF band
      50             :  *
      51             :  * Author:   Lucian Plesea, Lucian.Plesea jpl.nasa.gov, lplesea esri.com
      52             :  *
      53             :  ****************************************************************************/
      54             : 
      55             : #include "marfa.h"
      56             : #include "gdal_priv.h"
      57             : #include "ogr_srs_api.h"
      58             : #include "ogr_spatialref.h"
      59             : 
      60             : #include <vector>
      61             : #include <cassert>
      62             : #include <zlib.h>
      63             : #if defined(ZSTD_SUPPORT)
      64             : #include <zstd.h>
      65             : #endif
      66             : 
      67             : using namespace std::chrono;
      68             : 
      69             : NAMESPACE_MRF_START
      70             : 
      71             : // packs a block of a given type, with a stride
      72             : // Count is the number of items that need to be copied
      73             : // These are separate to allow for optimization
      74             : 
      75             : template <typename T>
      76          24 : static void cpy_stride_in(void *dst, void *src, int c, int stride)
      77             : {
      78          24 :     T *s = reinterpret_cast<T *>(src);
      79          24 :     T *d = reinterpret_cast<T *>(dst);
      80             : 
      81     6291480 :     while (c--)
      82             :     {
      83     6291460 :         *d++ = *s;
      84     6291460 :         s += stride;
      85             :     }
      86          24 : }
      87             : 
      88             : template <typename T>
      89          33 : static void cpy_stride_out(void *dst, void *src, int c, int stride)
      90             : {
      91          33 :     T *s = reinterpret_cast<T *>(src);
      92          33 :     T *d = reinterpret_cast<T *>(dst);
      93             : 
      94     8650780 :     while (c--)
      95             :     {
      96     8650750 :         *d = *s++;
      97     8650750 :         d += stride;
      98             :     }
      99          33 : }
     100             : 
     101             : // Does every value in the buffer have the same value, using strict comparison
     102             : template <typename T>
     103        5105 : inline int isAllVal(const T *b, size_t bytecount, double ndv)
     104             : {
     105        5105 :     T val = static_cast<T>(ndv);
     106        5105 :     size_t count = bytecount / sizeof(T);
     107     1843727 :     for (; count; --count)
     108             :     {
     109     1843727 :         if (*(b++) != val)
     110             :         {
     111        5098 :             return FALSE;
     112             :         }
     113             :     }
     114           7 :     return TRUE;
     115             : }
     116             : 
     117             : // Dispatcher based on gdal data type
     118        5105 : static int isAllVal(GDALDataType gt, void *b, size_t bytecount, double ndv)
     119             : {
     120             :     // Test to see if it has data
     121        5105 :     int isempty = false;
     122             : 
     123             :     // A case branch in a temporary macro, conversion from gdal enum to type
     124             : #define TEST_T(GType, T)                                                       \
     125             :     case GType:                                                                \
     126             :         isempty = isAllVal(reinterpret_cast<T *>(b), bytecount, ndv);          \
     127             :         break
     128             : 
     129        5105 :     switch (gt)
     130             :     {
     131        4942 :         TEST_T(GDT_Byte, GByte);
     132           0 :         TEST_T(GDT_Int8, GInt8);
     133          28 :         TEST_T(GDT_UInt16, GUInt16);
     134          27 :         TEST_T(GDT_Int16, GInt16);
     135          26 :         TEST_T(GDT_UInt32, GUInt32);
     136          26 :         TEST_T(GDT_Int32, GInt32);
     137           0 :         TEST_T(GDT_UInt64, GUInt64);
     138           4 :         TEST_T(GDT_Int64, GInt64);
     139          26 :         TEST_T(GDT_Float32, float);
     140          26 :         TEST_T(GDT_Float64, double);
     141           0 :         default:
     142           0 :             break;
     143             :     }
     144             : #undef TEST_T
     145             : 
     146        5105 :     return isempty;
     147             : }
     148             : 
     149             : // Swap bytes in place, unconditional
     150             : // cppcheck-suppress constParameterReference
     151           0 : static void swab_buff(buf_mgr &src, const ILImage &img)
     152             : {
     153             :     size_t i;
     154           0 :     switch (GDALGetDataTypeSize(img.dt))
     155             :     {
     156           0 :         case 16:
     157             :         {
     158           0 :             short int *b = (short int *)src.buffer;
     159           0 :             for (i = src.size / 2; i; b++, i--)
     160           0 :                 *b = swab16(*b);
     161           0 :             break;
     162             :         }
     163           0 :         case 32:
     164             :         {
     165           0 :             int *b = (int *)src.buffer;
     166           0 :             for (i = src.size / 4; i; b++, i--)
     167           0 :                 *b = swab32(*b);
     168           0 :             break;
     169             :         }
     170           0 :         case 64:
     171             :         {
     172           0 :             long long *b = (long long *)src.buffer;
     173           0 :             for (i = src.size / 8; i; b++, i--)
     174           0 :                 *b = swab64(*b);
     175           0 :             break;
     176             :         }
     177             :     }
     178           0 : }
     179             : 
     180             : // Similar to compress2() but with flags to control zlib features
     181             : // Returns true if it worked
     182           9 : static int ZPack(const buf_mgr &src, buf_mgr &dst, int flags)
     183             : {
     184             :     z_stream stream;
     185             :     int err;
     186             : 
     187           9 :     memset(&stream, 0, sizeof(stream));
     188           9 :     stream.next_in = (Bytef *)src.buffer;
     189           9 :     stream.avail_in = (uInt)src.size;
     190           9 :     stream.next_out = (Bytef *)dst.buffer;
     191           9 :     stream.avail_out = (uInt)dst.size;
     192             : 
     193           9 :     int level = flags & ZFLAG_LMASK;
     194           9 :     if (level > 9)
     195           0 :         level = 9;
     196           9 :     if (level < 1)
     197           0 :         level = 1;
     198           9 :     int wb = MAX_WBITS;
     199             :     // if gz flag is set, ignore raw request
     200           9 :     if (flags & ZFLAG_GZ)
     201           0 :         wb += 16;
     202           9 :     else if (flags & ZFLAG_RAW)
     203           0 :         wb = -wb;
     204           9 :     int memlevel = 8;  // Good compromise
     205           9 :     int strategy = (flags & ZFLAG_SMASK) >> 6;
     206           9 :     if (strategy > 4)
     207           0 :         strategy = 0;
     208             : 
     209           9 :     err = deflateInit2(&stream, level, Z_DEFLATED, wb, memlevel, strategy);
     210           9 :     if (err != Z_OK)
     211             :     {
     212           0 :         deflateEnd(&stream);
     213           0 :         return err;
     214             :     }
     215             : 
     216           9 :     err = deflate(&stream, Z_FINISH);
     217           9 :     if (err != Z_STREAM_END)
     218             :     {
     219           0 :         deflateEnd(&stream);
     220           0 :         return false;
     221             :     }
     222           9 :     dst.size = stream.total_out;
     223           9 :     err = deflateEnd(&stream);
     224           9 :     return err == Z_OK;
     225             : }
     226             : 
     227             : // Similar to uncompress() from zlib, accepts the ZFLAG_RAW
     228             : // Return true if it worked
     229           9 : static int ZUnPack(const buf_mgr &src, buf_mgr &dst, int flags)
     230             : {
     231             : 
     232             :     z_stream stream;
     233             :     int err;
     234             : 
     235           9 :     memset(&stream, 0, sizeof(stream));
     236           9 :     stream.next_in = (Bytef *)src.buffer;
     237           9 :     stream.avail_in = (uInt)src.size;
     238           9 :     stream.next_out = (Bytef *)dst.buffer;
     239           9 :     stream.avail_out = (uInt)dst.size;
     240             : 
     241             :     // 32 means autodetec gzip or zlib header, negative 15 is for raw
     242           9 :     int wb = (ZFLAG_RAW & flags) ? -MAX_WBITS : 32 + MAX_WBITS;
     243           9 :     err = inflateInit2(&stream, wb);
     244           9 :     if (err != Z_OK)
     245           0 :         return false;
     246             : 
     247           9 :     err = inflate(&stream, Z_FINISH);
     248           9 :     if (err != Z_STREAM_END)
     249             :     {
     250           0 :         inflateEnd(&stream);
     251           0 :         return false;
     252             :     }
     253           9 :     dst.size = stream.total_out;
     254           9 :     err = inflateEnd(&stream);
     255           9 :     return err == Z_OK;
     256             : }
     257             : 
     258             : /*
     259             :  * Deflates a buffer, extrasize is the available size in the buffer past the
     260             :  * input If the output fits past the data, it uses that area, otherwise it uses
     261             :  * a temporary buffer and copies the data over the input on return, returning a
     262             :  * pointer to it. The output size is returned in src.size Returns nullptr when
     263             :  * compression failed
     264             :  */
     265           9 : static void *DeflateBlock(buf_mgr &src, size_t extrasize, int flags)
     266             : {
     267             :     // The one we might need to allocate
     268           9 :     void *dbuff = nullptr;
     269           9 :     buf_mgr dst = {src.buffer + src.size, extrasize};
     270             : 
     271             :     // Allocate a temp buffer if there is not sufficient space,
     272             :     // We need to have a bit more than half the buffer available
     273           9 :     if (extrasize < (src.size + 64))
     274             :     {
     275           9 :         dst.size = src.size + 64;
     276           9 :         dbuff = VSIMalloc(dst.size);
     277           9 :         dst.buffer = (char *)dbuff;
     278           9 :         if (!dst.buffer)
     279           0 :             return nullptr;
     280             :     }
     281             : 
     282           9 :     if (!ZPack(src, dst, flags))
     283             :     {
     284           0 :         CPLFree(dbuff);  // Safe to call with NULL
     285           0 :         return nullptr;
     286             :     }
     287           9 :     if (dst.size > src.size)
     288             :     {
     289           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     290             :                  "DeflateBlock(): dst.size > src.size");
     291           0 :         CPLFree(dbuff);  // Safe to call with NULL
     292           0 :         return nullptr;
     293             :     }
     294             : 
     295             :     // source size is used to hold the output size
     296           9 :     src.size = dst.size;
     297             :     // If we didn't allocate a buffer, the receiver can use it already
     298           9 :     if (!dbuff)
     299           0 :         return dst.buffer;
     300             : 
     301             :     // If we allocated a buffer, we need to copy the data to the input buffer.
     302           9 :     memcpy(src.buffer, dbuff, src.size);
     303           9 :     CPLFree(dbuff);
     304           9 :     return src.buffer;
     305             : }
     306             : 
     307             : #if defined(ZSTD_SUPPORT)
     308             : 
     309          12 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static void rankfilter(buf_mgr &src,
     310             :                                                             size_t factor)
     311             : {
     312             :     // Arange bytes by rank
     313          12 :     if (factor > 1)
     314             :     {
     315           8 :         std::vector<char> tempb(src.size);
     316           8 :         char *d = tempb.data();
     317          43 :         for (size_t j = 0; j < factor; j++)
     318     9175080 :             for (size_t i = j; i < src.size; i += factor)
     319     9175040 :                 *d++ = src.buffer[i];
     320           8 :         memcpy(src.buffer, tempb.data(), src.size);
     321             :     }
     322             :     // byte delta
     323          12 :     auto p = reinterpret_cast<GByte *>(src.buffer);
     324          12 :     auto guard = p + src.size;
     325          12 :     GByte b(0);
     326    10223600 :     while (p < guard)
     327             :     {
     328    10223600 :         GByte temp = *p;
     329    10223600 :         *p -= b;
     330    10223600 :         b = temp;
     331    10223600 :         p++;
     332             :     }
     333          12 : }
     334             : 
     335          10 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static void derank(buf_mgr &src,
     336             :                                                         size_t factor)
     337             : {
     338             :     // undo delta
     339          10 :     auto p = reinterpret_cast<GByte *>(src.buffer);
     340          10 :     auto guard = p + src.size;
     341          10 :     GByte b(0);
     342     9699340 :     while (p < guard)
     343             :     {
     344     9699330 :         b += *p;
     345     9699330 :         *p = b;
     346     9699330 :         p++;
     347             :     }
     348          10 :     if (factor > 1)
     349             :     {  // undo rank separation
     350           8 :         std::vector<char> tempb(src.size);
     351           8 :         char *d = tempb.data();
     352           8 :         size_t chunk = src.size / factor;
     353     2097160 :         for (size_t i = 0; i < chunk; i++)
     354    11272200 :             for (size_t j = 0; j < factor; j++)
     355     9175040 :                 *d++ = src.buffer[chunk * j + i];
     356           8 :         memcpy(src.buffer, tempb.data(), src.size);
     357             :     }
     358          10 : }
     359             : 
     360             : /*
     361             :  * Compress a buffer using zstd, extrasize is the available size in the buffer
     362             :  * past the input If ranks > 0, apply the rank filter If the output fits past
     363             :  * the data, it uses that area, otherwise it uses a temporary buffer and copies
     364             :  * the data over the input on return, returning a pointer to it. The output size
     365             :  * is returned in src.size Returns nullptr when compression failed
     366             :  */
     367          12 : static void *ZstdCompBlock(buf_mgr &src, size_t extrasize, int c_level,
     368             :                            ZSTD_CCtx *cctx, size_t ranks)
     369             : {
     370          12 :     if (!cctx)
     371           0 :         return nullptr;
     372          12 :     if (ranks && (src.size % ranks) == 0)
     373          12 :         rankfilter(src, ranks);
     374             : 
     375             :     // might need a buffer for the zstd output
     376          24 :     std::vector<char> dbuff;
     377          12 :     void *dst = src.buffer + src.size;
     378          12 :     size_t size = extrasize;
     379             :     // Allocate a temp buffer if there is not sufficient space.
     380             :     // Zstd bound is about (size * 1.004 + 64)
     381          12 :     if (size < ZSTD_compressBound(src.size))
     382             :     {
     383          12 :         size = ZSTD_compressBound(src.size);
     384          12 :         dbuff.resize(size);
     385          12 :         dst = dbuff.data();
     386             :     }
     387             : 
     388             :     // Use the streaming interface, it's faster and better
     389             :     // See discussion at https://github.com/facebook/zstd/issues/3729
     390          12 :     ZSTD_outBuffer output = {dst, size, 0};
     391          12 :     ZSTD_inBuffer input = {src.buffer, src.size, 0};
     392             :     // Set level
     393          12 :     ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, c_level);
     394             :     // First, pass a continue flag, otherwise it will compress in one go
     395          12 :     size_t val = ZSTD_compressStream2(cctx, &output, &input, ZSTD_e_continue);
     396             :     // If it worked, pass the end flag to flush the buffer
     397          12 :     if (val == 0)
     398          12 :         val = ZSTD_compressStream2(cctx, &output, &input, ZSTD_e_end);
     399          12 :     if (ZSTD_isError(val))
     400           0 :         return nullptr;
     401          12 :     val = output.pos;
     402             : 
     403             :     // If we didn't need the buffer, packed data is already in the user buffer
     404          12 :     if (dbuff.empty())
     405             :     {
     406           0 :         src.size = val;
     407           0 :         return dst;
     408             :     }
     409             : 
     410          12 :     if (val > (src.size + extrasize))
     411             :     {  // Doesn't fit in user buffer
     412           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     413             :                  "MRF: ZSTD compression buffer too small");
     414           0 :         return nullptr;  // Error
     415             :     }
     416             : 
     417          12 :     memcpy(src.buffer, dbuff.data(), val);
     418          12 :     src.size = val;
     419          12 :     return src.buffer;
     420             : }
     421             : #endif
     422             : 
     423             : //
     424             : // The deflate_flags are available in all bands even if the DEFLATE option
     425             : // itself is not set.  This allows for PNG features to be controlled, as well
     426             : // as any other bands that use zlib by itself
     427             : //
     428         543 : MRFRasterBand::MRFRasterBand(MRFDataset *parent_dataset, const ILImage &image,
     429         543 :                              int band, int ov)
     430             :     : poMRFDS(parent_dataset),
     431         543 :       dodeflate(GetOptlist().FetchBoolean("DEFLATE", FALSE)),
     432             :       // Bring the quality to 0 to 9
     433         543 :       deflate_flags(image.quality / 10),
     434         543 :       dozstd(GetOptlist().FetchBoolean("ZSTD", FALSE)), zstd_level(9), m_l(ov),
     435        1629 :       img(image)
     436             : {
     437         543 :     nBand = band;
     438         543 :     eDataType = parent_dataset->current.dt;
     439         543 :     nRasterXSize = img.size.x;
     440         543 :     nRasterYSize = img.size.y;
     441         543 :     nBlockXSize = img.pagesize.x;
     442         543 :     nBlockYSize = img.pagesize.y;
     443         543 :     nBlocksPerRow = img.pagecount.x;
     444         543 :     nBlocksPerColumn = img.pagecount.y;
     445         543 :     img.NoDataValue = MRFRasterBand::GetNoDataValue(&img.hasNoData);
     446             : 
     447             :     // Pick up the twists, aka GZ, RAWZ headers
     448         543 :     if (GetOptlist().FetchBoolean("GZ", FALSE))
     449           0 :         deflate_flags |= ZFLAG_GZ;
     450         543 :     else if (GetOptlist().FetchBoolean("RAWZ", FALSE))
     451           0 :         deflate_flags |= ZFLAG_RAW;
     452             :     // And Pick up the ZLIB strategy, if any
     453         543 :     const char *zstrategy = GetOptlist().FetchNameValueDef("Z_STRATEGY", "");
     454         543 :     int zv = Z_DEFAULT_STRATEGY;
     455         543 :     if (EQUAL(zstrategy, "Z_HUFFMAN_ONLY"))
     456           0 :         zv = Z_HUFFMAN_ONLY;
     457         543 :     else if (EQUAL(zstrategy, "Z_RLE"))
     458           0 :         zv = Z_RLE;
     459         543 :     else if (EQUAL(zstrategy, "Z_FILTERED"))
     460           0 :         zv = Z_FILTERED;
     461         543 :     else if (EQUAL(zstrategy, "Z_FIXED"))
     462           0 :         zv = Z_FIXED;
     463         543 :     deflate_flags |= (zv << 6);
     464         543 :     if (image.quality < 23 && image.quality > 0)
     465           0 :         zstd_level = image.quality;
     466             : 
     467             : #if !defined(ZSTD_SUPPORT)
     468             :     if (dozstd)
     469             :     {  // signal error condition to caller
     470             :         CPLError(CE_Failure, CPLE_AssertionFailed,
     471             :                  "MRF: ZSTD support is not available");
     472             :         dozstd = FALSE;
     473             :     }
     474             : #endif
     475             :     // Chose zstd over deflate if both are enabled and available
     476         543 :     if (dozstd && dodeflate)
     477           0 :         dodeflate = FALSE;
     478         543 : }
     479             : 
     480             : // Clean up the overviews if they exist
     481        1086 : MRFRasterBand::~MRFRasterBand()
     482             : {
     483         615 :     while (!overviews.empty())
     484             :     {
     485          72 :         delete overviews.back();
     486          72 :         overviews.pop_back();
     487             :     }
     488         543 : }
     489             : 
     490             : // Look for a string from the dataset options or from the environment
     491          75 : const char *MRFRasterBand::GetOptionValue(const char *opt,
     492             :                                           const char *def) const
     493             : {
     494          75 :     const char *optValue = poMRFDS->optlist.FetchNameValue(opt);
     495          75 :     if (optValue)
     496           8 :         return optValue;
     497          67 :     return CPLGetConfigOption(opt, def);
     498             : }
     499             : 
     500             : // Utility function, returns a value from a vector corresponding to the band
     501             : // index or the first entry
     502         157 : static double getBandValue(const std::vector<double> &v, int idx)
     503             : {
     504         157 :     return (static_cast<int>(v.size()) > idx) ? v[idx] : v[0];
     505             : }
     506             : 
     507             : // Maybe we should check against the type range?
     508             : // It is not keeping track of how many values have been set,
     509             : // so the application should set none or all the bands
     510             : // This call is only valid during Create
     511          16 : CPLErr MRFRasterBand::SetNoDataValue(double val)
     512             : {
     513          16 :     if (poMRFDS->bCrystalized)
     514             :     {
     515           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     516             :                  "MRF: NoData can be set only during file create");
     517           0 :         return CE_Failure;
     518             :     }
     519          16 :     if (GInt32(poMRFDS->vNoData.size()) < nBand)
     520           0 :         poMRFDS->vNoData.resize(nBand);
     521          16 :     poMRFDS->vNoData[nBand - 1] = val;
     522             :     // We also need to set it for this band
     523          16 :     img.NoDataValue = val;
     524          16 :     img.hasNoData = true;
     525          16 :     return CE_None;
     526             : }
     527             : 
     528        5999 : double MRFRasterBand::GetNoDataValue(int *pbSuccess)
     529             : {
     530        5999 :     const std::vector<double> &v = poMRFDS->vNoData;
     531        5999 :     if (v.empty())
     532        5842 :         return GDALPamRasterBand::GetNoDataValue(pbSuccess);
     533         157 :     if (pbSuccess)
     534         155 :         *pbSuccess = TRUE;
     535         157 :     return getBandValue(v, nBand - 1);
     536             : }
     537             : 
     538           0 : double MRFRasterBand::GetMinimum(int *pbSuccess)
     539             : {
     540           0 :     const std::vector<double> &v = poMRFDS->vMin;
     541           0 :     if (v.empty())
     542           0 :         return GDALPamRasterBand::GetMinimum(pbSuccess);
     543           0 :     if (pbSuccess)
     544           0 :         *pbSuccess = TRUE;
     545           0 :     return getBandValue(v, nBand - 1);
     546             : }
     547             : 
     548           0 : double MRFRasterBand::GetMaximum(int *pbSuccess)
     549             : {
     550           0 :     const std::vector<double> &v = poMRFDS->vMax;
     551           0 :     if (v.empty())
     552           0 :         return GDALPamRasterBand::GetMaximum(pbSuccess);
     553           0 :     if (pbSuccess)
     554           0 :         *pbSuccess = TRUE;
     555           0 :     return getBandValue(v, nBand - 1);
     556             : }
     557             : 
     558             : // Fill with typed ndv, count is always in bytes
     559             : template <typename T>
     560           0 : static CPLErr buff_fill(void *b, size_t count, const T ndv)
     561             : {
     562           0 :     T *buffer = static_cast<T *>(b);
     563           0 :     count /= sizeof(T);
     564           0 :     while (count--)
     565           0 :         *buffer++ = ndv;
     566           0 :     return CE_None;
     567             : }
     568             : 
     569             : /**
     570             :  *\brief Fills a buffer with no data
     571             :  *
     572             :  */
     573          56 : CPLErr MRFRasterBand::FillBlock(void *buffer)
     574             : {
     575             :     int success;
     576          56 :     double ndv = GetNoDataValue(&success);
     577          56 :     if (!success)
     578          56 :         ndv = 0.0;
     579          56 :     size_t bsb = blockSizeBytes();
     580             : 
     581             :     // use memset for speed for bytes, or if nodata is zeros
     582          56 :     if (0.0 == ndv || eDataType == GDT_Byte || eDataType == GDT_Int8)
     583             :     {
     584          56 :         memset(buffer, int(ndv), bsb);
     585          56 :         return CE_None;
     586             :     }
     587             : 
     588             : #define bf(T) buff_fill<T>(buffer, bsb, T(ndv));
     589           0 :     switch (eDataType)
     590             :     {
     591           0 :         case GDT_UInt16:
     592           0 :             return bf(GUInt16);
     593           0 :         case GDT_Int16:
     594           0 :             return bf(GInt16);
     595           0 :         case GDT_UInt32:
     596           0 :             return bf(GUInt32);
     597           0 :         case GDT_Int32:
     598           0 :             return bf(GInt32);
     599           0 :         case GDT_UInt64:
     600           0 :             return bf(GUInt64);
     601           0 :         case GDT_Int64:
     602           0 :             return bf(GInt64);
     603           0 :         case GDT_Float32:
     604           0 :             return bf(float);
     605           0 :         case GDT_Float64:
     606           0 :             return bf(double);
     607           0 :         default:
     608           0 :             break;
     609             :     }
     610             : #undef bf
     611             :     // Should exit before
     612           0 :     return CE_Failure;
     613             : }
     614             : 
     615             : /*\brief Interleave block fill
     616             :  *
     617             :  *  Acquire space for all the other bands, fill each one then drop the locks
     618             :  *  The current band output goes directly into the buffer
     619             :  */
     620             : 
     621           0 : CPLErr MRFRasterBand::FillBlock(int xblk, int yblk, void *buffer)
     622             : {
     623           0 :     std::vector<GDALRasterBlock *> blocks;
     624             : 
     625           0 :     for (int i = 0; i < poMRFDS->nBands; i++)
     626             :     {
     627           0 :         GDALRasterBand *b = poMRFDS->GetRasterBand(i + 1);
     628           0 :         if (b->GetOverviewCount() && 0 != m_l)
     629           0 :             b = b->GetOverview(m_l - 1);
     630             : 
     631             :         // Get the other band blocks, keep them around until later
     632           0 :         if (b == this)
     633             :         {
     634           0 :             FillBlock(buffer);
     635             :         }
     636             :         else
     637             :         {
     638           0 :             GDALRasterBlock *poBlock = b->GetLockedBlockRef(xblk, yblk, 1);
     639           0 :             if (poBlock == nullptr)  // Didn't get this block
     640           0 :                 break;
     641           0 :             FillBlock(poBlock->GetDataRef());
     642           0 :             blocks.push_back(poBlock);
     643             :         }
     644             :     }
     645             : 
     646             :     // Drop the locks for blocks we acquired
     647           0 :     for (int i = 0; i < int(blocks.size()); i++)
     648           0 :         blocks[i]->DropLock();
     649             : 
     650           0 :     return CE_None;
     651             : }
     652             : 
     653             : /*\brief Interleave block read
     654             :  *
     655             :  *  Acquire space for all the other bands, unpack from the dataset buffer, then
     656             :  * drop the locks The current band output goes directly into the buffer
     657             :  */
     658             : 
     659           8 : CPLErr MRFRasterBand::ReadInterleavedBlock(int xblk, int yblk, void *buffer)
     660             : {
     661           8 :     std::vector<GDALRasterBlock *> blocks;
     662             : 
     663          32 :     for (int i = 0; i < poMRFDS->nBands; i++)
     664             :     {
     665          24 :         GDALRasterBand *b = poMRFDS->GetRasterBand(i + 1);
     666          24 :         if (b->GetOverviewCount() && 0 != m_l)
     667           0 :             b = b->GetOverview(m_l - 1);
     668             : 
     669          24 :         void *ob = buffer;
     670             :         // Get the other band blocks, keep them around until later
     671          24 :         if (b != this)
     672             :         {
     673          16 :             GDALRasterBlock *poBlock = b->GetLockedBlockRef(xblk, yblk, 1);
     674          16 :             if (poBlock == nullptr)
     675           0 :                 break;
     676          16 :             ob = poBlock->GetDataRef();
     677          16 :             blocks.push_back(poBlock);
     678             :         }
     679             : 
     680             :         // Just the right mix of templates and macros make deinterleaving tidy
     681          24 :         void *pbuffer = poMRFDS->GetPBuffer();
     682             : #define CpySI(T)                                                               \
     683             :     cpy_stride_in<T>(ob, reinterpret_cast<T *>(pbuffer) + i,                   \
     684             :                      blockSizeBytes() / sizeof(T), img.pagesize.c)
     685             : 
     686             :         // Page is already in poMRFDS->pbuffer, not empty
     687             :         // There are only four cases, since only the data size matters
     688          24 :         switch (GDALGetDataTypeSize(eDataType) / 8)
     689             :         {
     690          24 :             case 1:
     691          24 :                 CpySI(GByte);
     692          24 :                 break;
     693           0 :             case 2:
     694           0 :                 CpySI(GInt16);
     695           0 :                 break;
     696           0 :             case 4:
     697           0 :                 CpySI(GInt32);
     698           0 :                 break;
     699           0 :             case 8:
     700           0 :                 CpySI(GIntBig);
     701           0 :                 break;
     702             :         }
     703             :     }
     704             : 
     705             : #undef CpySI
     706             : 
     707             :     // Drop the locks we acquired
     708          24 :     for (int i = 0; i < int(blocks.size()); i++)
     709          16 :         blocks[i]->DropLock();
     710             : 
     711          16 :     return CE_None;
     712             : }
     713             : 
     714             : /**
     715             :  *\brief Fetch a block from the backing store dataset and keep a copy in the
     716             :  *cache
     717             :  *
     718             :  * @param xblk The X block number, zero based
     719             :  * @param yblk The Y block number, zero based
     720             :  * @param buffer buffer
     721             :  *
     722             :  */
     723           4 : CPLErr MRFRasterBand::FetchBlock(int xblk, int yblk, void *buffer)
     724             : {
     725           4 :     assert(!poMRFDS->source.empty());
     726           4 :     CPLDebug("MRF_IB", "FetchBlock %d,%d,0,%d, level  %d\n", xblk, yblk, nBand,
     727             :              m_l);
     728             : 
     729           4 :     if (poMRFDS->clonedSource)  // This is a clone
     730           1 :         return FetchClonedBlock(xblk, yblk, buffer);
     731             : 
     732           3 :     const GInt32 cstride = img.pagesize.c;  // 1 if band separate
     733           3 :     ILSize req(xblk, yblk, 0, (nBand - 1) / cstride, m_l);
     734           3 :     GUIntBig infooffset = IdxOffset(req, img);
     735             : 
     736           3 :     GDALDataset *poSrcDS = nullptr;
     737           3 :     if (nullptr == (poSrcDS = poMRFDS->GetSrcDS()))
     738             :     {
     739           1 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: Can't open source file %s",
     740           1 :                  poMRFDS->source.c_str());
     741           1 :         return CE_Failure;
     742             :     }
     743             : 
     744             :     // Scale to base resolution
     745           2 :     double scl = pow(poMRFDS->scale, m_l);
     746           2 :     if (0 == m_l)
     747           2 :         scl = 1;  // To allow for precision issues
     748             : 
     749             :     // Prepare parameters for RasterIO, they might be different from a full page
     750           2 :     const GSpacing vsz = GDALGetDataTypeSizeBytes(eDataType);
     751           2 :     int Xoff = int(xblk * img.pagesize.x * scl + 0.5);
     752           2 :     int Yoff = int(yblk * img.pagesize.y * scl + 0.5);
     753           2 :     int readszx = int(img.pagesize.x * scl + 0.5);
     754           2 :     int readszy = int(img.pagesize.y * scl + 0.5);
     755             : 
     756             :     // Compare with the full size and clip to the right and bottom if needed
     757           2 :     int clip = 0;
     758           2 :     if (Xoff + readszx > poMRFDS->full.size.x)
     759             :     {
     760           2 :         clip |= 1;
     761           2 :         readszx = poMRFDS->full.size.x - Xoff;
     762             :     }
     763           2 :     if (Yoff + readszy > poMRFDS->full.size.y)
     764             :     {
     765           2 :         clip |= 1;
     766           2 :         readszy = poMRFDS->full.size.y - Yoff;
     767             :     }
     768             : 
     769             :     // This is where the whole page fits
     770           2 :     void *ob = buffer;
     771           2 :     if (cstride != 1)
     772           0 :         ob = poMRFDS->GetPBuffer();
     773             : 
     774             :     // Fill buffer with NoData if clipping
     775           2 :     if (clip)
     776           2 :         FillBlock(ob);
     777             : 
     778             :     // Use the dataset RasterIO to read one or all bands if interleaved
     779           4 :     CPLErr ret = poSrcDS->RasterIO(
     780             :         GF_Read, Xoff, Yoff, readszx, readszy, ob, pcount(readszx, int(scl)),
     781             :         pcount(readszy, int(scl)), eDataType, cstride,
     782           2 :         (1 == cstride) ? &nBand : nullptr, vsz * cstride,
     783           2 :         vsz * cstride * img.pagesize.x,
     784           2 :         (cstride != 1) ? vsz : vsz * img.pagesize.x * img.pagesize.y, nullptr);
     785             : 
     786           2 :     if (ret != CE_None)
     787           0 :         return ret;
     788             : 
     789             :     // Might have the block in the pbuffer, mark it anyhow
     790           2 :     poMRFDS->tile = req;
     791             :     buf_mgr filesrc;
     792           2 :     filesrc.buffer = (char *)ob;
     793           2 :     filesrc.size = static_cast<size_t>(img.pageSizeBytes);
     794             : 
     795           2 :     if (poMRFDS->bypass_cache)
     796             :     {  // No local caching, just return the data
     797           0 :         if (1 == cstride)
     798           0 :             return CE_None;
     799           0 :         return ReadInterleavedBlock(xblk, yblk, buffer);
     800             :     }
     801             : 
     802             :     // Test to see if it needs to be written, or just marked as checked
     803             :     int success;
     804           2 :     double val = GetNoDataValue(&success);
     805           2 :     if (!success)
     806           2 :         val = 0.0;
     807             : 
     808             :     // TODO: test band by band if data is interleaved
     809           2 :     if (isAllVal(eDataType, ob, img.pageSizeBytes, val))
     810             :     {
     811             :         // Mark it empty and checked, ignore the possible write error
     812           0 :         poMRFDS->WriteTile((void *)1, infooffset, 0);
     813           0 :         if (1 == cstride)
     814           0 :             return CE_None;
     815           0 :         return ReadInterleavedBlock(xblk, yblk, buffer);
     816             :     }
     817             : 
     818             :     // Write the page in the local cache
     819             : 
     820             :     // Have to use a separate buffer for compression output.
     821           2 :     void *outbuff = VSIMalloc(poMRFDS->pbsize);
     822           2 :     if (nullptr == outbuff)
     823             :     {
     824           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     825             :                  "Can't get buffer for writing page");
     826             :         // This is not really an error for a cache, the data is fine
     827           0 :         return CE_Failure;
     828             :     }
     829             : 
     830           2 :     buf_mgr filedst = {static_cast<char *>(outbuff), poMRFDS->pbsize};
     831           2 :     auto start_time = steady_clock::now();
     832           2 :     Compress(filedst, filesrc);
     833             : 
     834             :     // Where the output is, in case we deflate
     835           2 :     void *usebuff = outbuff;
     836           2 :     if (dodeflate)
     837             :     {
     838           0 :         usebuff = DeflateBlock(filedst, poMRFDS->pbsize - filedst.size,
     839             :                                deflate_flags);
     840           0 :         if (!usebuff)
     841             :         {
     842           0 :             CPLError(CE_Failure, CPLE_AppDefined, "MRF: Deflate error");
     843           0 :             return CE_Failure;
     844             :         }
     845             :     }
     846             : 
     847             : #if defined(ZSTD_SUPPORT)
     848           2 :     else if (dozstd)
     849             :     {
     850           0 :         size_t ranks = 0;  // Assume no need for byte rank sort
     851           0 :         if (img.comp == IL_NONE || img.comp == IL_ZSTD)
     852           0 :             ranks =
     853           0 :                 static_cast<size_t>(GDALGetDataTypeSizeBytes(img.dt)) * cstride;
     854           0 :         usebuff = ZstdCompBlock(filedst, poMRFDS->pbsize - filedst.size,
     855           0 :                                 zstd_level, poMRFDS->getzsc(), ranks);
     856           0 :         if (!usebuff)
     857             :         {
     858           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     859             :                      "MRF: ZSTD compression error");
     860           0 :             return CE_Failure;
     861             :         }
     862             :     }
     863             : #endif
     864             : 
     865           2 :     poMRFDS->write_timer +=
     866           2 :         duration_cast<nanoseconds>(steady_clock::now() - start_time);
     867             : 
     868             :     // Write and update the tile index
     869           2 :     ret = poMRFDS->WriteTile(usebuff, infooffset, filedst.size);
     870           2 :     CPLFree(outbuff);
     871             : 
     872             :     // If we hit an error or if unpaking is not needed
     873           2 :     if (ret != CE_None || cstride == 1)
     874           2 :         return ret;
     875             : 
     876             :     // data is already in DS buffer, deinterlace it in pixel blocks
     877           0 :     return ReadInterleavedBlock(xblk, yblk, buffer);
     878             : }
     879             : 
     880             : /**
     881             :  *\brief Fetch for a cloned MRF
     882             :  *
     883             :  * @param xblk The X block number, zero based
     884             :  * @param yblk The Y block number, zero based
     885             :  * @param buffer buffer
     886             :  *
     887             :  */
     888             : 
     889           1 : CPLErr MRFRasterBand::FetchClonedBlock(int xblk, int yblk, void *buffer)
     890             : {
     891           1 :     CPLDebug("MRF_IB", "FetchClonedBlock %d,%d,0,%d, level  %d\n", xblk, yblk,
     892             :              nBand, m_l);
     893             : 
     894             :     // Paranoid check
     895           1 :     assert(poMRFDS->clonedSource);
     896           1 :     MRFDataset *poSrc = static_cast<MRFDataset *>(poMRFDS->GetSrcDS());
     897           1 :     if (nullptr == poSrc)
     898             :     {
     899           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: Can't open source file %s",
     900           0 :                  poMRFDS->source.c_str());
     901           0 :         return CE_Failure;
     902             :     }
     903             : 
     904           1 :     if (poMRFDS->bypass_cache || GF_Read == DataMode())
     905             :     {
     906             :         // Can't store, so just fetch from source, which is an MRF with
     907             :         // identical structure
     908             :         MRFRasterBand *b =
     909           0 :             static_cast<MRFRasterBand *>(poSrc->GetRasterBand(nBand));
     910           0 :         if (b->GetOverviewCount() && m_l)
     911           0 :             b = static_cast<MRFRasterBand *>(b->GetOverview(m_l - 1));
     912           0 :         if (b == nullptr)
     913           0 :             return CE_Failure;
     914           0 :         return b->IReadBlock(xblk, yblk, buffer);
     915             :     }
     916             : 
     917           1 :     ILSize req(xblk, yblk, 0, (nBand - 1) / img.pagesize.c, m_l);
     918             :     ILIdx tinfo;
     919             : 
     920             :     // Get the cloned source tile info
     921             :     // The cloned source index is after the current one
     922           1 :     if (CE_None != poMRFDS->ReadTileIdx(tinfo, req, img, poMRFDS->idxSize))
     923             :     {
     924           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     925             :                  "MRF: Unable to read cloned index entry");
     926           0 :         return CE_Failure;
     927             :     }
     928             : 
     929           1 :     GUIntBig infooffset = IdxOffset(req, img);
     930             :     CPLErr err;
     931             : 
     932             :     // Does the source have this tile?
     933           1 :     if (tinfo.size == 0)
     934             :     {  // Nope, mark it empty and return fill
     935           0 :         err = poMRFDS->WriteTile((void *)1, infooffset, 0);
     936           0 :         if (CE_None != err)
     937           0 :             return err;
     938           0 :         return FillBlock(buffer);
     939             :     }
     940             : 
     941           1 :     VSILFILE *srcfd = poSrc->DataFP();
     942           1 :     if (nullptr == srcfd)
     943             :     {
     944           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     945             :                  "MRF: Can't open source data file %s",
     946           0 :                  poMRFDS->source.c_str());
     947           0 :         return CE_Failure;
     948             :     }
     949             : 
     950             :     // Need to read the tile from the source
     951           1 :     if (tinfo.size <= 0 || tinfo.size > INT_MAX)
     952             :     {
     953           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     954             :                  "Invalid tile size " CPL_FRMT_GIB, tinfo.size);
     955           0 :         return CE_Failure;
     956             :     }
     957           1 :     char *buf = static_cast<char *>(VSIMalloc(static_cast<size_t>(tinfo.size)));
     958           1 :     if (buf == nullptr)
     959             :     {
     960           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     961             :                  "Cannot allocate " CPL_FRMT_GIB " bytes", tinfo.size);
     962           0 :         return CE_Failure;
     963             :     }
     964             : 
     965           1 :     VSIFSeekL(srcfd, tinfo.offset, SEEK_SET);
     966           2 :     if (tinfo.size !=
     967           1 :         GIntBig(VSIFReadL(buf, 1, static_cast<size_t>(tinfo.size), srcfd)))
     968             :     {
     969           0 :         CPLFree(buf);
     970           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     971             :                  "MRF: Can't read data from source %s",
     972             :                  poSrc->current.datfname.c_str());
     973           0 :         return CE_Failure;
     974             :     }
     975             : 
     976             :     // Write it then reissue the read
     977           1 :     err = poMRFDS->WriteTile(buf, infooffset, tinfo.size);
     978           1 :     CPLFree(buf);
     979           1 :     if (CE_None != err)
     980           0 :         return err;
     981             :     // Reissue read, it will work from the cloned data
     982           1 :     return IReadBlock(xblk, yblk, buffer);
     983             : }
     984             : 
     985             : /**
     986             :  *\brief read a block in the provided buffer
     987             :  *
     988             :  *  For separate band model, the DS buffer is not used, the read is direct in
     989             :  *the buffer For pixel interleaved model, the DS buffer holds the temp copy and
     990             :  *all the other bands are force read
     991             :  *
     992             :  */
     993             : 
     994        1882 : CPLErr MRFRasterBand::IReadBlock(int xblk, int yblk, void *buffer)
     995             : {
     996        1882 :     GInt32 cstride = img.pagesize.c;
     997             :     ILIdx tinfo;
     998        1882 :     ILSize req(xblk, yblk, 0, (nBand - 1) / cstride, m_l);
     999        3764 :     CPLDebug("MRF_IB",
    1000             :              "IReadBlock %d,%d,0,%d, level %d, idxoffset " CPL_FRMT_GIB "\n",
    1001        1882 :              xblk, yblk, nBand - 1, m_l, IdxOffset(req, img));
    1002             : 
    1003             :     // If this is a caching file and bypass is on, just do the fetch
    1004        1882 :     if (poMRFDS->bypass_cache && !poMRFDS->source.empty())
    1005           0 :         return FetchBlock(xblk, yblk, buffer);
    1006             : 
    1007        1882 :     tinfo.size = 0;  // Just in case it is missing
    1008        1882 :     if (CE_None != poMRFDS->ReadTileIdx(tinfo, req, img))
    1009             :     {
    1010           0 :         if (!poMRFDS->no_errors)
    1011             :         {
    1012           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1013             :                      "MRF: Unable to read index at offset " CPL_FRMT_GIB,
    1014           0 :                      IdxOffset(req, img));
    1015           0 :             return CE_Failure;
    1016             :         }
    1017           0 :         return FillBlock(buffer);
    1018             :     }
    1019             : 
    1020        1882 :     if (0 == tinfo.size)
    1021             :     {  // Could be missing or it could be caching
    1022             :         // Offset != 0 means no data, Update mode is for local MRFs only
    1023             :         // if caching index mode is RO don't try to fetch
    1024             :         // Also, caching MRFs can't be opened in update mode
    1025          12 :         if (0 != tinfo.offset || GA_Update == poMRFDS->eAccess ||
    1026          18 :             poMRFDS->source.empty() || IdxMode() == GF_Read)
    1027           2 :             return FillBlock(buffer);
    1028             : 
    1029             :         // caching MRF, need to fetch a block
    1030           4 :         return FetchBlock(xblk, yblk, buffer);
    1031             :     }
    1032             : 
    1033        1876 :     CPLDebug("MRF_IB", "Tinfo offset " CPL_FRMT_GIB ", size " CPL_FRMT_GIB "\n",
    1034             :              tinfo.offset, tinfo.size);
    1035             :     // If we have a tile, read it
    1036             : 
    1037             :     // Should use a permanent buffer, like the pbuffer mechanism
    1038             :     // Get a large buffer, in case we need to unzip
    1039             : 
    1040             :     // We add a padding of 3 bytes since in LERC1 decompression, we can
    1041             :     // dereference a unsigned int at the end of the buffer, that can be
    1042             :     // partially out of the buffer.
    1043             :     // Can be reproduced with :
    1044             :     // gdal_translate ../autotest/gcore/data/byte.tif out.mrf -of MRF -co
    1045             :     // COMPRESS=LERC -co OPTIONS=V1:YES -ot Float32 valgrind gdalinfo -checksum
    1046             :     // out.mrf Invalid read of size 4 at BitStuffer::read(unsigned char**,
    1047             :     // std::vector<unsigned int, std::allocator<unsigned int> >&) const
    1048             :     // (BitStuffer.cpp:153)
    1049             : 
    1050             :     // No stored tile should be larger than twice the raw size.
    1051        1876 :     if (tinfo.size <= 0 || tinfo.size > poMRFDS->pbsize * 2)
    1052             :     {
    1053           0 :         if (!poMRFDS->no_errors)
    1054             :         {
    1055           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    1056             :                      "Stored tile is too large: " CPL_FRMT_GIB, tinfo.size);
    1057           0 :             return CE_Failure;
    1058             :         }
    1059           0 :         return FillBlock(buffer);
    1060             :     }
    1061             : 
    1062        1876 :     VSILFILE *dfp = DataFP();
    1063             : 
    1064             :     // No data file to read from
    1065        1876 :     if (dfp == nullptr)
    1066           0 :         return CE_Failure;
    1067             : 
    1068        1876 :     void *data = VSIMalloc(static_cast<size_t>(tinfo.size + PADDING_BYTES));
    1069        1876 :     if (data == nullptr)
    1070             :     {
    1071           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1072             :                  "Could not allocate memory for tile size: " CPL_FRMT_GIB,
    1073             :                  tinfo.size);
    1074           0 :         return CE_Failure;
    1075             :     }
    1076             : 
    1077             :     // This part is not thread safe, but it is what GDAL expects
    1078        1876 :     VSIFSeekL(dfp, tinfo.offset, SEEK_SET);
    1079        1876 :     if (1 != VSIFReadL(data, static_cast<size_t>(tinfo.size), 1, dfp))
    1080             :     {
    1081           0 :         CPLFree(data);
    1082           0 :         if (poMRFDS->no_errors)
    1083           0 :             return FillBlock(buffer);
    1084           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unable to read data page, %d@%x",
    1085           0 :                  static_cast<int>(tinfo.size), static_cast<int>(tinfo.offset));
    1086           0 :         return CE_Failure;
    1087             :     }
    1088             : 
    1089             :     /* initialize padding bytes */
    1090        1876 :     memset(((char *)data) + static_cast<size_t>(tinfo.size), 0, PADDING_BYTES);
    1091        1876 :     buf_mgr src = {(char *)data, static_cast<size_t>(tinfo.size)};
    1092             :     buf_mgr dst;
    1093             : 
    1094        1876 :     auto start_time = steady_clock::now();
    1095             : 
    1096             :     // We got the data, do we need to decompress it before decoding?
    1097        1876 :     if (dodeflate)
    1098             :     {
    1099           9 :         if (img.pageSizeBytes > INT_MAX - 1440)
    1100             :         {
    1101           0 :             CPLFree(data);
    1102           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Page size is too big at %d",
    1103             :                      img.pageSizeBytes);
    1104           0 :             return CE_Failure;
    1105             :         }
    1106           9 :         dst.size =
    1107           9 :             img.pageSizeBytes +
    1108             :             1440;  // in case the packed page is a bit larger than the raw one
    1109           9 :         dst.buffer = static_cast<char *>(VSIMalloc(dst.size));
    1110           9 :         if (nullptr == dst.buffer)
    1111             :         {
    1112           0 :             CPLFree(data);
    1113           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate %d bytes",
    1114           0 :                      static_cast<int>(dst.size));
    1115           0 :             return CE_Failure;
    1116             :         }
    1117             : 
    1118           9 :         if (ZUnPack(src, dst, deflate_flags))
    1119             :         {  // Got it unpacked, update the pointers
    1120           9 :             CPLFree(data);
    1121           9 :             data = dst.buffer;
    1122           9 :             tinfo.size = dst.size;
    1123             :         }
    1124             :         else
    1125             :         {  // assume the page was not gzipped, warn only
    1126           0 :             CPLFree(dst.buffer);
    1127           0 :             if (!poMRFDS->no_errors)
    1128           0 :                 CPLError(CE_Warning, CPLE_AppDefined, "Can't inflate page!");
    1129             :         }
    1130             :     }
    1131             : 
    1132             : #if defined(ZSTD_SUPPORT)
    1133             :     // undo ZSTD
    1134        1867 :     else if (dozstd)
    1135             :     {
    1136          10 :         auto ctx = poMRFDS->getzsd();
    1137          10 :         if (!ctx)
    1138             :         {
    1139           0 :             CPLFree(data);
    1140           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Can't acquire ZSTD context");
    1141           0 :             return CE_Failure;
    1142             :         }
    1143          10 :         if (img.pageSizeBytes > INT_MAX - 1440)
    1144             :         {
    1145           0 :             CPLFree(data);
    1146           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Page is too large at %d",
    1147             :                      img.pageSizeBytes);
    1148           0 :             return CE_Failure;
    1149             :         }
    1150          10 :         dst.size =
    1151          10 :             img.pageSizeBytes +
    1152             :             1440;  // Allow for a slight increase from previous compressions
    1153          10 :         dst.buffer = static_cast<char *>(VSIMalloc(dst.size));
    1154          10 :         if (nullptr == dst.buffer)
    1155             :         {
    1156           0 :             CPLFree(data);
    1157           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate %d bytes",
    1158           0 :                      static_cast<int>(dst.size));
    1159           0 :             return CE_Failure;
    1160             :         }
    1161             : 
    1162          20 :         auto raw_size = ZSTD_decompressDCtx(ctx, dst.buffer, dst.size,
    1163          10 :                                             src.buffer, src.size);
    1164          10 :         if (ZSTD_isError(raw_size))
    1165             :         {  // assume page was not packed, warn only
    1166           0 :             CPLFree(dst.buffer);
    1167           0 :             if (!poMRFDS->no_errors)
    1168           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1169             :                          "Can't unpack ZSTD page!");
    1170             :         }
    1171             :         else
    1172             :         {
    1173          10 :             CPLFree(data);  // The compressed data
    1174          10 :             data = dst.buffer;
    1175          10 :             tinfo.size = raw_size;
    1176             :             // Might need to undo the rank sort
    1177          10 :             size_t ranks = 0;
    1178          10 :             if (img.comp == IL_NONE || img.comp == IL_ZSTD)
    1179          10 :                 ranks = static_cast<size_t>(GDALGetDataTypeSizeBytes(img.dt)) *
    1180          10 :                         img.pagesize.c;
    1181          10 :             if (ranks)
    1182             :             {
    1183          10 :                 src.buffer = static_cast<char *>(data);
    1184          10 :                 src.size = static_cast<size_t>(tinfo.size);
    1185          10 :                 derank(src, ranks);
    1186             :             }
    1187             :         }
    1188             :     }
    1189             : #endif
    1190             : 
    1191        1876 :     src.buffer = static_cast<char *>(data);
    1192        1876 :     src.size = static_cast<size_t>(tinfo.size);
    1193             : 
    1194             :     // After unpacking, the size has to be pageSizeBytes
    1195             :     // If pages are interleaved, use the dataset page buffer instead
    1196        1876 :     dst.buffer = reinterpret_cast<char *>(
    1197           8 :         (1 == cstride) ? buffer : poMRFDS->GetPBuffer());
    1198        1876 :     dst.size = img.pageSizeBytes;
    1199             : 
    1200        1876 :     if (poMRFDS->no_errors)
    1201           0 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    1202        1876 :     CPLErr ret = Decompress(dst, src);
    1203             : 
    1204        1876 :     poMRFDS->read_timer +=
    1205        1876 :         duration_cast<nanoseconds>(steady_clock::now() - start_time);
    1206             : 
    1207        1876 :     dst.size =
    1208        1876 :         img.pageSizeBytes;  // In case the decompress failed, force it back
    1209             : 
    1210             :     // Swap whatever we decompressed if we need to
    1211        1876 :     if (is_Endianness_Dependent(img.dt, img.comp) && (img.nbo != NET_ORDER))
    1212           0 :         swab_buff(dst, img);
    1213             : 
    1214        1876 :     CPLFree(data);
    1215        1876 :     if (poMRFDS->no_errors)
    1216             :     {
    1217           0 :         CPLPopErrorHandler();
    1218           0 :         if (ret != CE_None)  // Set each page buffer to the correct no data
    1219             :                              // value, then proceed
    1220           0 :             return (1 == cstride) ? FillBlock(buffer)
    1221           0 :                                   : FillBlock(xblk, yblk, buffer);
    1222             :     }
    1223             : 
    1224             :     // If pages are separate or we had errors, we're done
    1225        1876 :     if (1 == cstride || CE_None != ret)
    1226        1868 :         return ret;
    1227             : 
    1228             :     // De-interleave page from dataset buffer and return
    1229           8 :     return ReadInterleavedBlock(xblk, yblk, buffer);
    1230             : }
    1231             : 
    1232             : /**
    1233             :  *\brief Write a block from the provided buffer
    1234             :  *
    1235             :  * Same trick as read, use a temporary tile buffer for pixel interleave
    1236             :  * For band separate, use a
    1237             :  * Write the block once it has all the bands, report
    1238             :  * if a new block is started before the old one was completed
    1239             :  *
    1240             :  */
    1241             : 
    1242        5081 : CPLErr MRFRasterBand::IWriteBlock(int xblk, int yblk, void *buffer)
    1243             : {
    1244        5081 :     GInt32 cstride = img.pagesize.c;
    1245        5081 :     ILSize req(xblk, yblk, 0, (nBand - 1) / cstride, m_l);
    1246        5081 :     GUIntBig infooffset = IdxOffset(req, img);
    1247             : 
    1248        5081 :     CPLDebug("MRF_IB", "IWriteBlock %d,%d,0,%d, level %d, stride %d\n", xblk,
    1249             :              yblk, nBand, m_l, cstride);
    1250             : 
    1251             :     // Finish the Create call
    1252        5081 :     if (!poMRFDS->bCrystalized && !poMRFDS->Crystalize())
    1253             :     {
    1254           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error creating files");
    1255           0 :         return CE_Failure;
    1256             :     }
    1257             : 
    1258        5081 :     if (1 == cstride)
    1259             :     {  // Separate bands, we can write it as is
    1260             :         // Empty page skip
    1261             :         int success;
    1262        5070 :         double val = GetNoDataValue(&success);
    1263        5070 :         if (!success)
    1264        4998 :             val = 0.0;
    1265        5070 :         if (isAllVal(eDataType, buffer, img.pageSizeBytes, val))
    1266           1 :             return poMRFDS->WriteTile(nullptr, infooffset, 0);
    1267             : 
    1268             :         // Use the pbuffer to hold the compressed page before writing it
    1269        5069 :         poMRFDS->tile = ILSize();  // Mark it corrupt
    1270             : 
    1271             :         buf_mgr src;
    1272        5069 :         src.buffer = (char *)buffer;
    1273        5069 :         src.size = static_cast<size_t>(img.pageSizeBytes);
    1274        5069 :         buf_mgr dst = {(char *)poMRFDS->GetPBuffer(),
    1275        5069 :                        poMRFDS->GetPBufferSize()};
    1276             : 
    1277             :         // Swab the source before encoding if we need to
    1278        5069 :         if (is_Endianness_Dependent(img.dt, img.comp) && (img.nbo != NET_ORDER))
    1279           0 :             swab_buff(src, img);
    1280             : 
    1281        5069 :         auto start_time = steady_clock::now();
    1282             : 
    1283             :         // Compress functions need to return the compressed size in
    1284             :         // the bytes in buffer field
    1285        5069 :         Compress(dst, src);
    1286        5069 :         void *usebuff = dst.buffer;
    1287        5069 :         if (dodeflate)
    1288             :         {
    1289             :             usebuff =
    1290           9 :                 DeflateBlock(dst, poMRFDS->pbsize - dst.size, deflate_flags);
    1291           9 :             if (!usebuff)
    1292             :             {
    1293           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "MRF: Deflate error");
    1294           0 :                 return CE_Failure;
    1295             :             }
    1296             :         }
    1297             : 
    1298             : #if defined(ZSTD_SUPPORT)
    1299        5060 :         else if (dozstd)
    1300             :         {
    1301          11 :             size_t ranks = 0;  // Assume no need for byte rank sort
    1302          11 :             if (img.comp == IL_NONE || img.comp == IL_ZSTD)
    1303          11 :                 ranks = static_cast<size_t>(GDALGetDataTypeSizeBytes(img.dt));
    1304          11 :             usebuff = ZstdCompBlock(dst, poMRFDS->pbsize - dst.size, zstd_level,
    1305          11 :                                     poMRFDS->getzsc(), ranks);
    1306          11 :             if (!usebuff)
    1307             :             {
    1308           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1309             :                          "MRF: Zstd Compression error");
    1310           0 :                 return CE_Failure;
    1311             :             }
    1312             :         }
    1313             : #endif
    1314        5069 :         poMRFDS->write_timer +=
    1315        5069 :             duration_cast<nanoseconds>(steady_clock::now() - start_time);
    1316        5069 :         return poMRFDS->WriteTile(usebuff, infooffset, dst.size);
    1317             :     }
    1318             : 
    1319             :     // Multiple bands per page, use a temporary to assemble the page
    1320             :     // Temporary is large because we use it to hold both the uncompressed and
    1321             :     // the compressed
    1322          11 :     poMRFDS->tile = req;
    1323          11 :     poMRFDS->bdirty = 0;
    1324             : 
    1325             :     // Keep track of what bands are empty
    1326          11 :     GUIntBig empties = 0;
    1327             : 
    1328          11 :     void *tbuffer = VSIMalloc(img.pageSizeBytes + poMRFDS->pbsize);
    1329             : 
    1330          11 :     if (!tbuffer)
    1331             :     {
    1332           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1333             :                  "MRF: Can't allocate write buffer");
    1334           0 :         return CE_Failure;
    1335             :     }
    1336             : 
    1337             :     // Get the other bands from the block cache
    1338          44 :     for (int iBand = 0; iBand < poMRFDS->nBands; iBand++)
    1339             :     {
    1340          33 :         char *pabyThisImage = nullptr;
    1341          33 :         GDALRasterBlock *poBlock = nullptr;
    1342             : 
    1343          33 :         if (iBand == nBand - 1)
    1344             :         {
    1345          11 :             pabyThisImage = reinterpret_cast<char *>(buffer);
    1346          11 :             poMRFDS->bdirty |= bandbit();
    1347             :         }
    1348             :         else
    1349             :         {
    1350          22 :             GDALRasterBand *band = poMRFDS->GetRasterBand(iBand + 1);
    1351             :             // Pick the right overview
    1352          22 :             if (m_l)
    1353           0 :                 band = band->GetOverview(m_l - 1);
    1354             :             poBlock = (reinterpret_cast<MRFRasterBand *>(band))
    1355          22 :                           ->TryGetLockedBlockRef(xblk, yblk);
    1356          22 :             if (nullptr == poBlock)
    1357           0 :                 continue;
    1358             :             // This is where the image data is for this band
    1359             : 
    1360          22 :             pabyThisImage = reinterpret_cast<char *>(poBlock->GetDataRef());
    1361          22 :             poMRFDS->bdirty |= bandbit(iBand);
    1362             :         }
    1363             : 
    1364             :         // Keep track of empty bands, but encode them anyhow, in case some are
    1365             :         // not empty
    1366             :         int success;
    1367          33 :         double val = GetNoDataValue(&success);
    1368          33 :         if (!success)
    1369          33 :             val = 0.0;
    1370          33 :         if (isAllVal(eDataType, pabyThisImage, blockSizeBytes(), val))
    1371           6 :             empties |= bandbit(iBand);
    1372             : 
    1373             :             // Copy the data into the dataset buffer here
    1374             :             // Just the right mix of templates and macros make this real tidy
    1375             : #define CpySO(T)                                                               \
    1376             :     cpy_stride_out<T>((reinterpret_cast<T *>(tbuffer)) + iBand, pabyThisImage, \
    1377             :                       blockSizeBytes() / sizeof(T), cstride)
    1378             : 
    1379             :         // Build the page in tbuffer
    1380          33 :         switch (GDALGetDataTypeSize(eDataType) / 8)
    1381             :         {
    1382          33 :             case 1:
    1383          33 :                 CpySO(GByte);
    1384          33 :                 break;
    1385           0 :             case 2:
    1386           0 :                 CpySO(GInt16);
    1387           0 :                 break;
    1388           0 :             case 4:
    1389           0 :                 CpySO(GInt32);
    1390           0 :                 break;
    1391           0 :             case 8:
    1392           0 :                 CpySO(GIntBig);
    1393           0 :                 break;
    1394           0 :             default:
    1395             :             {
    1396           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1397             :                          "MRF: Write datatype of %d bytes "
    1398             :                          "not implemented",
    1399           0 :                          GDALGetDataTypeSize(eDataType) / 8);
    1400           0 :                 if (poBlock != nullptr)
    1401             :                 {
    1402           0 :                     poBlock->MarkClean();
    1403           0 :                     poBlock->DropLock();
    1404             :                 }
    1405           0 :                 CPLFree(tbuffer);
    1406           0 :                 return CE_Failure;
    1407             :             }
    1408             :         }
    1409             : 
    1410          33 :         if (poBlock != nullptr)
    1411             :         {
    1412          22 :             poBlock->MarkClean();
    1413          22 :             poBlock->DropLock();
    1414             :         }
    1415             :     }
    1416             : 
    1417             :     // Should keep track of the individual band buffers and only mix them if
    1418             :     // this is not an empty page ( move the Copy with Stride Out from above
    1419             :     // below this test This way works fine, but it does work extra for empty
    1420             :     // pages
    1421             : 
    1422          11 :     if (GIntBig(empties) == AllBandMask())
    1423             :     {
    1424           0 :         CPLFree(tbuffer);
    1425           0 :         return poMRFDS->WriteTile(nullptr, infooffset, 0);
    1426             :     }
    1427             : 
    1428          11 :     if (poMRFDS->bdirty != AllBandMask())
    1429           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    1430             :                  "MRF: IWrite, band dirty mask is " CPL_FRMT_GIB
    1431             :                  " instead of " CPL_FRMT_GIB,
    1432           0 :                  poMRFDS->bdirty, AllBandMask());
    1433             : 
    1434             :     buf_mgr src;
    1435          11 :     src.buffer = (char *)tbuffer;
    1436          11 :     src.size = static_cast<size_t>(img.pageSizeBytes);
    1437             : 
    1438             :     // Use the space after pagesizebytes for compressed output, it is of pbsize
    1439          11 :     char *outbuff = (char *)tbuffer + img.pageSizeBytes;
    1440             : 
    1441          11 :     buf_mgr dst = {outbuff, poMRFDS->pbsize};
    1442             :     CPLErr ret;
    1443             : 
    1444          11 :     auto start_time = steady_clock::now();
    1445             : 
    1446          11 :     ret = Compress(dst, src);
    1447          11 :     if (ret != CE_None)
    1448             :     {
    1449             :         // Compress failed, write it as an empty tile
    1450           0 :         CPLFree(tbuffer);
    1451           0 :         poMRFDS->WriteTile(nullptr, infooffset, 0);
    1452           0 :         return CE_None;  // Should report the error, but it triggers partial
    1453             :                          // band attempts
    1454             :     }
    1455             : 
    1456             :     // Where the output is, in case we deflate
    1457          11 :     void *usebuff = outbuff;
    1458          11 :     if (dodeflate)
    1459             :     {
    1460             :         // Move the packed part at the start of tbuffer, to make more space
    1461             :         // available
    1462           0 :         memcpy(tbuffer, outbuff, dst.size);
    1463           0 :         dst.buffer = static_cast<char *>(tbuffer);
    1464           0 :         usebuff = DeflateBlock(dst,
    1465           0 :                                static_cast<size_t>(img.pageSizeBytes) +
    1466           0 :                                    poMRFDS->pbsize - dst.size,
    1467             :                                deflate_flags);
    1468           0 :         if (!usebuff)
    1469           0 :             CPLError(CE_Failure, CPLE_AppDefined, "MRF: Deflate error");
    1470             :     }
    1471             : 
    1472             : #if defined(ZSTD_SUPPORT)
    1473          11 :     else if (dozstd)
    1474             :     {
    1475           1 :         memcpy(tbuffer, outbuff, dst.size);
    1476           1 :         dst.buffer = static_cast<char *>(tbuffer);
    1477           1 :         size_t ranks = 0;  // Assume no need for byte rank sort
    1478           1 :         if (img.comp == IL_NONE || img.comp == IL_ZSTD)
    1479           1 :             ranks =
    1480           1 :                 static_cast<size_t>(GDALGetDataTypeSizeBytes(img.dt)) * cstride;
    1481           3 :         usebuff = ZstdCompBlock(dst,
    1482           1 :                                 static_cast<size_t>(img.pageSizeBytes) +
    1483           1 :                                     poMRFDS->pbsize - dst.size,
    1484           1 :                                 zstd_level, poMRFDS->getzsc(), ranks);
    1485           1 :         if (!usebuff)
    1486           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1487             :                      "MRF: ZStd compression error");
    1488             :     }
    1489             : #endif
    1490             : 
    1491          11 :     poMRFDS->write_timer +=
    1492          11 :         duration_cast<nanoseconds>(steady_clock::now() - start_time);
    1493             : 
    1494          11 :     if (!usebuff)
    1495             :     {  // Error was signaled
    1496           0 :         CPLFree(tbuffer);
    1497           0 :         poMRFDS->WriteTile(nullptr, infooffset, 0);
    1498           0 :         poMRFDS->bdirty = 0;
    1499           0 :         return CE_Failure;
    1500             :     }
    1501             : 
    1502          11 :     ret = poMRFDS->WriteTile(usebuff, infooffset, dst.size);
    1503          11 :     CPLFree(tbuffer);
    1504             : 
    1505          11 :     poMRFDS->bdirty = 0;
    1506          11 :     return ret;
    1507             : }
    1508             : 
    1509             : //
    1510             : // Tests if a given block exists without reading it
    1511             : // returns false only when it is definitely not existing
    1512             : //
    1513         160 : bool MRFRasterBand::TestBlock(int xblk, int yblk)
    1514             : {
    1515             :     // When bypassing the cache, assume all blocks are valid
    1516         160 :     if (poMRFDS->bypass_cache && !poMRFDS->source.empty())
    1517           0 :         return true;
    1518             : 
    1519             :     // Blocks outside of image have no data by default
    1520         160 :     if (xblk < 0 || yblk < 0 || xblk >= img.pagecount.x ||
    1521         146 :         yblk >= img.pagecount.y)
    1522          25 :         return false;
    1523             : 
    1524             :     ILIdx tinfo;
    1525         135 :     GInt32 cstride = img.pagesize.c;
    1526         135 :     ILSize req(xblk, yblk, 0, (nBand - 1) / cstride, m_l);
    1527             : 
    1528         135 :     if (CE_None != poMRFDS->ReadTileIdx(tinfo, req, img))
    1529             :         // Got an error reading the tile index
    1530           0 :         return !poMRFDS->no_errors;
    1531             : 
    1532             :     // Got an index, if the size is readable, the block does exist
    1533         135 :     if (0 < tinfo.size && tinfo.size < poMRFDS->pbsize * 2)
    1534         135 :         return true;
    1535             : 
    1536             :     // We are caching, but the tile has not been checked, so it could exist
    1537           0 :     return (!poMRFDS->source.empty() && 0 == tinfo.offset);
    1538             : }
    1539             : 
    1540         183 : int MRFRasterBand::GetOverviewCount()
    1541             : {
    1542             :     // First try internal overviews
    1543         183 :     int nInternalOverviewCount = static_cast<int>(overviews.size());
    1544         183 :     if (nInternalOverviewCount > 0)
    1545         137 :         return nInternalOverviewCount;
    1546          46 :     return GDALPamRasterBand::GetOverviewCount();
    1547             : }
    1548             : 
    1549         158 : GDALRasterBand *MRFRasterBand::GetOverview(int n)
    1550             : {
    1551             :     // First try internal overviews
    1552         158 :     if (n >= 0 && n < (int)overviews.size())
    1553          85 :         return overviews[n];
    1554          73 :     return GDALPamRasterBand::GetOverview(n);
    1555             : }
    1556             : 
    1557             : NAMESPACE_MRF_END

Generated by: LCOV version 1.14