LCOV - code coverage report
Current view: top level - frmts/mrf - LERC_band.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 305 418 73.0 %
Date: 2024-11-25 23:50:41 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     3417610 :             for (int col = 0; col < w; col++)
     206     3410950 :                 *dst++ = zImg.IsValid(row, col) ? static_cast<T>(zImg(row, col))
     207             :                                                 : ndv;
     208          13 :         return true;
     209             :     }
     210        1539 :     for (int row = 0; row < h; row++)
     211      787968 :         for (int col = 0; col < w; col++)
     212             :         {
     213      786432 :             *dst =
     214      786432 :                 zImg.IsValid(row, col) ? static_cast<T>(zImg(row, col)) : ndv;
     215      786432 :             dst += stride;
     216             :         }
     217           3 :     return true;
     218             : }
     219             : 
     220          10 : static CPLErr CompressLERC1(buf_mgr &dst, buf_mgr &src, const ILImage &img,
     221             :                             double precision)
     222             : {
     223          20 :     Lerc1Image zImg;
     224          10 :     GInt32 stride = img.pagesize.c;
     225          10 :     Lerc1NS::Byte *ptr = reinterpret_cast<Lerc1NS::Byte *>(dst.buffer);
     226             : 
     227          22 :     for (int c = 0; c < stride; c++)
     228             :     {
     229             : #define FILL(T)                                                                \
     230             :     Lerc1ImgFill(zImg, reinterpret_cast<T *>(src.buffer) + c, img, stride)
     231          12 :         switch (img.dt)
     232             :         {
     233           5 :             case GDT_Byte:
     234           5 :                 FILL(GByte);
     235           5 :                 break;
     236           1 :             case GDT_UInt16:
     237           1 :                 FILL(GUInt16);
     238           1 :                 break;
     239           1 :             case GDT_Int16:
     240           1 :                 FILL(GInt16);
     241           1 :                 break;
     242           1 :             case GDT_Int32:
     243           1 :                 FILL(GInt32);
     244           1 :                 break;
     245           1 :             case GDT_UInt32:
     246           1 :                 FILL(GUInt32);
     247           1 :                 break;
     248           2 :             case GDT_Float32:
     249           2 :                 FILL(float);
     250           2 :                 break;
     251           1 :             case GDT_Float64:
     252           1 :                 FILL(double);
     253           1 :                 break;
     254           0 :             default:
     255           0 :                 break;
     256             :         }
     257             : #undef FILL
     258          12 :         if (!zImg.write(&ptr, precision))
     259             :         {
     260           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     261             :                      "MRF: Error during LERC compression");
     262           0 :             return CE_Failure;
     263             :         }
     264             :     }
     265             : 
     266             :     // write changes the value of the pointer, we can find the size by testing
     267             :     // how far it moved Add a couple of bytes, to avoid buffer overflow on
     268             :     // reading
     269          10 :     dst.size = reinterpret_cast<char *>(ptr) - dst.buffer + PADDING_BYTES;
     270          10 :     CPLDebug("MRF_LERC", "LERC Compressed to %d\n", (int)dst.size);
     271          10 :     return CE_None;
     272             : }
     273             : 
     274             : // LERC 1 Decompression
     275          14 : static CPLErr DecompressLERC1(buf_mgr &dst, const buf_mgr &src,
     276             :                               const ILImage &img)
     277             : {
     278          28 :     Lerc1Image zImg;
     279             : 
     280             :     // need to add the padding bytes so that out-of-buffer-access
     281          14 :     size_t nRemainingBytes = src.size + PADDING_BYTES;
     282          14 :     Lerc1NS::Byte *ptr = reinterpret_cast<Lerc1NS::Byte *>(src.buffer);
     283          14 :     GInt32 stride = img.pagesize.c;
     284          30 :     for (int c = 0; c < stride; c++)
     285             :     {
     286             :         // Check that input passes snicker test
     287          16 :         if (checkV1(reinterpret_cast<char *>(ptr), nRemainingBytes) <= 0)
     288             :         {
     289           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     290             :                      "MRF: LERC1 tile format error");
     291           0 :             return CE_Failure;
     292             :         }
     293             : 
     294          16 :         if (!zImg.read(&ptr, nRemainingBytes, 1e12))
     295             :         {
     296           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     297             :                      "MRF: Error during LERC decompression");
     298           0 :             return CE_Failure;
     299             :         }
     300             : 
     301             :         // Unpack from zImg to dst buffer, calling the right type
     302          16 :         bool success = false;
     303             : #define UFILL(T)                                                               \
     304             :     success = Lerc1ImgUFill(zImg, reinterpret_cast<T *>(dst.buffer) + c, img,  \
     305             :                             stride)
     306          16 :         switch (img.dt)
     307             :         {
     308           7 :             case GDT_Byte:
     309           7 :                 UFILL(GByte);
     310           7 :                 break;
     311           0 :             case GDT_Int8:
     312           0 :                 UFILL(GInt8);
     313           0 :                 break;
     314           1 :             case GDT_UInt16:
     315           1 :                 UFILL(GUInt16);
     316           1 :                 break;
     317           1 :             case GDT_Int16:
     318           1 :                 UFILL(GInt16);
     319           1 :                 break;
     320           1 :             case GDT_Int32:
     321           1 :                 UFILL(GInt32);
     322           1 :                 break;
     323           1 :             case GDT_UInt32:
     324           1 :                 UFILL(GUInt32);
     325           1 :                 break;
     326           4 :             case GDT_Float32:
     327           4 :                 UFILL(float);
     328           4 :                 break;
     329           1 :             case GDT_Float64:
     330           1 :                 UFILL(double);
     331           1 :                 break;
     332           0 :             default:
     333           0 :                 break;
     334             :         }
     335             : #undef UFILL
     336          16 :         if (!success)
     337             :         {
     338           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     339             :                      "MRF: Error during LERC decompression");
     340           0 :             return CE_Failure;
     341             :         }
     342             :     }
     343             : 
     344          14 :     return CE_None;
     345             : }
     346             : 
     347             : // Lerc2
     348             : 
     349           1 : static GDALDataType L2toGDT(L2NS::DataType L2type)
     350             : {
     351             :     GDALDataType dt;
     352           1 :     switch (L2type)
     353             :     {
     354           0 :         case L2NS::DataType::dt_short:
     355           0 :             dt = GDT_Int16;
     356           0 :             break;
     357           0 :         case L2NS::DataType::dt_ushort:
     358           0 :             dt = GDT_UInt16;
     359           0 :             break;
     360           0 :         case L2NS::DataType::dt_int:
     361           0 :             dt = GDT_Int32;
     362           0 :             break;
     363           0 :         case L2NS::DataType::dt_uint:
     364           0 :             dt = GDT_UInt32;
     365           0 :             break;
     366           0 :         case L2NS::DataType::dt_float:
     367           0 :             dt = GDT_Float32;
     368           0 :             break;
     369           0 :         case L2NS::DataType::dt_double:
     370           0 :             dt = GDT_Float64;
     371           0 :             break;
     372           0 :         case L2NS::DataType::dt_char:
     373           0 :             dt = GDT_Int8;
     374           0 :             break;
     375           1 :         default:  // Unsigned byte
     376           1 :             dt = GDT_Byte;
     377             :     }
     378           1 :     return dt;
     379             : }
     380             : 
     381        6424 : static L2NS::DataType GDTtoL2(GDALDataType dt)
     382             : {
     383             :     L2NS::DataType L2dt;
     384        6424 :     switch (dt)
     385             :     {
     386           2 :         case GDT_Int16:
     387           2 :             L2dt = L2NS::DataType::dt_short;
     388           2 :             break;
     389           2 :         case GDT_UInt16:
     390           2 :             L2dt = L2NS::DataType::dt_ushort;
     391           2 :             break;
     392           2 :         case GDT_Int32:
     393           2 :             L2dt = L2NS::DataType::dt_int;
     394           2 :             break;
     395           2 :         case GDT_UInt32:
     396           2 :             L2dt = L2NS::DataType::dt_uint;
     397           2 :             break;
     398           2 :         case GDT_Float32:
     399           2 :             L2dt = L2NS::DataType::dt_float;
     400           2 :             break;
     401           4 :         case GDT_Float64:
     402           4 :             L2dt = L2NS::DataType::dt_double;
     403           4 :             break;
     404        6410 :         default:
     405        6410 :             L2dt = L2NS::DataType::dt_uchar;
     406             :     }
     407        6424 :     return L2dt;
     408             : }
     409             : 
     410             : // Populate a LERC2 bitmask based on comparison with the image no data value
     411             : // Returns the number of NoData values found
     412             : template <typename T>
     413           1 : static size_t MaskFill(std::vector<Lerc1NS::Byte> &bm, const T *src,
     414             :                        const ILImage &img)
     415             : {
     416           1 :     size_t w = static_cast<size_t>(img.pagesize.x);
     417           1 :     size_t h = static_cast<size_t>(img.pagesize.y);
     418           1 :     size_t stride = static_cast<size_t>(img.pagesize.c);
     419           1 :     size_t nndv = 0;
     420             : 
     421           1 :     bm.resize(w * h);
     422             : 
     423           1 :     T ndv = static_cast<T>(img.NoDataValue);
     424           1 :     if (!img.hasNoData)
     425           0 :         ndv = 0;  // It really doesn't get called when img doesn't have
     426             :                   // NoDataValue
     427      262145 :     for (size_t i = 0; i < bm.size(); i++)
     428             :     {
     429      262144 :         if (ndv == src[i * stride])
     430             :         {
     431          57 :             bm[i] = 0;
     432          57 :             nndv++;
     433             :         }
     434             :         else
     435             :         {
     436      262087 :             bm[i] = 1;
     437             :         }
     438             :     }
     439             : 
     440           1 :     return nndv;
     441             : }
     442             : 
     443             : // Fill in no data values based on a LERC2 bitmask
     444             : template <typename T>
     445           1 : static void UnMask(std::vector<Lerc1NS::Byte> &bm, T *data, const ILImage &img)
     446             : {
     447           1 :     size_t w = static_cast<size_t>(img.pagesize.x);
     448           1 :     size_t h = static_cast<size_t>(img.pagesize.y);
     449           1 :     size_t stride = static_cast<size_t>(img.pagesize.c);
     450             : 
     451           1 :     if (bm.size() != w * h)
     452           0 :         return;
     453             : 
     454           1 :     T ndv = T(img.NoDataValue);
     455           1 :     if (stride == 1)
     456             :     {
     457      262145 :         for (size_t i = 0; i < w * h; i++)
     458      262144 :             if (!bm[i])
     459           0 :                 data[i] = ndv;
     460             :     }
     461             :     else
     462             :     {
     463           0 :         for (size_t i = 0; i < w * h; i++)
     464           0 :             if (!bm[i])
     465           0 :                 for (size_t c = 0; c < stride; c++)
     466           0 :                     data[i * stride + c] = ndv;
     467             :     }
     468             : }
     469             : 
     470        4812 : static CPLErr CompressLERC2(buf_mgr &dst, buf_mgr &src, const ILImage &img,
     471             :                             double precision, int l2ver)
     472             : {
     473        4812 :     auto w = static_cast<int>(img.pagesize.x);
     474        4812 :     auto h = static_cast<int>(img.pagesize.y);
     475        4812 :     auto stride = static_cast<int>(img.pagesize.c);
     476             : 
     477             :     // build a mask
     478        9624 :     std::vector<Lerc1NS::Byte> bm;
     479        4812 :     size_t nndv = 0;
     480        4812 :     if (img.hasNoData)
     481             :     {  // Only build a bitmask if no data value is defined
     482           1 :         switch (img.dt)
     483             :         {
     484             : 
     485             : #define MASK(T) nndv = MaskFill(bm, reinterpret_cast<T *>(src.buffer), img)
     486             : 
     487           1 :             case GDT_Byte:
     488           1 :                 MASK(GByte);
     489           1 :                 break;
     490           0 :             case GDT_UInt16:
     491           0 :                 MASK(GUInt16);
     492           0 :                 break;
     493           0 :             case GDT_Int16:
     494           0 :                 MASK(GInt16);
     495           0 :                 break;
     496           0 :             case GDT_Int32:
     497           0 :                 MASK(GInt32);
     498           0 :                 break;
     499           0 :             case GDT_UInt32:
     500           0 :                 MASK(GUInt32);
     501           0 :                 break;
     502           0 :             case GDT_Float32:
     503           0 :                 MASK(float);
     504           0 :                 break;
     505           0 :             case GDT_Float64:
     506           0 :                 MASK(double);
     507           0 :                 break;
     508           0 :             default:
     509           0 :                 break;
     510             : 
     511             : #undef MASK
     512             :         }
     513             :     }
     514             : 
     515        4812 :     unsigned int sz = 0;
     516        4812 :     auto pbm = bm.data();
     517        4812 :     if (!bm.empty() && nndv != bm.size())
     518           1 :         pbm = nullptr;
     519       14436 :     auto status = lerc_encodeForVersion(
     520        4812 :         reinterpret_cast<void *>(src.buffer), l2ver,
     521        4812 :         static_cast<unsigned int>(GDTtoL2(img.dt)), stride, w, h, 1,
     522             : #if LERC_AT_LEAST_VERSION(3, 0, 0)
     523             :         pbm ? 1 : 0,
     524             : #endif
     525        4812 :         pbm, precision, reinterpret_cast<Lerc1NS::Byte *>(dst.buffer),
     526        4812 :         static_cast<unsigned int>(dst.size), &sz);
     527             : 
     528        4812 :     if (L2NS::ErrCode::Ok != static_cast<L2NS::ErrCode>(status) ||
     529        4812 :         sz > (dst.size - PADDING_BYTES))
     530             :     {
     531           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     532             :                  "MRF: Error during LERC2 compression");
     533           0 :         return CE_Failure;
     534             :     }
     535             : 
     536        4812 :     dst.size = static_cast<size_t>(sz) + PADDING_BYTES;
     537        4812 :     return CE_None;
     538             : }
     539             : 
     540             : // LERC1 splits of early, so this is mostly LERC2
     541        1626 : CPLErr LERC_Band::Decompress(buf_mgr &dst, buf_mgr &src)
     542             : {
     543        2693 :     if (src.size >= Lerc1Image::computeNumBytesNeededToWriteVoidImage() &&
     544        1067 :         IsLerc1(src.buffer))
     545          14 :         return DecompressLERC1(dst, src, img);
     546             : 
     547             :     // Can only be LERC2 here, verify
     548        1612 :     if (src.size < 50 || !IsLerc2(src.buffer))
     549             :     {
     550           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: Not a lerc tile");
     551           0 :         return CE_Failure;
     552             :     }
     553             : 
     554        1612 :     auto w = static_cast<int>(img.pagesize.x);
     555        1612 :     auto h = static_cast<int>(img.pagesize.y);
     556        1612 :     auto stride = static_cast<int>(img.pagesize.c);
     557             : 
     558        3224 :     std::vector<Lerc1NS::Byte> bm;
     559        1612 :     if (img.hasNoData)
     560           1 :         bm.resize(static_cast<size_t>(w) * static_cast<size_t>(h));
     561        1612 :     auto pbm = bm.data();
     562        1612 :     if (bm.empty())
     563        1611 :         pbm = nullptr;
     564             : 
     565             :     // Decoding may fail for many different reasons, including input not
     566             :     // matching tile expectations
     567             :     auto status =
     568        3224 :         lerc_decode(reinterpret_cast<Lerc1NS::Byte *>(src.buffer),
     569        1612 :                     static_cast<unsigned int>(src.size),
     570             : #if LERC_AT_LEAST_VERSION(3, 0, 0)
     571             :                     pbm ? 1 : 0,
     572             : #endif
     573             :                     pbm, stride, w, h, 1,
     574        1612 :                     static_cast<unsigned int>(GDTtoL2(img.dt)), dst.buffer);
     575        1612 :     if (L2NS::ErrCode::Ok != static_cast<L2NS::ErrCode>(status))
     576             :     {
     577           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error decoding Lerc");
     578           0 :         return CE_Failure;
     579             :     }
     580             : 
     581             :     // No mask means we're done
     582        1612 :     if (bm.empty())
     583        1611 :         return CE_None;
     584             : 
     585             :     // Fill in no data values
     586           1 :     switch (img.dt)
     587             :     {
     588             : #define UNMASK(T) UnMask(bm, reinterpret_cast<T *>(dst.buffer), img)
     589           1 :         case GDT_Byte:
     590           1 :             UNMASK(GByte);
     591           1 :             break;
     592           0 :         case GDT_UInt16:
     593           0 :             UNMASK(GUInt16);
     594           0 :             break;
     595           0 :         case GDT_Int16:
     596           0 :             UNMASK(GInt16);
     597           0 :             break;
     598           0 :         case GDT_Int32:
     599           0 :             UNMASK(GInt32);
     600           0 :             break;
     601           0 :         case GDT_UInt32:
     602           0 :             UNMASK(GUInt32);
     603           0 :             break;
     604           0 :         case GDT_Float32:
     605           0 :             UNMASK(float);
     606           0 :             break;
     607           0 :         case GDT_Float64:
     608           0 :             UNMASK(double);
     609           0 :             break;
     610           0 :         default:
     611           0 :             break;
     612             : #undef DECODE
     613             :     }
     614           1 :     return CE_None;
     615             : }
     616             : 
     617        4822 : CPLErr LERC_Band::Compress(buf_mgr &dst, buf_mgr &src)
     618             : {
     619        4822 :     if (version == 2)
     620        4812 :         return CompressLERC2(dst, src, img, precision, l2ver);
     621             :     else
     622          10 :         return CompressLERC1(dst, src, img, precision);
     623             : }
     624             : 
     625           6 : CPLXMLNode *LERC_Band::GetMRFConfig(GDALOpenInfo *poOpenInfo)
     626             : {
     627             :     // Header of Lerc2 takes 58 bytes, an empty area 62 or more, depending on
     628             :     // the subversion. Size of Lerc1 empty file is 67 Anything under 50 bytes
     629             :     // can't be lerc
     630           6 :     if (poOpenInfo->eAccess != GA_ReadOnly ||
     631           6 :         poOpenInfo->pszFilename == nullptr ||
     632           6 :         poOpenInfo->pabyHeader == nullptr ||
     633           6 :         strlen(poOpenInfo->pszFilename) < 1 || poOpenInfo->nHeaderBytes < 50)
     634           0 :         return nullptr;
     635             : 
     636             :     // Check the header too
     637           6 :     char *psz = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
     638          12 :     CPLString sHeader;
     639           6 :     sHeader.assign(psz, psz + poOpenInfo->nHeaderBytes);
     640           6 :     if (!(IsLerc1(sHeader) || IsLerc2(sHeader)))
     641           0 :         return nullptr;
     642             : 
     643           6 :     GDALDataType dt = GDT_Unknown;  // Use this as a validity flag
     644             : 
     645             :     // Use this structure to fetch width and height
     646           6 :     ILSize size(-1, -1, 1, 1, 1);
     647             : 
     648          11 :     if (IsLerc1(sHeader) &&
     649           5 :         sHeader.size() >= Lerc1Image::computeNumBytesNeededToWriteVoidImage())
     650             :     {
     651           5 :         if (Lerc1Image::getwh(reinterpret_cast<Lerc1NS::Byte *>(psz),
     652           5 :                               poOpenInfo->nHeaderBytes, size.x, size.y))
     653           5 :             dt = GDALGetDataTypeByName(CSLFetchNameValueDef(
     654           5 :                 poOpenInfo->papszOpenOptions, "DATATYPE", "Byte"));
     655             :     }
     656           1 :     else if (IsLerc2(sHeader))
     657             :     {
     658             :         // getBlobInfo will fail without the whole LERC blob
     659             :         // Wasteful, but that's the only choice given by the LERC C API
     660             :         // This will only work if the Lerc2 file is under the constant defined
     661             :         // here
     662             :         static const GIntBig MAX_L2SIZE(10 * 1024 * 1024);  // 10MB
     663           1 :         GByte *buffer = nullptr;
     664             :         vsi_l_offset l2size;
     665             : 
     666             : #define INFOIDX(T) static_cast<size_t>(L2NS::InfoArrOrder::T)
     667             : 
     668           1 :         if (VSIIngestFile(nullptr, poOpenInfo->pszFilename, &buffer, &l2size,
     669           1 :                           MAX_L2SIZE))
     670             :         {
     671             :             //! Info returned in infoArray is { version, dataType, nDim, nCols,
     672             :             //! nRows, nBands, nValidPixels... }, see Lerc_types.h .
     673           2 :             std::vector<unsigned int> info(INFOIDX(nValidPixels) + 1);
     674             :             auto status =
     675           1 :                 lerc_getBlobInfo(reinterpret_cast<Lerc1NS::Byte *>(buffer),
     676             :                                  static_cast<unsigned int>(l2size), info.data(),
     677           1 :                                  nullptr, static_cast<int>(info.size()), 0);
     678           1 :             VSIFree(buffer);
     679           2 :             if (L2NS::ErrCode::Ok == static_cast<L2NS::ErrCode>(status) &&
     680           1 :                 1 == info[INFOIDX(nBands)])
     681             :             {
     682           1 :                 size.x = info[INFOIDX(nCols)];
     683           1 :                 size.y = info[INFOIDX(nRows)];
     684           1 :                 if (info[INFOIDX(version)] > 3)  // Single band before version 4
     685           0 :                     size.c = info[INFOIDX(nDim)];
     686           1 :                 dt = L2toGDT(
     687           1 :                     static_cast<L2NS::DataType>(info[INFOIDX(dataType)]));
     688             :             }
     689             :         }
     690             :     }
     691             : 
     692           6 :     if (size.x <= 0 || size.y <= 0 || dt == GDT_Unknown)
     693           0 :         return nullptr;
     694             : 
     695             :     // Build and return the MRF configuration for a single tile reader
     696           6 :     CPLXMLNode *config = CPLCreateXMLNode(nullptr, CXT_Element, "MRF_META");
     697           6 :     CPLXMLNode *raster = CPLCreateXMLNode(config, CXT_Element, "Raster");
     698           6 :     XMLSetAttributeVal(raster, "Size", size, "%.0f");
     699           6 :     XMLSetAttributeVal(raster, "PageSize", size, "%.0f");
     700           6 :     CPLCreateXMLElementAndValue(raster, "Compression", CompName(IL_LERC));
     701           6 :     CPLCreateXMLElementAndValue(raster, "DataType", GDALGetDataTypeName(dt));
     702           6 :     CPLCreateXMLElementAndValue(raster, "DataFile", poOpenInfo->pszFilename);
     703             :     // Set a magic index file name to prevent the driver from attempting to open
     704             :     // it
     705           6 :     CPLCreateXMLElementAndValue(raster, "IndexFile", "(null)");
     706             :     // The NDV could be passed as an open option
     707             :     const char *pszNDV =
     708           6 :         CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "NDV", "");
     709           6 :     if (strlen(pszNDV) > 0)
     710             :     {
     711             :         CPLXMLNode *values =
     712           4 :             CPLCreateXMLNode(raster, CXT_Element, "DataValues");
     713           4 :         XMLSetAttributeVal(values, "NoData", pszNDV);
     714             :     }
     715           6 :     return config;
     716             : }
     717             : 
     718          75 : LERC_Band::LERC_Band(MRFDataset *pDS, const ILImage &image, int b, int level)
     719          75 :     : MRFRasterBand(pDS, image, b, level)
     720             : {
     721             :     // Lerc doesn't handle 64bit int types
     722          75 :     if (image.dt == GDT_UInt64 || image.dt == GDT_Int64)
     723             :     {
     724           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     725             :                  "Lerc compression of 64 bit integers is not supported");
     726           0 :         return;
     727             :     }
     728             : 
     729             :     // Pick 1/1000 for floats and 0.5 losless for integers.
     730          75 :     if (eDataType == GDT_Float32 || eDataType == GDT_Float64)
     731          17 :         precision = strtod(GetOptionValue("LERC_PREC", ".001"), nullptr);
     732             :     else
     733          58 :         precision =
     734          58 :             std::max(0.5, strtod(GetOptionValue("LERC_PREC", ".5"), nullptr));
     735             : 
     736             :     // Encode in V2 by default.
     737          75 :     version = GetOptlist().FetchBoolean("V1", FALSE) ? 1 : 2;
     738             :     // For LERC 2 there are multiple versions too, -1 means use the library
     739             :     // default Use v2.2 for single band encoding
     740         150 :     l2ver = atoi(GetOptlist().FetchNameValueDef(
     741          75 :         "L2_VER", (img.pagesize.c == 1) ? "2" : "-1"));
     742             : 
     743          75 :     if (image.pageSizeBytes > INT_MAX / 4)
     744             :     {
     745           0 :         CPLError(CE_Failure, CPLE_AppDefined, "LERC page too large");
     746           0 :         return;
     747             :     }
     748             :     // Enlarge the page buffer, LERC may expand data.
     749          75 :     pDS->SetPBufferSize(2 * image.pageSizeBytes);
     750             : }
     751             : 
     752         150 : LERC_Band::~LERC_Band()
     753             : {
     754         150 : }
     755             : 
     756             : NAMESPACE_MRF_END

Generated by: LCOV version 1.14