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

Generated by: LCOV version 1.14