LCOV - code coverage report
Current view: top level - frmts/mrf - LERC_band.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 290 381 76.1 %
Date: 2026-06-18 12:02:19 Functions: 29 42 69.0 %

          Line data    Source code
       1             : /*
       2             : Copyright 2013-2021 Esri
       3             : Licensed under the Apache License, Version 2.0 (the "License");
       4             : you may not use this file except in compliance with the License.
       5             : You may obtain a copy of the License at
       6             : http://www.apache.org/licenses/LICENSE-2.0
       7             : Unless required by applicable law or agreed to in writing, software
       8             : distributed under the License is distributed on an "AS IS" BASIS,
       9             : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      10             : See the License for the specific language governing permissions and
      11             : limitations under the License.
      12             : A local copy of the license and additional notices are located with the
      13             : source distribution at:
      14             : http://github.com/Esri/lerc/
      15             : 
      16             : LERC band implementation
      17             : LERC page compression and decompression functions
      18             : 
      19             : Authors:  Lucian Plesea
      20             : */
      21             : 
      22             : #include "marfa.h"
      23             : #include <algorithm>
      24             : #include <vector>
      25             : #include "LERCV1/Lerc1Image.h"
      26             : 
      27             : #include "gdal_priv_templates.hpp"
      28             : #include "gdal_openinfo.h"
      29             : 
      30             : // Requires lerc at least 2v4, where the c_api changed, but there is no good way
      31             : // to check
      32             : #include <Lerc_c_api.h>
      33             : #include <Lerc_types.h>
      34             : 
      35             : #ifndef LERC_AT_LEAST_VERSION
      36             : #define LERC_AT_LEAST_VERSION(maj, min, patch) 0
      37             : #endif
      38             : 
      39             : // name of internal or external libLerc namespace
      40             : #if defined(USING_NAMESPACE_LERC)
      41             : #define L2NS GDAL_LercNS
      42             : #else
      43             : // External lerc
      44             : #define L2NS LercNS
      45             : #endif
      46             : 
      47             : USING_NAMESPACE_LERC1
      48             : NAMESPACE_MRF_START
      49             : 
      50             : // Read an unaligned 4 byte little endian int from location p, advances pointer
      51         150 : static void READ_GINT32(int &X, const char *&p)
      52             : {
      53         150 :     memcpy(&X, p, sizeof(GInt32));
      54         150 :     p += sizeof(GInt32);
      55         150 : }
      56             : 
      57          15 : static void READ_FLOAT(float &X, const char *&p)
      58             : {
      59          15 :     memcpy(&X, p, sizeof(float));
      60          15 :     p += sizeof(float);
      61          15 : }
      62             : 
      63             : //
      64             : // Check that a buffer contains a supported Lerc1 blob, the type supported by
      65             : // MRF Can't really check everything without decoding, this just checks the main
      66             : // structure returns actual size if it is Lerc1 with size < sz returns 0 if
      67             : // format doesn't match returns -1 if Lerc1 but size can't be determined
      68             : //
      69             : // returns -<actual size> if actual size > sz
      70             : 
      71          15 : static int checkV1(const char *s, size_t sz)
      72             : {
      73             :     GInt32 nBytesMask, nBytesData;
      74             : 
      75             :     // Header is 34 bytes
      76             :     // band header is 16, first mask band then data band
      77          15 :     if (sz < static_cast<size_t>(
      78          15 :                  Lerc1Image::computeNumBytesNeededToWriteVoidImage()))
      79           0 :         return 0;
      80             :     // First ten bytes are ASCII signature
      81          15 :     if (!STARTS_WITH(s, "CntZImage "))
      82           0 :         return 0;
      83          15 :     s += 10;
      84             : 
      85             :     // Version 11
      86             :     int i;
      87          15 :     READ_GINT32(i, s);
      88          15 :     if (i != 11)
      89           0 :         return 0;
      90             : 
      91             :     // Type 8 is CntZ
      92          15 :     READ_GINT32(i, s);
      93          15 :     if (i != 8)
      94           0 :         return 0;
      95             : 
      96             :     // Height
      97          15 :     READ_GINT32(i, s);  // Arbitrary number in Lerc1Image::read()
      98          15 :     if (i > 20000 || i <= 0)
      99           0 :         return 0;
     100             : 
     101             :     // Width
     102          15 :     READ_GINT32(i, s);
     103          15 :     if (i > 20000 || i <= 0)
     104           0 :         return 0;
     105             : 
     106             :     // Skip the max val stored as double
     107          15 :     s += sizeof(double);
     108             : 
     109             :     // First header should be the mask, which mean 0 blocks
     110             :     // Height
     111          15 :     READ_GINT32(i, s);
     112          15 :     if (i != 0)
     113           0 :         return 0;
     114             : 
     115             :     // WIDTH
     116          15 :     READ_GINT32(i, s);
     117          15 :     if (i != 0)
     118           0 :         return 0;
     119             : 
     120          15 :     READ_GINT32(nBytesMask, s);
     121          15 :     if (nBytesMask < 0)
     122           0 :         return 0;
     123             : 
     124             :     // mask max value, 0 or 1 as float
     125             :     float val;
     126          15 :     READ_FLOAT(val, s);
     127          15 :     if (val != 0.0f && val != 1.0f)
     128           0 :         return 0;
     129             : 
     130             :     // If data header can't be read the actual size is unknown
     131          15 :     if (nBytesMask > INT_MAX - 66 || static_cast<size_t>(66 + nBytesMask) >= sz)
     132             :     {
     133           0 :         return -1;
     134             :     }
     135             : 
     136          15 :     s += nBytesMask;
     137             : 
     138             :     // Data Band header
     139          15 :     READ_GINT32(i,
     140             :                 s);  // number of full height blocks, never single pixel blocks
     141          15 :     if (i <= 0 || i > 10000)
     142           0 :         return 0;
     143             : 
     144          15 :     READ_GINT32(i,
     145             :                 s);  // number of full width blocks, never single pixel blocks
     146          15 :     if (i <= 0 || i > 10000)
     147           0 :         return 0;
     148             : 
     149          15 :     READ_GINT32(nBytesData, s);
     150          15 :     if (nBytesData < 0)
     151           0 :         return 0;
     152             : 
     153             :     // Actual LERC blob size
     154          15 :     if (66 + nBytesMask > INT_MAX - nBytesData)
     155           0 :         return -1;
     156          15 :     int size = static_cast<int>(66 + nBytesMask + nBytesData);
     157          15 :     return (static_cast<size_t>(size) > sz) ? -size : size;
     158             : }
     159             : 
     160             : // Load a buffer of type T into a LERC1 zImg, with a given stride
     161             : template <typename T>
     162          12 : static void Lerc1ImgFill(Lerc1Image &zImg, T *src, const ILImage &img,
     163             :                          GInt32 stride)
     164             : {
     165          12 :     int w = img.pagesize.x;
     166          12 :     int h = img.pagesize.y;
     167          12 :     zImg.resize(w, h);
     168          12 :     const float ndv = static_cast<float>(img.hasNoData ? img.NoDataValue : 0);
     169          12 :     if (stride == 1)
     170             :     {
     171        4617 :         for (int row = 0; row < h; row++)
     172     2363904 :             for (int col = 0; col < w; col++)
     173             :             {
     174     2359296 :                 float val = static_cast<float>(*src++);
     175     2359296 :                 zImg(row, col) = val;
     176     2359296 :                 zImg.SetMask(row, col, !CPLIsEqual(ndv, val));
     177             :             }
     178           9 :         return;
     179             :     }
     180        1539 :     for (int row = 0; row < h; row++)
     181      787968 :         for (int col = 0; col < w; col++)
     182             :         {
     183      786432 :             float val = static_cast<float>(*src);
     184      786432 :             src += stride;
     185      786432 :             zImg(row, col) = val;
     186      786432 :             zImg.SetMask(row, col, !CPLIsEqual(ndv, val));
     187             :         }
     188             : }
     189             : 
     190             : // Unload LERC1 zImg into a type T buffer
     191             : template <typename T>
     192          15 : static bool Lerc1ImgUFill(Lerc1Image &zImg, T *dst, const ILImage &img,
     193             :                           GInt32 stride)
     194             : {
     195          14 :     const T ndv =
     196          13 :         static_cast<T>(img.hasNoData && GDALIsValueInRange<T>(img.NoDataValue)
     197           9 :                            ? img.NoDataValue
     198             :                            : 0);
     199          15 :     if (img.pagesize.y != zImg.getHeight() || img.pagesize.x != zImg.getWidth())
     200           0 :         return false;
     201          15 :     int w = img.pagesize.x;
     202          15 :     int h = img.pagesize.y;
     203          15 :     if (1 == stride)
     204             :     {
     205        6159 :         for (int row = 0; row < h; row++)
     206             :         {
     207     3154954 :             for (int col = 0; col < w; col++)
     208             :             {
     209     3148807 :                 if (zImg.IsValid(row, col))
     210             :                 {
     211       27192 :                     GDALCopyWord(zImg(row, col), *dst);
     212             :                 }
     213             :                 else
     214             :                 {
     215     3121611 :                     *dst = ndv;
     216             :                 }
     217     3148807 :                 ++dst;
     218             :             }
     219             :         }
     220          12 :         return true;
     221             :     }
     222        1539 :     for (int row = 0; row < h; row++)
     223             :     {
     224      787968 :         for (int col = 0; col < w; col++)
     225             :         {
     226      786432 :             if (zImg.IsValid(row, col))
     227             :             {
     228      239713 :                 GDALCopyWord(zImg(row, col), *dst);
     229             :             }
     230             :             else
     231             :             {
     232      546719 :                 *dst = ndv;
     233             :             }
     234      786432 :             dst += stride;
     235             :         }
     236             :     }
     237           3 :     return true;
     238             : }
     239             : 
     240          10 : static CPLErr CompressLERC1(buf_mgr &dst, buf_mgr &src, const ILImage &img,
     241             :                             double precision)
     242             : {
     243          20 :     Lerc1Image zImg;
     244          10 :     GInt32 stride = img.pagesize.c;
     245          10 :     Lerc1NS::Byte *ptr = reinterpret_cast<Lerc1NS::Byte *>(dst.buffer);
     246             : 
     247          22 :     for (int c = 0; c < stride; c++)
     248             :     {
     249             : #define FILL(T)                                                                \
     250             :     Lerc1ImgFill(zImg, reinterpret_cast<T *>(src.buffer) + c, img, stride)
     251          12 :         switch (img.dt)
     252             :         {
     253           5 :             case GDT_UInt8:
     254           5 :                 FILL(GByte);
     255           5 :                 break;
     256           1 :             case GDT_UInt16:
     257           1 :                 FILL(GUInt16);
     258           1 :                 break;
     259           1 :             case GDT_Int16:
     260           1 :                 FILL(GInt16);
     261           1 :                 break;
     262           1 :             case GDT_Int32:
     263           1 :                 FILL(GInt32);
     264           1 :                 break;
     265           1 :             case GDT_UInt32:
     266           1 :                 FILL(GUInt32);
     267           1 :                 break;
     268           2 :             case GDT_Float32:
     269           2 :                 FILL(float);
     270           2 :                 break;
     271           1 :             case GDT_Float64:
     272           1 :                 FILL(double);
     273           1 :                 break;
     274           0 :             default:
     275           0 :                 break;
     276             :         }
     277             : #undef FILL
     278          12 :         if (!zImg.write(&ptr, precision))
     279             :         {
     280           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     281             :                      "MRF: Error during LERC compression");
     282           0 :             return CE_Failure;
     283             :         }
     284             :     }
     285             : 
     286             :     // write changes the value of the pointer, we can find the size by testing
     287             :     // how far it moved Add a couple of bytes, to avoid buffer overflow on
     288             :     // reading
     289          10 :     dst.size = reinterpret_cast<char *>(ptr) - dst.buffer + PADDING_BYTES;
     290          10 :     CPLDebug("MRF_LERC", "LERC Compressed to %d\n", (int)dst.size);
     291          10 :     return CE_None;
     292             : }
     293             : 
     294             : // LERC 1 Decompression
     295          13 : static CPLErr DecompressLERC1(buf_mgr &dst, const buf_mgr &src,
     296             :                               const ILImage &img)
     297             : {
     298          26 :     Lerc1Image zImg;
     299             : 
     300             :     // need to add the padding bytes so that out-of-buffer-access
     301          13 :     size_t nRemainingBytes = src.size + PADDING_BYTES;
     302          13 :     Lerc1NS::Byte *ptr = reinterpret_cast<Lerc1NS::Byte *>(src.buffer);
     303          13 :     GInt32 stride = img.pagesize.c;
     304          28 :     for (int c = 0; c < stride; c++)
     305             :     {
     306             :         // Check that input passes snicker test
     307          15 :         if (checkV1(reinterpret_cast<char *>(ptr), nRemainingBytes) <= 0)
     308             :         {
     309           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     310             :                      "MRF: LERC1 tile format error");
     311           0 :             return CE_Failure;
     312             :         }
     313             : 
     314          15 :         if (!zImg.read(&ptr, nRemainingBytes, 1e12))
     315             :         {
     316           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     317             :                      "MRF: Error during LERC decompression");
     318           0 :             return CE_Failure;
     319             :         }
     320             : 
     321             :         // Unpack from zImg to dst buffer, calling the right type
     322          15 :         bool success = false;
     323             : #define UFILL(T)                                                               \
     324             :     success = Lerc1ImgUFill(zImg, reinterpret_cast<T *>(dst.buffer) + c, img,  \
     325             :                             stride)
     326          15 :         switch (img.dt)
     327             :         {
     328           6 :             case GDT_UInt8:
     329           6 :                 UFILL(GByte);
     330           6 :                 break;
     331           0 :             case GDT_Int8:
     332           0 :                 UFILL(GInt8);
     333           0 :                 break;
     334           1 :             case GDT_UInt16:
     335           1 :                 UFILL(GUInt16);
     336           1 :                 break;
     337           1 :             case GDT_Int16:
     338           1 :                 UFILL(GInt16);
     339           1 :                 break;
     340           1 :             case GDT_Int32:
     341           1 :                 UFILL(GInt32);
     342           1 :                 break;
     343           1 :             case GDT_UInt32:
     344           1 :                 UFILL(GUInt32);
     345           1 :                 break;
     346           4 :             case GDT_Float32:
     347           4 :                 UFILL(float);
     348           4 :                 break;
     349           1 :             case GDT_Float64:
     350           1 :                 UFILL(double);
     351           1 :                 break;
     352           0 :             default:
     353           0 :                 break;
     354             :         }
     355             : #undef UFILL
     356          15 :         if (!success)
     357             :         {
     358           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     359             :                      "MRF: Error during LERC decompression");
     360           0 :             return CE_Failure;
     361             :         }
     362             :     }
     363             : 
     364          13 :     return CE_None;
     365             : }
     366             : 
     367             : // Lerc2
     368             : 
     369        6423 : static L2NS::DataType GDTtoL2(GDALDataType dt)
     370             : {
     371             :     L2NS::DataType L2dt;
     372        6423 :     switch (dt)
     373             :     {
     374           2 :         case GDT_Int16:
     375           2 :             L2dt = L2NS::DataType::dt_short;
     376           2 :             break;
     377           2 :         case GDT_UInt16:
     378           2 :             L2dt = L2NS::DataType::dt_ushort;
     379           2 :             break;
     380           2 :         case GDT_Int32:
     381           2 :             L2dt = L2NS::DataType::dt_int;
     382           2 :             break;
     383           2 :         case GDT_UInt32:
     384           2 :             L2dt = L2NS::DataType::dt_uint;
     385           2 :             break;
     386           2 :         case GDT_Float32:
     387           2 :             L2dt = L2NS::DataType::dt_float;
     388           2 :             break;
     389           4 :         case GDT_Float64:
     390           4 :             L2dt = L2NS::DataType::dt_double;
     391           4 :             break;
     392        6409 :         default:
     393        6409 :             L2dt = L2NS::DataType::dt_uchar;
     394             :     }
     395        6423 :     return L2dt;
     396             : }
     397             : 
     398             : // Populate a LERC2 bitmask based on comparison with the image no data value
     399             : // Returns the number of NoData values found
     400             : template <typename T>
     401           1 : static size_t MaskFill(std::vector<Lerc1NS::Byte> &bm, const T *src,
     402             :                        const ILImage &img)
     403             : {
     404           1 :     size_t w = static_cast<size_t>(img.pagesize.x);
     405           1 :     size_t h = static_cast<size_t>(img.pagesize.y);
     406           1 :     size_t stride = static_cast<size_t>(img.pagesize.c);
     407           1 :     size_t nndv = 0;
     408             : 
     409           1 :     bm.resize(w * h);
     410             : 
     411           1 :     T ndv = static_cast<T>(img.NoDataValue);
     412           1 :     if (!img.hasNoData)
     413           0 :         ndv = 0;  // It really doesn't get called when img doesn't have
     414             :                   // NoDataValue
     415      262145 :     for (size_t i = 0; i < bm.size(); i++)
     416             :     {
     417      262144 :         if (ndv == src[i * stride])
     418             :         {
     419          57 :             bm[i] = 0;
     420          57 :             nndv++;
     421             :         }
     422             :         else
     423             :         {
     424      262087 :             bm[i] = 1;
     425             :         }
     426             :     }
     427             : 
     428           1 :     return nndv;
     429             : }
     430             : 
     431             : // Fill in no data values based on a LERC2 bitmask
     432             : template <typename T>
     433           1 : static void UnMask(std::vector<Lerc1NS::Byte> &bm, T *data, const ILImage &img)
     434             : {
     435           1 :     size_t w = static_cast<size_t>(img.pagesize.x);
     436           1 :     size_t h = static_cast<size_t>(img.pagesize.y);
     437           1 :     size_t stride = static_cast<size_t>(img.pagesize.c);
     438             : 
     439           1 :     if (bm.size() != w * h)
     440           0 :         return;
     441             : 
     442           1 :     T ndv = T(img.NoDataValue);
     443           1 :     if (stride == 1)
     444             :     {
     445      262145 :         for (size_t i = 0; i < w * h; i++)
     446      262144 :             if (!bm[i])
     447           0 :                 data[i] = ndv;
     448             :     }
     449             :     else
     450             :     {
     451           0 :         for (size_t i = 0; i < w * h; i++)
     452           0 :             if (!bm[i])
     453           0 :                 for (size_t c = 0; c < stride; c++)
     454           0 :                     data[i * stride + c] = ndv;
     455             :     }
     456             : }
     457             : 
     458        4812 : static CPLErr CompressLERC2(buf_mgr &dst, buf_mgr &src, const ILImage &img,
     459             :                             double precision, int l2ver)
     460             : {
     461        4812 :     auto w = static_cast<int>(img.pagesize.x);
     462        4812 :     auto h = static_cast<int>(img.pagesize.y);
     463        4812 :     auto stride = static_cast<int>(img.pagesize.c);
     464             : 
     465             :     // build a mask
     466        9624 :     std::vector<Lerc1NS::Byte> bm;
     467        4812 :     size_t nndv = 0;
     468        4812 :     if (img.hasNoData)
     469             :     {  // Only build a bitmask if no data value is defined
     470           1 :         switch (img.dt)
     471             :         {
     472             : 
     473             : #define MASK(T) nndv = MaskFill(bm, reinterpret_cast<T *>(src.buffer), img)
     474             : 
     475           1 :             case GDT_UInt8:
     476           1 :                 MASK(GByte);
     477           1 :                 break;
     478           0 :             case GDT_UInt16:
     479           0 :                 MASK(GUInt16);
     480           0 :                 break;
     481           0 :             case GDT_Int16:
     482           0 :                 MASK(GInt16);
     483           0 :                 break;
     484           0 :             case GDT_Int32:
     485           0 :                 MASK(GInt32);
     486           0 :                 break;
     487           0 :             case GDT_UInt32:
     488           0 :                 MASK(GUInt32);
     489           0 :                 break;
     490           0 :             case GDT_Float32:
     491           0 :                 MASK(float);
     492           0 :                 break;
     493           0 :             case GDT_Float64:
     494           0 :                 MASK(double);
     495           0 :                 break;
     496           0 :             default:
     497           0 :                 break;
     498             : 
     499             : #undef MASK
     500             :         }
     501             :     }
     502             : 
     503        4812 :     unsigned int sz = 0;
     504        4812 :     auto pbm = bm.data();
     505        4812 :     if (!bm.empty() && nndv != bm.size())
     506           1 :         pbm = nullptr;
     507       14436 :     auto status = lerc_encodeForVersion(
     508        4812 :         reinterpret_cast<void *>(src.buffer), l2ver,
     509        4812 :         static_cast<unsigned int>(GDTtoL2(img.dt)), stride, w, h, 1,
     510             : #if LERC_AT_LEAST_VERSION(3, 0, 0)
     511             :         pbm ? 1 : 0,
     512             : #endif
     513        4812 :         pbm, precision, reinterpret_cast<Lerc1NS::Byte *>(dst.buffer),
     514        4812 :         static_cast<unsigned int>(dst.size), &sz);
     515             : 
     516        4812 :     if (L2NS::ErrCode::Ok != static_cast<L2NS::ErrCode>(status) ||
     517        4812 :         sz > (dst.size - PADDING_BYTES))
     518             :     {
     519           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     520             :                  "MRF: Error during LERC2 compression");
     521           0 :         return CE_Failure;
     522             :     }
     523             : 
     524        4812 :     dst.size = static_cast<size_t>(sz) + PADDING_BYTES;
     525        4812 :     return CE_None;
     526             : }
     527             : 
     528             : // LERC1 splits of early, so this is mostly LERC2
     529        1624 : CPLErr LERC_Band::Decompress(buf_mgr &dst, buf_mgr &src)
     530             : {
     531        2689 :     if (src.size >= Lerc1Image::computeNumBytesNeededToWriteVoidImage() &&
     532        1065 :         IsLerc1(src.buffer))
     533          13 :         return DecompressLERC1(dst, src, img);
     534             : 
     535             :     // Can only be LERC2 here, verify
     536        1611 :     if (src.size < 50 || !IsLerc2(src.buffer))
     537             :     {
     538           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: Not a lerc tile");
     539           0 :         return CE_Failure;
     540             :     }
     541             : 
     542        1611 :     auto w = static_cast<int>(img.pagesize.x);
     543        1611 :     auto h = static_cast<int>(img.pagesize.y);
     544        1611 :     auto stride = static_cast<int>(img.pagesize.c);
     545             : 
     546        3222 :     std::vector<Lerc1NS::Byte> bm;
     547        1611 :     const int nMasks = img.hasNoData ? 1 : 0;
     548        1611 :     if (nMasks > 0)
     549           1 :         bm.resize(static_cast<size_t>(w) * static_cast<size_t>(h) * nMasks);
     550        1611 :     auto pbm = bm.data();
     551        1611 :     if (bm.empty())
     552        1610 :         pbm = nullptr;
     553             : 
     554             :     // Decoding may fail for many different reasons, including input not
     555             :     // matching tile expectations
     556             :     auto status =
     557        3222 :         lerc_decode(reinterpret_cast<Lerc1NS::Byte *>(src.buffer),
     558        1611 :                     static_cast<unsigned int>(src.size),
     559             : #if LERC_AT_LEAST_VERSION(3, 0, 0)
     560             :                     nMasks,
     561             : #endif
     562             :                     pbm, stride, w, h, 1,
     563        1611 :                     static_cast<unsigned int>(GDTtoL2(img.dt)), dst.buffer);
     564        1611 :     if (L2NS::ErrCode::Ok != static_cast<L2NS::ErrCode>(status))
     565             :     {
     566           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     567             :                  "MRF: Error decoding Lerc: status=%d", status);
     568           0 :         return CE_Failure;
     569             :     }
     570             : 
     571             :     // No mask means we're done
     572        1611 :     if (bm.empty())
     573        1610 :         return CE_None;
     574             : 
     575             :     // Fill in no data values
     576           1 :     switch (img.dt)
     577             :     {
     578             : #define UNMASK(T) UnMask(bm, reinterpret_cast<T *>(dst.buffer), img)
     579           1 :         case GDT_UInt8:
     580           1 :             UNMASK(GByte);
     581           1 :             break;
     582           0 :         case GDT_UInt16:
     583           0 :             UNMASK(GUInt16);
     584           0 :             break;
     585           0 :         case GDT_Int16:
     586           0 :             UNMASK(GInt16);
     587           0 :             break;
     588           0 :         case GDT_Int32:
     589           0 :             UNMASK(GInt32);
     590           0 :             break;
     591           0 :         case GDT_UInt32:
     592           0 :             UNMASK(GUInt32);
     593           0 :             break;
     594           0 :         case GDT_Float32:
     595           0 :             UNMASK(float);
     596           0 :             break;
     597           0 :         case GDT_Float64:
     598           0 :             UNMASK(double);
     599           0 :             break;
     600           0 :         default:
     601           0 :             break;
     602             : #undef DECODE
     603             :     }
     604           1 :     return CE_None;
     605             : }
     606             : 
     607        4822 : CPLErr LERC_Band::Compress(buf_mgr &dst, buf_mgr &src)
     608             : {
     609        4822 :     if (version == 2)
     610        4812 :         return CompressLERC2(dst, src, img, precision, l2ver);
     611             :     else
     612          10 :         return CompressLERC1(dst, src, img, precision);
     613             : }
     614             : 
     615             : #if defined(GDAL_USE_LERC_INTERNAL)
     616           4 : CPLXMLNode *LERC_Band::GetMRFConfig(GDALOpenInfo *poOpenInfo)
     617             : {
     618             :     // Size of Lerc1 empty file is 67 Anything under 50 bytes
     619             :     // can't be lerc
     620           4 :     if (poOpenInfo->eAccess != GA_ReadOnly ||
     621           4 :         poOpenInfo->pszFilename == nullptr ||
     622           4 :         poOpenInfo->pabyHeader == nullptr ||
     623           4 :         strlen(poOpenInfo->pszFilename) < 1 || poOpenInfo->nHeaderBytes < 50)
     624           0 :         return nullptr;
     625             : 
     626             :     // Check the header too
     627           4 :     char *psz = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
     628           8 :     CPLString sHeader;
     629           4 :     sHeader.assign(psz, psz + poOpenInfo->nHeaderBytes);
     630           4 :     if (!IsLerc1(sHeader))
     631           0 :         return nullptr;
     632             : 
     633           4 :     GDALDataType dt = GDT_Unknown;  // Use this as a validity flag
     634             : 
     635             :     // Use this structure to fetch width and height
     636           4 :     ILSize size(-1, -1, 1, 1, 1);
     637             : 
     638           8 :     if (IsLerc1(sHeader) &&
     639           4 :         sHeader.size() >= Lerc1Image::computeNumBytesNeededToWriteVoidImage())
     640             :     {
     641           4 :         if (Lerc1Image::getwh(reinterpret_cast<Lerc1NS::Byte *>(psz),
     642           4 :                               poOpenInfo->nHeaderBytes, size.x, size.y))
     643           4 :             dt = GDALGetDataTypeByName(CSLFetchNameValueDef(
     644           4 :                 poOpenInfo->papszOpenOptions, "DATATYPE", "Byte"));
     645             :     }
     646             : 
     647           4 :     if (size.x <= 0 || size.y <= 0 || dt == GDT_Unknown)
     648           0 :         return nullptr;
     649             : 
     650             :     // Build and return the MRF configuration for a single tile reader
     651           4 :     CPLXMLNode *config = CPLCreateXMLNode(nullptr, CXT_Element, "MRF_META");
     652           4 :     CPLXMLNode *raster = CPLCreateXMLNode(config, CXT_Element, "Raster");
     653           4 :     XMLSetAttributeVal(raster, "Size", size, "%.0f");
     654           4 :     XMLSetAttributeVal(raster, "PageSize", size, "%.0f");
     655           4 :     CPLCreateXMLElementAndValue(raster, "Compression", CompName(IL_LERC));
     656           4 :     CPLCreateXMLElementAndValue(raster, "DataType", GDALGetDataTypeName(dt));
     657           4 :     CPLCreateXMLElementAndValue(raster, "DataFile", poOpenInfo->pszFilename);
     658             :     // Set a magic index file name to prevent the driver from attempting to open
     659             :     // it
     660           4 :     CPLCreateXMLElementAndValue(raster, "IndexFile", "(null)");
     661             :     // The NDV could be passed as an open option
     662             :     const char *pszNDV =
     663           4 :         CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "NDV", "");
     664           4 :     if (strlen(pszNDV) > 0)
     665             :     {
     666             :         CPLXMLNode *values =
     667           3 :             CPLCreateXMLNode(raster, CXT_Element, "DataValues");
     668           3 :         XMLSetAttributeVal(values, "NoData", pszNDV);
     669             :     }
     670           4 :     return config;
     671             : }
     672             : #endif
     673             : 
     674          73 : LERC_Band::LERC_Band(MRFDataset *pDS, const ILImage &image, int b, int level)
     675          73 :     : MRFRasterBand(pDS, image, b, level)
     676             : {
     677             :     // Lerc doesn't handle 64bit int types
     678          73 :     if (image.dt == GDT_UInt64 || image.dt == GDT_Int64)
     679             :     {
     680           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     681             :                  "Lerc compression of 64 bit integers is not supported");
     682           0 :         return;
     683             :     }
     684             : 
     685             :     // Pick 1/1000 for floats and 0.5 losless for integers.
     686          73 :     if (eDataType == GDT_Float32 || eDataType == GDT_Float64)
     687          17 :         precision = strtod(GetOptionValue("LERC_PREC", ".001"), nullptr);
     688             :     else
     689          56 :         precision =
     690          56 :             std::max(0.5, strtod(GetOptionValue("LERC_PREC", ".5"), nullptr));
     691             : 
     692             :     // Encode in V2 by default.
     693          73 :     version = GetOptlist().FetchBoolean("V1", FALSE) ? 1 : 2;
     694             :     // For LERC 2 there are multiple versions too, -1 means use the library
     695             :     // default Use v2.2 for single band encoding
     696         146 :     l2ver = atoi(GetOptlist().FetchNameValueDef(
     697          73 :         "L2_VER", (img.pagesize.c == 1) ? "2" : "-1"));
     698             : 
     699          73 :     if (image.pageSizeBytes > INT_MAX / 4)
     700             :     {
     701           0 :         CPLError(CE_Failure, CPLE_AppDefined, "LERC page too large");
     702           0 :         return;
     703             :     }
     704             :     // Enlarge the page buffer, LERC may expand data.
     705          73 :     pDS->SetPBufferSize(2 * image.pageSizeBytes);
     706             : }
     707             : 
     708         146 : LERC_Band::~LERC_Band()
     709             : {
     710         146 : }
     711             : 
     712             : NAMESPACE_MRF_END

Generated by: LCOV version 1.14