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