Coverage Report

Created: 2026-06-30 08:33

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
114
#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
24.6k
{
53
24.6k
    memcpy(&X, p, sizeof(GInt32));
54
24.6k
    p += sizeof(GInt32);
55
24.6k
}
56
57
static void READ_FLOAT(float &X, const char *&p)
58
2.23k
{
59
2.23k
    memcpy(&X, p, sizeof(float));
60
2.23k
    p += sizeof(float);
61
2.23k
}
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
3.00k
{
73
3.00k
    GInt32 nBytesMask, nBytesData;
74
75
    // Header is 34 bytes
76
    // band header is 16, first mask band then data band
77
3.00k
    if (sz < static_cast<size_t>(
78
3.00k
                 Lerc1Image::computeNumBytesNeededToWriteVoidImage()))
79
0
        return 0;
80
    // First ten bytes are ASCII signature
81
3.00k
    if (!STARTS_WITH(s, "CntZImage "))
82
10
        return 0;
83
2.99k
    s += 10;
84
85
    // Version 11
86
2.99k
    int i;
87
2.99k
    READ_GINT32(i, s);
88
2.99k
    if (i != 11)
89
23
        return 0;
90
91
    // Type 8 is CntZ
92
2.96k
    READ_GINT32(i, s);
93
2.96k
    if (i != 8)
94
13
        return 0;
95
96
    // Height
97
2.95k
    READ_GINT32(i, s);  // Arbitrary number in Lerc1Image::read()
98
2.95k
    if (i > 20000 || i <= 0)
99
16
        return 0;
100
101
    // Width
102
2.94k
    READ_GINT32(i, s);
103
2.94k
    if (i > 20000 || i <= 0)
104
18
        return 0;
105
106
    // Skip the max val stored as double
107
2.92k
    s += sizeof(double);
108
109
    // First header should be the mask, which mean 0 blocks
110
    // Height
111
2.92k
    READ_GINT32(i, s);
112
2.92k
    if (i != 0)
113
389
        return 0;
114
115
    // WIDTH
116
2.53k
    READ_GINT32(i, s);
117
2.53k
    if (i != 0)
118
28
        return 0;
119
120
2.50k
    READ_GINT32(nBytesMask, s);
121
2.50k
    if (nBytesMask < 0)
122
274
        return 0;
123
124
    // mask max value, 0 or 1 as float
125
2.23k
    float val;
126
2.23k
    READ_FLOAT(val, s);
127
2.23k
    if (val != 0.0f && val != 1.0f)
128
548
        return 0;
129
130
    // If data header can't be read the actual size is unknown
131
1.68k
    if (nBytesMask > INT_MAX - 66 || static_cast<size_t>(66 + nBytesMask) >= sz)
132
16
    {
133
16
        return -1;
134
16
    }
135
136
1.66k
    s += nBytesMask;
137
138
    // Data Band header
139
1.66k
    READ_GINT32(i,
140
1.66k
                s);  // number of full height blocks, never single pixel blocks
141
1.66k
    if (i <= 0 || i > 10000)
142
51
        return 0;
143
144
1.61k
    READ_GINT32(i,
145
1.61k
                s);  // number of full width blocks, never single pixel blocks
146
1.61k
    if (i <= 0 || i > 10000)
147
29
        return 0;
148
149
1.58k
    READ_GINT32(nBytesData, s);
150
1.58k
    if (nBytesData < 0)
151
6
        return 0;
152
153
    // Actual LERC blob size
154
1.58k
    if (66 + nBytesMask > INT_MAX - nBytesData)
155
0
        return -1;
156
1.58k
    int size = static_cast<int>(66 + nBytesMask + nBytesData);
157
1.58k
    return (static_cast<size_t>(size) > sz) ? -size : size;
158
1.58k
}
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
26
{
195
26
    const T ndv =
196
26
        static_cast<T>(img.hasNoData && GDALIsValueInRange<T>(img.NoDataValue)
197
26
                           ? img.NoDataValue
198
26
                           : 0);
199
26
    if (img.pagesize.y != zImg.getHeight() || img.pagesize.x != zImg.getWidth())
200
6
        return false;
201
20
    int w = img.pagesize.x;
202
20
    int h = img.pagesize.y;
203
20
    if (1 == stride)
204
10
    {
205
77.3k
        for (int row = 0; row < h; row++)
206
77.2k
        {
207
4.45M
            for (int col = 0; col < w; col++)
208
4.37M
            {
209
4.37M
                if (zImg.IsValid(row, col))
210
2.40k
                {
211
2.40k
                    GDALCopyWord(zImg(row, col), *dst);
212
2.40k
                }
213
4.37M
                else
214
4.37M
                {
215
4.37M
                    *dst = ndv;
216
4.37M
                }
217
4.37M
                ++dst;
218
4.37M
            }
219
77.2k
        }
220
10
        return true;
221
10
    }
222
5.13k
    for (int row = 0; row < h; row++)
223
5.12k
    {
224
2.62M
        for (int col = 0; col < w; col++)
225
2.62M
        {
226
2.62M
            if (zImg.IsValid(row, col))
227
4.00k
            {
228
4.00k
                GDALCopyWord(zImg(row, col), *dst);
229
4.00k
            }
230
2.61M
            else
231
2.61M
            {
232
2.61M
                *dst = ndv;
233
2.61M
            }
234
2.62M
            dst += stride;
235
2.62M
        }
236
5.12k
    }
237
10
    return true;
238
20
}
LERC_band.cpp:bool GDAL_MRF::Lerc1ImgUFill<unsigned char>(Lerc1NS::Lerc1Image&, unsigned char*, GDAL_MRF::ILImage const&, int)
Line
Count
Source
194
26
{
195
26
    const T ndv =
196
26
        static_cast<T>(img.hasNoData && GDALIsValueInRange<T>(img.NoDataValue)
197
26
                           ? img.NoDataValue
198
26
                           : 0);
199
26
    if (img.pagesize.y != zImg.getHeight() || img.pagesize.x != zImg.getWidth())
200
6
        return false;
201
20
    int w = img.pagesize.x;
202
20
    int h = img.pagesize.y;
203
20
    if (1 == stride)
204
10
    {
205
77.3k
        for (int row = 0; row < h; row++)
206
77.2k
        {
207
4.45M
            for (int col = 0; col < w; col++)
208
4.37M
            {
209
4.37M
                if (zImg.IsValid(row, col))
210
2.40k
                {
211
2.40k
                    GDALCopyWord(zImg(row, col), *dst);
212
2.40k
                }
213
4.37M
                else
214
4.37M
                {
215
4.37M
                    *dst = ndv;
216
4.37M
                }
217
4.37M
                ++dst;
218
4.37M
            }
219
77.2k
        }
220
10
        return true;
221
10
    }
222
5.13k
    for (int row = 0; row < h; row++)
223
5.12k
    {
224
2.62M
        for (int col = 0; col < w; col++)
225
2.62M
        {
226
2.62M
            if (zImg.IsValid(row, col))
227
4.00k
            {
228
4.00k
                GDALCopyWord(zImg(row, col), *dst);
229
4.00k
            }
230
2.61M
            else
231
2.61M
            {
232
2.61M
                *dst = ndv;
233
2.61M
            }
234
2.62M
            dst += stride;
235
2.62M
        }
236
5.12k
    }
237
10
    return true;
238
20
}
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
2.99k
{
298
2.99k
    Lerc1Image zImg;
299
300
    // need to add the padding bytes so that out-of-buffer-access
301
2.99k
    size_t nRemainingBytes = src.size + PADDING_BYTES;
302
2.99k
    Lerc1NS::Byte *ptr = reinterpret_cast<Lerc1NS::Byte *>(src.buffer);
303
2.99k
    GInt32 stride = img.pagesize.c;
304
3.01k
    for (int c = 0; c < stride; c++)
305
3.00k
    {
306
        // Check that input passes snicker test
307
3.00k
        if (checkV1(reinterpret_cast<char *>(ptr), nRemainingBytes) <= 0)
308
2.40k
        {
309
2.40k
            CPLError(CE_Failure, CPLE_AppDefined,
310
2.40k
                     "MRF: LERC1 tile format error");
311
2.40k
            return CE_Failure;
312
2.40k
        }
313
314
594
        if (!zImg.read(&ptr, nRemainingBytes, 1e12))
315
568
        {
316
568
            CPLError(CE_Failure, CPLE_AppDefined,
317
568
                     "MRF: Error during LERC decompression");
318
568
            return CE_Failure;
319
568
        }
320
321
        // Unpack from zImg to dst buffer, calling the right type
322
26
        bool success = false;
323
26
#define UFILL(T)                                                               \
324
26
    success = Lerc1ImgUFill(zImg, reinterpret_cast<T *>(dst.buffer) + c, img,  \
325
26
                            stride)
326
26
        switch (img.dt)
327
26
        {
328
26
            case GDT_UInt8:
329
26
                UFILL(GByte);
330
26
                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
26
        }
355
26
#undef UFILL
356
26
        if (!success)
357
6
        {
358
6
            CPLError(CE_Failure, CPLE_AppDefined,
359
6
                     "MRF: Error during LERC decompression");
360
6
            return CE_Failure;
361
6
        }
362
26
    }
363
364
10
    return CE_None;
365
2.99k
}
366
367
// Lerc2
368
369
static L2NS::DataType GDTtoL2(GDALDataType dt)
370
38
{
371
38
    L2NS::DataType L2dt;
372
38
    switch (dt)
373
38
    {
374
0
        case GDT_Int16:
375
0
            L2dt = L2NS::DataType::dt_short;
376
0
            break;
377
0
        case GDT_UInt16:
378
0
            L2dt = L2NS::DataType::dt_ushort;
379
0
            break;
380
0
        case GDT_Int32:
381
0
            L2dt = L2NS::DataType::dt_int;
382
0
            break;
383
0
        case GDT_UInt32:
384
0
            L2dt = L2NS::DataType::dt_uint;
385
0
            break;
386
0
        case GDT_Float32:
387
0
            L2dt = L2NS::DataType::dt_float;
388
0
            break;
389
0
        case GDT_Float64:
390
0
            L2dt = L2NS::DataType::dt_double;
391
0
            break;
392
38
        default:
393
38
            L2dt = L2NS::DataType::dt_uchar;
394
38
    }
395
38
    return L2dt;
396
38
}
397
398
// Populate a LERC2 bitmask based on comparison with the image no data value
399
// Returns the number of NoData values found
400
template <typename T>
401
static size_t MaskFill(std::vector<Lerc1NS::Byte> &bm, const T *src,
402
                       const ILImage &img)
403
0
{
404
0
    size_t w = static_cast<size_t>(img.pagesize.x);
405
0
    size_t h = static_cast<size_t>(img.pagesize.y);
406
0
    size_t stride = static_cast<size_t>(img.pagesize.c);
407
0
    size_t nndv = 0;
408
409
0
    bm.resize(w * h);
410
411
0
    T ndv = static_cast<T>(img.NoDataValue);
412
0
    if (!img.hasNoData)
413
0
        ndv = 0;  // It really doesn't get called when img doesn't have
414
                  // NoDataValue
415
0
    for (size_t i = 0; i < bm.size(); i++)
416
0
    {
417
0
        if (ndv == src[i * stride])
418
0
        {
419
0
            bm[i] = 0;
420
0
            nndv++;
421
0
        }
422
0
        else
423
0
        {
424
0
            bm[i] = 1;
425
0
        }
426
0
    }
427
428
0
    return nndv;
429
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&)
430
431
// Fill in no data values based on a LERC2 bitmask
432
template <typename T>
433
static void UnMask(std::vector<Lerc1NS::Byte> &bm, T *data, const ILImage &img)
434
0
{
435
0
    size_t w = static_cast<size_t>(img.pagesize.x);
436
0
    size_t h = static_cast<size_t>(img.pagesize.y);
437
0
    size_t stride = static_cast<size_t>(img.pagesize.c);
438
439
0
    if (bm.size() != w * h)
440
0
        return;
441
442
0
    T ndv = T(img.NoDataValue);
443
0
    if (stride == 1)
444
0
    {
445
0
        for (size_t i = 0; i < w * h; i++)
446
0
            if (!bm[i])
447
0
                data[i] = ndv;
448
0
    }
449
0
    else
450
0
    {
451
0
        for (size_t i = 0; i < w * h; i++)
452
0
            if (!bm[i])
453
0
                for (size_t c = 0; c < stride; c++)
454
0
                    data[i * stride + c] = ndv;
455
0
    }
456
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&)
457
458
static CPLErr CompressLERC2(buf_mgr &dst, buf_mgr &src, const ILImage &img,
459
                            double precision, int l2ver)
460
0
{
461
0
    auto w = static_cast<int>(img.pagesize.x);
462
0
    auto h = static_cast<int>(img.pagesize.y);
463
0
    auto stride = static_cast<int>(img.pagesize.c);
464
465
    // build a mask
466
0
    std::vector<Lerc1NS::Byte> bm;
467
0
    size_t nndv = 0;
468
0
    if (img.hasNoData)
469
0
    {  // Only build a bitmask if no data value is defined
470
0
        switch (img.dt)
471
0
        {
472
473
0
#define MASK(T) nndv = MaskFill(bm, reinterpret_cast<T *>(src.buffer), img)
474
475
0
            case GDT_UInt8:
476
0
                MASK(GByte);
477
0
                break;
478
0
            case GDT_UInt16:
479
0
                MASK(GUInt16);
480
0
                break;
481
0
            case GDT_Int16:
482
0
                MASK(GInt16);
483
0
                break;
484
0
            case GDT_Int32:
485
0
                MASK(GInt32);
486
0
                break;
487
0
            case GDT_UInt32:
488
0
                MASK(GUInt32);
489
0
                break;
490
0
            case GDT_Float32:
491
0
                MASK(float);
492
0
                break;
493
0
            case GDT_Float64:
494
0
                MASK(double);
495
0
                break;
496
0
            default:
497
0
                break;
498
499
0
#undef MASK
500
0
        }
501
0
    }
502
503
0
    unsigned int sz = 0;
504
0
    auto pbm = bm.data();
505
0
    if (!bm.empty() && nndv != bm.size())
506
0
        pbm = nullptr;
507
0
    auto status = lerc_encodeForVersion(
508
0
        reinterpret_cast<void *>(src.buffer), l2ver,
509
0
        static_cast<unsigned int>(GDTtoL2(img.dt)), stride, w, h, 1,
510
#if LERC_AT_LEAST_VERSION(3, 0, 0)
511
        pbm ? 1 : 0,
512
#endif
513
0
        pbm, precision, reinterpret_cast<Lerc1NS::Byte *>(dst.buffer),
514
0
        static_cast<unsigned int>(dst.size), &sz);
515
516
0
    if (L2NS::ErrCode::Ok != static_cast<L2NS::ErrCode>(status) ||
517
0
        sz > (dst.size - PADDING_BYTES))
518
0
    {
519
0
        CPLError(CE_Failure, CPLE_AppDefined,
520
0
                 "MRF: Error during LERC2 compression");
521
0
        return CE_Failure;
522
0
    }
523
524
0
    dst.size = static_cast<size_t>(sz) + PADDING_BYTES;
525
0
    return CE_None;
526
0
}
527
528
// LERC1 splits of early, so this is mostly LERC2
529
CPLErr LERC_Band::Decompress(buf_mgr &dst, buf_mgr &src)
530
3.06k
{
531
3.06k
    if (src.size >= Lerc1Image::computeNumBytesNeededToWriteVoidImage() &&
532
3.06k
        IsLerc1(src.buffer))
533
2.99k
        return DecompressLERC1(dst, src, img);
534
535
    // Can only be LERC2 here, verify
536
70
    if (src.size < 50 || !IsLerc2(src.buffer))
537
32
    {
538
32
        CPLError(CE_Failure, CPLE_AppDefined, "MRF: Not a lerc tile");
539
32
        return CE_Failure;
540
32
    }
541
542
38
    auto w = static_cast<int>(img.pagesize.x);
543
38
    auto h = static_cast<int>(img.pagesize.y);
544
38
    auto stride = static_cast<int>(img.pagesize.c);
545
546
38
    std::vector<Lerc1NS::Byte> bm;
547
38
    const int nMasks = img.hasNoData ? 1 : 0;
548
38
    if (nMasks > 0)
549
0
        bm.resize(static_cast<size_t>(w) * static_cast<size_t>(h) * nMasks);
550
38
    auto pbm = bm.data();
551
38
    if (bm.empty())
552
38
        pbm = nullptr;
553
554
    // Decoding may fail for many different reasons, including input not
555
    // matching tile expectations
556
38
    auto status =
557
38
        lerc_decode(reinterpret_cast<Lerc1NS::Byte *>(src.buffer),
558
38
                    static_cast<unsigned int>(src.size),
559
#if LERC_AT_LEAST_VERSION(3, 0, 0)
560
                    nMasks,
561
#endif
562
38
                    pbm, stride, w, h, 1,
563
38
                    static_cast<unsigned int>(GDTtoL2(img.dt)), dst.buffer);
564
38
    if (L2NS::ErrCode::Ok != static_cast<L2NS::ErrCode>(status))
565
37
    {
566
37
        CPLError(CE_Failure, CPLE_AppDefined,
567
37
                 "MRF: Error decoding Lerc: status=%d", status);
568
37
        return CE_Failure;
569
37
    }
570
571
    // No mask means we're done
572
1
    if (bm.empty())
573
1
        return CE_None;
574
575
    // Fill in no data values
576
0
    switch (img.dt)
577
0
    {
578
0
#define UNMASK(T) UnMask(bm, reinterpret_cast<T *>(dst.buffer), img)
579
0
        case GDT_UInt8:
580
0
            UNMASK(GByte);
581
0
            break;
582
0
        case GDT_UInt16:
583
0
            UNMASK(GUInt16);
584
0
            break;
585
0
        case GDT_Int16:
586
0
            UNMASK(GInt16);
587
0
            break;
588
0
        case GDT_Int32:
589
0
            UNMASK(GInt32);
590
0
            break;
591
0
        case GDT_UInt32:
592
0
            UNMASK(GUInt32);
593
0
            break;
594
0
        case GDT_Float32:
595
0
            UNMASK(float);
596
0
            break;
597
0
        case GDT_Float64:
598
0
            UNMASK(double);
599
0
            break;
600
0
        default:
601
0
            break;
602
0
#undef DECODE
603
0
    }
604
0
    return CE_None;
605
0
}
606
607
CPLErr LERC_Band::Compress(buf_mgr &dst, buf_mgr &src)
608
0
{
609
0
    if (version == 2)
610
0
        return CompressLERC2(dst, src, img, precision, l2ver);
611
0
    else
612
0
        return CompressLERC1(dst, src, img, precision);
613
0
}
614
615
#if defined(GDAL_USE_LERC_INTERNAL)
616
CPLXMLNode *LERC_Band::GetMRFConfig(GDALOpenInfo *poOpenInfo)
617
422
{
618
    // Size of Lerc1 empty file is 67 Anything under 50 bytes
619
    // can't be lerc
620
422
    if (poOpenInfo->eAccess != GA_ReadOnly ||
621
422
        poOpenInfo->pszFilename == nullptr ||
622
422
        poOpenInfo->pabyHeader == nullptr ||
623
422
        strlen(poOpenInfo->pszFilename) < 1 || poOpenInfo->nHeaderBytes < 50)
624
5
        return nullptr;
625
626
    // Check the header too
627
417
    char *psz = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
628
417
    CPLString sHeader;
629
417
    sHeader.assign(psz, psz + poOpenInfo->nHeaderBytes);
630
417
    if (!IsLerc1(sHeader))
631
88
        return nullptr;
632
633
329
    GDALDataType dt = GDT_Unknown;  // Use this as a validity flag
634
635
    // Use this structure to fetch width and height
636
329
    ILSize size(-1, -1, 1, 1, 1);
637
638
329
    if (IsLerc1(sHeader) &&
639
329
        sHeader.size() >= Lerc1Image::computeNumBytesNeededToWriteVoidImage())
640
328
    {
641
328
        if (Lerc1Image::getwh(reinterpret_cast<Lerc1NS::Byte *>(psz),
642
328
                              poOpenInfo->nHeaderBytes, size.x, size.y))
643
242
            dt = GDALGetDataTypeByName(CSLFetchNameValueDef(
644
242
                poOpenInfo->papszOpenOptions, "DATATYPE", "Byte"));
645
328
    }
646
647
329
    if (size.x <= 0 || size.y <= 0 || dt == GDT_Unknown)
648
87
        return nullptr;
649
650
    // Build and return the MRF configuration for a single tile reader
651
242
    CPLXMLNode *config = CPLCreateXMLNode(nullptr, CXT_Element, "MRF_META");
652
242
    CPLXMLNode *raster = CPLCreateXMLNode(config, CXT_Element, "Raster");
653
242
    XMLSetAttributeVal(raster, "Size", size, "%.0f");
654
242
    XMLSetAttributeVal(raster, "PageSize", size, "%.0f");
655
242
    CPLCreateXMLElementAndValue(raster, "Compression", CompName(IL_LERC));
656
242
    CPLCreateXMLElementAndValue(raster, "DataType", GDALGetDataTypeName(dt));
657
242
    CPLCreateXMLElementAndValue(raster, "DataFile", poOpenInfo->pszFilename);
658
    // Set a magic index file name to prevent the driver from attempting to open
659
    // it
660
242
    CPLCreateXMLElementAndValue(raster, "IndexFile", "(null)");
661
    // The NDV could be passed as an open option
662
242
    const char *pszNDV =
663
242
        CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "NDV", "");
664
242
    if (strlen(pszNDV) > 0)
665
0
    {
666
0
        CPLXMLNode *values =
667
0
            CPLCreateXMLNode(raster, CXT_Element, "DataValues");
668
0
        XMLSetAttributeVal(values, "NoData", pszNDV);
669
0
    }
670
242
    return config;
671
329
}
672
#endif
673
674
LERC_Band::LERC_Band(MRFDataset *pDS, const ILImage &image, int b, int level)
675
632
    : MRFRasterBand(pDS, image, b, level)
676
632
{
677
    // Lerc doesn't handle 64bit int types
678
632
    if (image.dt == GDT_UInt64 || image.dt == GDT_Int64)
679
0
    {
680
0
        CPLError(CE_Failure, CPLE_NotSupported,
681
0
                 "Lerc compression of 64 bit integers is not supported");
682
0
        return;
683
0
    }
684
685
    // Pick 1/1000 for floats and 0.5 losless for integers.
686
632
    if (eDataType == GDT_Float32 || eDataType == GDT_Float64)
687
0
        precision = CPLStrtod(GetOptionValue("LERC_PREC", ".001"), nullptr);
688
632
    else
689
632
        precision = std::max(
690
632
            0.5, CPLStrtod(GetOptionValue("LERC_PREC", ".5"), nullptr));
691
692
    // Encode in V2 by default.
693
632
    version = GetOptlist().FetchBoolean("V1", FALSE) ? 1 : 2;
694
    // For LERC 2 there are multiple versions too, -1 means use the library
695
    // default Use v2.2 for single band encoding
696
632
    l2ver = atoi(GetOptlist().FetchNameValueDef(
697
632
        "L2_VER", (img.pagesize.c == 1) ? "2" : "-1"));
698
699
632
    if (image.pageSizeBytes > INT_MAX / 4)
700
0
    {
701
0
        CPLError(CE_Failure, CPLE_AppDefined, "LERC page too large");
702
0
        return;
703
0
    }
704
    // Enlarge the page buffer, LERC may expand data.
705
632
    pDS->SetPBufferSize(2 * image.pageSizeBytes);
706
632
}
707
708
LERC_Band::~LERC_Band()
709
632
{
710
632
}
711
712
NAMESPACE_MRF_END