Coverage Report

Created: 2025-12-03 08:24

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