LCOV - code coverage report
Current view: top level - frmts/mrf - LERC_band.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 302 407 74.2 %
Date: 2024-05-04 12:52:34 Functions: 30 42 71.4 %

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

Generated by: LCOV version 1.14