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

Generated by: LCOV version 1.14