LCOV - code coverage report
Current view: top level - frmts/mrf - LERC_band.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 309 422 73.2 %
Date: 2025-10-19 15:46:27 Functions: 30 43 69.8 %

          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         160 : static void READ_GINT32(int &X, const char *&p)
      52             : {
      53         160 :     memcpy(&X, p, sizeof(GInt32));
      54         160 :     p += sizeof(GInt32);
      55         160 : }
      56             : 
      57          16 : static void READ_FLOAT(float &X, const char *&p)
      58             : {
      59          16 :     memcpy(&X, p, sizeof(float));
      60          16 :     p += sizeof(float);
      61          16 : }
      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          16 : 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          16 :     if (sz < static_cast<size_t>(
      78          16 :                  Lerc1Image::computeNumBytesNeededToWriteVoidImage()))
      79           0 :         return 0;
      80             :     // First ten bytes are ASCII signature
      81          16 :     if (!STARTS_WITH(s, "CntZImage "))
      82           0 :         return 0;
      83          16 :     s += 10;
      84             : 
      85             :     // Version 11
      86             :     int i;
      87          16 :     READ_GINT32(i, s);
      88          16 :     if (i != 11)
      89           0 :         return 0;
      90             : 
      91             :     // Type 8 is CntZ
      92          16 :     READ_GINT32(i, s);
      93          16 :     if (i != 8)
      94           0 :         return 0;
      95             : 
      96             :     // Height
      97          16 :     READ_GINT32(i, s);  // Arbitrary number in Lerc1Image::read()
      98          16 :     if (i > 20000 || i <= 0)
      99           0 :         return 0;
     100             : 
     101             :     // Width
     102          16 :     READ_GINT32(i, s);
     103          16 :     if (i > 20000 || i <= 0)
     104           0 :         return 0;
     105             : 
     106             :     // Skip the max val stored as double
     107          16 :     s += sizeof(double);
     108             : 
     109             :     // First header should be the mask, which mean 0 blocks
     110             :     // Height
     111          16 :     READ_GINT32(i, s);
     112          16 :     if (i != 0)
     113           0 :         return 0;
     114             : 
     115             :     // WIDTH
     116          16 :     READ_GINT32(i, s);
     117          16 :     if (i != 0)
     118           0 :         return 0;
     119             : 
     120          16 :     READ_GINT32(nBytesMask, s);
     121          16 :     if (nBytesMask < 0)
     122           0 :         return 0;
     123             : 
     124             :     // mask max value, 0 or 1 as float
     125             :     float val;
     126          16 :     READ_FLOAT(val, s);
     127          16 :     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          16 :     if (nBytesMask > INT_MAX - 66 || static_cast<size_t>(66 + nBytesMask) >= sz)
     132             :     {
     133           0 :         return -1;
     134             :     }
     135             : 
     136          16 :     s += nBytesMask;
     137             : 
     138             :     // Data Band header
     139          16 :     READ_GINT32(i,
     140             :                 s);  // number of full height blocks, never single pixel blocks
     141          16 :     if (i <= 0 || i > 10000)
     142           0 :         return 0;
     143             : 
     144          16 :     READ_GINT32(i,
     145             :                 s);  // number of full width blocks, never single pixel blocks
     146          16 :     if (i <= 0 || i > 10000)
     147           0 :         return 0;
     148             : 
     149          16 :     READ_GINT32(nBytesData, s);
     150          16 :     if (nBytesData < 0)
     151           0 :         return 0;
     152             : 
     153             :     // Actual LERC blob size
     154          16 :     if (66 + nBytesMask > INT_MAX - nBytesData)
     155           0 :         return -1;
     156          16 :     int size = static_cast<int>(66 + nBytesMask + nBytesData);
     157          16 :     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          16 : static bool Lerc1ImgUFill(Lerc1Image &zImg, T *dst, const ILImage &img,
     193             :                           GInt32 stride)
     194             : {
     195          14 :     const T ndv =
     196          14 :         static_cast<T>(img.hasNoData && GDALIsValueInRange<T>(img.NoDataValue)
     197          10 :                            ? img.NoDataValue
     198             :                            : 0);
     199          16 :     if (img.pagesize.y != zImg.getHeight() || img.pagesize.x != zImg.getWidth())
     200           0 :         return false;
     201          16 :     int w = img.pagesize.x;
     202          16 :     int h = img.pagesize.y;
     203          16 :     if (1 == stride)
     204             :     {
     205        6672 :         for (int row = 0; row < h; row++)
     206             :         {
     207     3417610 :             for (int col = 0; col < w; col++)
     208             :             {
     209     3410950 :                 if (zImg.IsValid(row, col))
     210             :                 {
     211       27592 :                     GDALCopyWord(zImg(row, col), *dst);
     212             :                 }
     213             :                 else
     214             :                 {
     215     3383350 :                     *dst = ndv;
     216             :                 }
     217     3410950 :                 ++dst;
     218             :             }
     219             :         }
     220          13 :         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_Byte:
     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          14 : static CPLErr DecompressLERC1(buf_mgr &dst, const buf_mgr &src,
     296             :                               const ILImage &img)
     297             : {
     298          28 :     Lerc1Image zImg;
     299             : 
     300             :     // need to add the padding bytes so that out-of-buffer-access
     301          14 :     size_t nRemainingBytes = src.size + PADDING_BYTES;
     302          14 :     Lerc1NS::Byte *ptr = reinterpret_cast<Lerc1NS::Byte *>(src.buffer);
     303          14 :     GInt32 stride = img.pagesize.c;
     304          30 :     for (int c = 0; c < stride; c++)
     305             :     {
     306             :         // Check that input passes snicker test
     307          16 :         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          16 :         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          16 :         bool success = false;
     323             : #define UFILL(T)                                                               \
     324             :     success = Lerc1ImgUFill(zImg, reinterpret_cast<T *>(dst.buffer) + c, img,  \
     325             :                             stride)
     326          16 :         switch (img.dt)
     327             :         {
     328           7 :             case GDT_Byte:
     329           7 :                 UFILL(GByte);
     330           7 :                 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          16 :         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          14 :     return CE_None;
     365             : }
     366             : 
     367             : // Lerc2
     368             : 
     369           1 : static GDALDataType L2toGDT(L2NS::DataType L2type)
     370             : {
     371             :     GDALDataType dt;
     372           1 :     switch (L2type)
     373             :     {
     374           0 :         case L2NS::DataType::dt_short:
     375           0 :             dt = GDT_Int16;
     376           0 :             break;
     377           0 :         case L2NS::DataType::dt_ushort:
     378           0 :             dt = GDT_UInt16;
     379           0 :             break;
     380           0 :         case L2NS::DataType::dt_int:
     381           0 :             dt = GDT_Int32;
     382           0 :             break;
     383           0 :         case L2NS::DataType::dt_uint:
     384           0 :             dt = GDT_UInt32;
     385           0 :             break;
     386           0 :         case L2NS::DataType::dt_float:
     387           0 :             dt = GDT_Float32;
     388           0 :             break;
     389           0 :         case L2NS::DataType::dt_double:
     390           0 :             dt = GDT_Float64;
     391           0 :             break;
     392           0 :         case L2NS::DataType::dt_char:
     393           0 :             dt = GDT_Int8;
     394           0 :             break;
     395           1 :         default:  // Unsigned byte
     396           1 :             dt = GDT_Byte;
     397             :     }
     398           1 :     return dt;
     399             : }
     400             : 
     401        6424 : static L2NS::DataType GDTtoL2(GDALDataType dt)
     402             : {
     403             :     L2NS::DataType L2dt;
     404        6424 :     switch (dt)
     405             :     {
     406           2 :         case GDT_Int16:
     407           2 :             L2dt = L2NS::DataType::dt_short;
     408           2 :             break;
     409           2 :         case GDT_UInt16:
     410           2 :             L2dt = L2NS::DataType::dt_ushort;
     411           2 :             break;
     412           2 :         case GDT_Int32:
     413           2 :             L2dt = L2NS::DataType::dt_int;
     414           2 :             break;
     415           2 :         case GDT_UInt32:
     416           2 :             L2dt = L2NS::DataType::dt_uint;
     417           2 :             break;
     418           2 :         case GDT_Float32:
     419           2 :             L2dt = L2NS::DataType::dt_float;
     420           2 :             break;
     421           4 :         case GDT_Float64:
     422           4 :             L2dt = L2NS::DataType::dt_double;
     423           4 :             break;
     424        6410 :         default:
     425        6410 :             L2dt = L2NS::DataType::dt_uchar;
     426             :     }
     427        6424 :     return L2dt;
     428             : }
     429             : 
     430             : // Populate a LERC2 bitmask based on comparison with the image no data value
     431             : // Returns the number of NoData values found
     432             : template <typename T>
     433           1 : static size_t MaskFill(std::vector<Lerc1NS::Byte> &bm, const T *src,
     434             :                        const ILImage &img)
     435             : {
     436           1 :     size_t w = static_cast<size_t>(img.pagesize.x);
     437           1 :     size_t h = static_cast<size_t>(img.pagesize.y);
     438           1 :     size_t stride = static_cast<size_t>(img.pagesize.c);
     439           1 :     size_t nndv = 0;
     440             : 
     441           1 :     bm.resize(w * h);
     442             : 
     443           1 :     T ndv = static_cast<T>(img.NoDataValue);
     444           1 :     if (!img.hasNoData)
     445           0 :         ndv = 0;  // It really doesn't get called when img doesn't have
     446             :                   // NoDataValue
     447      262145 :     for (size_t i = 0; i < bm.size(); i++)
     448             :     {
     449      262144 :         if (ndv == src[i * stride])
     450             :         {
     451          57 :             bm[i] = 0;
     452          57 :             nndv++;
     453             :         }
     454             :         else
     455             :         {
     456      262087 :             bm[i] = 1;
     457             :         }
     458             :     }
     459             : 
     460           1 :     return nndv;
     461             : }
     462             : 
     463             : // Fill in no data values based on a LERC2 bitmask
     464             : template <typename T>
     465           1 : static void UnMask(std::vector<Lerc1NS::Byte> &bm, T *data, const ILImage &img)
     466             : {
     467           1 :     size_t w = static_cast<size_t>(img.pagesize.x);
     468           1 :     size_t h = static_cast<size_t>(img.pagesize.y);
     469           1 :     size_t stride = static_cast<size_t>(img.pagesize.c);
     470             : 
     471           1 :     if (bm.size() != w * h)
     472           0 :         return;
     473             : 
     474           1 :     T ndv = T(img.NoDataValue);
     475           1 :     if (stride == 1)
     476             :     {
     477      262145 :         for (size_t i = 0; i < w * h; i++)
     478      262144 :             if (!bm[i])
     479           0 :                 data[i] = ndv;
     480             :     }
     481             :     else
     482             :     {
     483           0 :         for (size_t i = 0; i < w * h; i++)
     484           0 :             if (!bm[i])
     485           0 :                 for (size_t c = 0; c < stride; c++)
     486           0 :                     data[i * stride + c] = ndv;
     487             :     }
     488             : }
     489             : 
     490        4812 : static CPLErr CompressLERC2(buf_mgr &dst, buf_mgr &src, const ILImage &img,
     491             :                             double precision, int l2ver)
     492             : {
     493        4812 :     auto w = static_cast<int>(img.pagesize.x);
     494        4812 :     auto h = static_cast<int>(img.pagesize.y);
     495        4812 :     auto stride = static_cast<int>(img.pagesize.c);
     496             : 
     497             :     // build a mask
     498        9624 :     std::vector<Lerc1NS::Byte> bm;
     499        4812 :     size_t nndv = 0;
     500        4812 :     if (img.hasNoData)
     501             :     {  // Only build a bitmask if no data value is defined
     502           1 :         switch (img.dt)
     503             :         {
     504             : 
     505             : #define MASK(T) nndv = MaskFill(bm, reinterpret_cast<T *>(src.buffer), img)
     506             : 
     507           1 :             case GDT_Byte:
     508           1 :                 MASK(GByte);
     509           1 :                 break;
     510           0 :             case GDT_UInt16:
     511           0 :                 MASK(GUInt16);
     512           0 :                 break;
     513           0 :             case GDT_Int16:
     514           0 :                 MASK(GInt16);
     515           0 :                 break;
     516           0 :             case GDT_Int32:
     517           0 :                 MASK(GInt32);
     518           0 :                 break;
     519           0 :             case GDT_UInt32:
     520           0 :                 MASK(GUInt32);
     521           0 :                 break;
     522           0 :             case GDT_Float32:
     523           0 :                 MASK(float);
     524           0 :                 break;
     525           0 :             case GDT_Float64:
     526           0 :                 MASK(double);
     527           0 :                 break;
     528           0 :             default:
     529           0 :                 break;
     530             : 
     531             : #undef MASK
     532             :         }
     533             :     }
     534             : 
     535        4812 :     unsigned int sz = 0;
     536        4812 :     auto pbm = bm.data();
     537        4812 :     if (!bm.empty() && nndv != bm.size())
     538           1 :         pbm = nullptr;
     539       14436 :     auto status = lerc_encodeForVersion(
     540        4812 :         reinterpret_cast<void *>(src.buffer), l2ver,
     541        4812 :         static_cast<unsigned int>(GDTtoL2(img.dt)), stride, w, h, 1,
     542             : #if LERC_AT_LEAST_VERSION(3, 0, 0)
     543             :         pbm ? 1 : 0,
     544             : #endif
     545        4812 :         pbm, precision, reinterpret_cast<Lerc1NS::Byte *>(dst.buffer),
     546        4812 :         static_cast<unsigned int>(dst.size), &sz);
     547             : 
     548        4812 :     if (L2NS::ErrCode::Ok != static_cast<L2NS::ErrCode>(status) ||
     549        4812 :         sz > (dst.size - PADDING_BYTES))
     550             :     {
     551           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     552             :                  "MRF: Error during LERC2 compression");
     553           0 :         return CE_Failure;
     554             :     }
     555             : 
     556        4812 :     dst.size = static_cast<size_t>(sz) + PADDING_BYTES;
     557        4812 :     return CE_None;
     558             : }
     559             : 
     560             : // LERC1 splits of early, so this is mostly LERC2
     561        1626 : CPLErr LERC_Band::Decompress(buf_mgr &dst, buf_mgr &src)
     562             : {
     563        2693 :     if (src.size >= Lerc1Image::computeNumBytesNeededToWriteVoidImage() &&
     564        1067 :         IsLerc1(src.buffer))
     565          14 :         return DecompressLERC1(dst, src, img);
     566             : 
     567             :     // Can only be LERC2 here, verify
     568        1612 :     if (src.size < 50 || !IsLerc2(src.buffer))
     569             :     {
     570           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: Not a lerc tile");
     571           0 :         return CE_Failure;
     572             :     }
     573             : 
     574        1612 :     auto w = static_cast<int>(img.pagesize.x);
     575        1612 :     auto h = static_cast<int>(img.pagesize.y);
     576        1612 :     auto stride = static_cast<int>(img.pagesize.c);
     577             : 
     578        3224 :     std::vector<Lerc1NS::Byte> bm;
     579        1612 :     if (img.hasNoData)
     580           1 :         bm.resize(static_cast<size_t>(w) * static_cast<size_t>(h));
     581        1612 :     auto pbm = bm.data();
     582        1612 :     if (bm.empty())
     583        1611 :         pbm = nullptr;
     584             : 
     585             :     // Decoding may fail for many different reasons, including input not
     586             :     // matching tile expectations
     587             :     auto status =
     588        3224 :         lerc_decode(reinterpret_cast<Lerc1NS::Byte *>(src.buffer),
     589        1612 :                     static_cast<unsigned int>(src.size),
     590             : #if LERC_AT_LEAST_VERSION(3, 0, 0)
     591             :                     pbm ? 1 : 0,
     592             : #endif
     593             :                     pbm, stride, w, h, 1,
     594        1612 :                     static_cast<unsigned int>(GDTtoL2(img.dt)), dst.buffer);
     595        1612 :     if (L2NS::ErrCode::Ok != static_cast<L2NS::ErrCode>(status))
     596             :     {
     597           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error decoding Lerc");
     598           0 :         return CE_Failure;
     599             :     }
     600             : 
     601             :     // No mask means we're done
     602        1612 :     if (bm.empty())
     603        1611 :         return CE_None;
     604             : 
     605             :     // Fill in no data values
     606           1 :     switch (img.dt)
     607             :     {
     608             : #define UNMASK(T) UnMask(bm, reinterpret_cast<T *>(dst.buffer), img)
     609           1 :         case GDT_Byte:
     610           1 :             UNMASK(GByte);
     611           1 :             break;
     612           0 :         case GDT_UInt16:
     613           0 :             UNMASK(GUInt16);
     614           0 :             break;
     615           0 :         case GDT_Int16:
     616           0 :             UNMASK(GInt16);
     617           0 :             break;
     618           0 :         case GDT_Int32:
     619           0 :             UNMASK(GInt32);
     620           0 :             break;
     621           0 :         case GDT_UInt32:
     622           0 :             UNMASK(GUInt32);
     623           0 :             break;
     624           0 :         case GDT_Float32:
     625           0 :             UNMASK(float);
     626           0 :             break;
     627           0 :         case GDT_Float64:
     628           0 :             UNMASK(double);
     629           0 :             break;
     630           0 :         default:
     631           0 :             break;
     632             : #undef DECODE
     633             :     }
     634           1 :     return CE_None;
     635             : }
     636             : 
     637        4822 : CPLErr LERC_Band::Compress(buf_mgr &dst, buf_mgr &src)
     638             : {
     639        4822 :     if (version == 2)
     640        4812 :         return CompressLERC2(dst, src, img, precision, l2ver);
     641             :     else
     642          10 :         return CompressLERC1(dst, src, img, precision);
     643             : }
     644             : 
     645           6 : CPLXMLNode *LERC_Band::GetMRFConfig(GDALOpenInfo *poOpenInfo)
     646             : {
     647             :     // Header of Lerc2 takes 58 bytes, an empty area 62 or more, depending on
     648             :     // the subversion. Size of Lerc1 empty file is 67 Anything under 50 bytes
     649             :     // can't be lerc
     650           6 :     if (poOpenInfo->eAccess != GA_ReadOnly ||
     651           6 :         poOpenInfo->pszFilename == nullptr ||
     652           6 :         poOpenInfo->pabyHeader == nullptr ||
     653           6 :         strlen(poOpenInfo->pszFilename) < 1 || poOpenInfo->nHeaderBytes < 50)
     654           0 :         return nullptr;
     655             : 
     656             :     // Check the header too
     657           6 :     char *psz = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
     658          12 :     CPLString sHeader;
     659           6 :     sHeader.assign(psz, psz + poOpenInfo->nHeaderBytes);
     660           6 :     if (!(IsLerc1(sHeader) || IsLerc2(sHeader)))
     661           0 :         return nullptr;
     662             : 
     663           6 :     GDALDataType dt = GDT_Unknown;  // Use this as a validity flag
     664             : 
     665             :     // Use this structure to fetch width and height
     666           6 :     ILSize size(-1, -1, 1, 1, 1);
     667             : 
     668          11 :     if (IsLerc1(sHeader) &&
     669           5 :         sHeader.size() >= Lerc1Image::computeNumBytesNeededToWriteVoidImage())
     670             :     {
     671           5 :         if (Lerc1Image::getwh(reinterpret_cast<Lerc1NS::Byte *>(psz),
     672           5 :                               poOpenInfo->nHeaderBytes, size.x, size.y))
     673           5 :             dt = GDALGetDataTypeByName(CSLFetchNameValueDef(
     674           5 :                 poOpenInfo->papszOpenOptions, "DATATYPE", "Byte"));
     675             :     }
     676           1 :     else if (IsLerc2(sHeader))
     677             :     {
     678             :         // getBlobInfo will fail without the whole LERC blob
     679             :         // Wasteful, but that's the only choice given by the LERC C API
     680             :         // This will only work if the Lerc2 file is under the constant defined
     681             :         // here
     682             :         static const GIntBig MAX_L2SIZE(10 * 1024 * 1024);  // 10MB
     683           1 :         GByte *buffer = nullptr;
     684             :         vsi_l_offset l2size;
     685             : 
     686             : #define INFOIDX(T) static_cast<size_t>(L2NS::InfoArrOrder::T)
     687             : 
     688           1 :         if (VSIIngestFile(nullptr, poOpenInfo->pszFilename, &buffer, &l2size,
     689           1 :                           MAX_L2SIZE))
     690             :         {
     691             :             //! Info returned in infoArray is { version, dataType, nDim, nCols,
     692             :             //! nRows, nBands, nValidPixels... }, see Lerc_types.h .
     693           2 :             std::vector<unsigned int> info(INFOIDX(nValidPixels) + 1);
     694             :             auto status =
     695           1 :                 lerc_getBlobInfo(reinterpret_cast<Lerc1NS::Byte *>(buffer),
     696             :                                  static_cast<unsigned int>(l2size), info.data(),
     697           1 :                                  nullptr, static_cast<int>(info.size()), 0);
     698           1 :             VSIFree(buffer);
     699           2 :             if (L2NS::ErrCode::Ok == static_cast<L2NS::ErrCode>(status) &&
     700           1 :                 1 == info[INFOIDX(nBands)])
     701             :             {
     702           1 :                 size.x = info[INFOIDX(nCols)];
     703           1 :                 size.y = info[INFOIDX(nRows)];
     704           1 :                 if (info[INFOIDX(version)] > 3)  // Single band before version 4
     705           0 :                     size.c = info[INFOIDX(nDim)];
     706           1 :                 dt = L2toGDT(
     707           1 :                     static_cast<L2NS::DataType>(info[INFOIDX(dataType)]));
     708             :             }
     709             :         }
     710             :     }
     711             : 
     712           6 :     if (size.x <= 0 || size.y <= 0 || dt == GDT_Unknown)
     713           0 :         return nullptr;
     714             : 
     715             :     // Build and return the MRF configuration for a single tile reader
     716           6 :     CPLXMLNode *config = CPLCreateXMLNode(nullptr, CXT_Element, "MRF_META");
     717           6 :     CPLXMLNode *raster = CPLCreateXMLNode(config, CXT_Element, "Raster");
     718           6 :     XMLSetAttributeVal(raster, "Size", size, "%.0f");
     719           6 :     XMLSetAttributeVal(raster, "PageSize", size, "%.0f");
     720           6 :     CPLCreateXMLElementAndValue(raster, "Compression", CompName(IL_LERC));
     721           6 :     CPLCreateXMLElementAndValue(raster, "DataType", GDALGetDataTypeName(dt));
     722           6 :     CPLCreateXMLElementAndValue(raster, "DataFile", poOpenInfo->pszFilename);
     723             :     // Set a magic index file name to prevent the driver from attempting to open
     724             :     // it
     725           6 :     CPLCreateXMLElementAndValue(raster, "IndexFile", "(null)");
     726             :     // The NDV could be passed as an open option
     727             :     const char *pszNDV =
     728           6 :         CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "NDV", "");
     729           6 :     if (strlen(pszNDV) > 0)
     730             :     {
     731             :         CPLXMLNode *values =
     732           4 :             CPLCreateXMLNode(raster, CXT_Element, "DataValues");
     733           4 :         XMLSetAttributeVal(values, "NoData", pszNDV);
     734             :     }
     735           6 :     return config;
     736             : }
     737             : 
     738          75 : LERC_Band::LERC_Band(MRFDataset *pDS, const ILImage &image, int b, int level)
     739          75 :     : MRFRasterBand(pDS, image, b, level)
     740             : {
     741             :     // Lerc doesn't handle 64bit int types
     742          75 :     if (image.dt == GDT_UInt64 || image.dt == GDT_Int64)
     743             :     {
     744           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     745             :                  "Lerc compression of 64 bit integers is not supported");
     746           0 :         return;
     747             :     }
     748             : 
     749             :     // Pick 1/1000 for floats and 0.5 losless for integers.
     750          75 :     if (eDataType == GDT_Float32 || eDataType == GDT_Float64)
     751          17 :         precision = strtod(GetOptionValue("LERC_PREC", ".001"), nullptr);
     752             :     else
     753          58 :         precision =
     754          58 :             std::max(0.5, strtod(GetOptionValue("LERC_PREC", ".5"), nullptr));
     755             : 
     756             :     // Encode in V2 by default.
     757          75 :     version = GetOptlist().FetchBoolean("V1", FALSE) ? 1 : 2;
     758             :     // For LERC 2 there are multiple versions too, -1 means use the library
     759             :     // default Use v2.2 for single band encoding
     760         150 :     l2ver = atoi(GetOptlist().FetchNameValueDef(
     761          75 :         "L2_VER", (img.pagesize.c == 1) ? "2" : "-1"));
     762             : 
     763          75 :     if (image.pageSizeBytes > INT_MAX / 4)
     764             :     {
     765           0 :         CPLError(CE_Failure, CPLE_AppDefined, "LERC page too large");
     766           0 :         return;
     767             :     }
     768             :     // Enlarge the page buffer, LERC may expand data.
     769          75 :     pDS->SetPBufferSize(2 * image.pageSizeBytes);
     770             : }
     771             : 
     772         150 : LERC_Band::~LERC_Band()
     773             : {
     774         150 : }
     775             : 
     776             : NAMESPACE_MRF_END

Generated by: LCOV version 1.14