Coverage Report

Created: 2026-07-25 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/third_party/LercLib/Lerc2.cpp
Line
Count
Source
1
/*
2
Copyright 2015 Esri
3
4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7
8
http://www.apache.org/licenses/LICENSE-2.0
9
10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
16
A local copy of the license and additional notices are located with the
17
source distribution at:
18
19
http://github.com/Esri/lerc/
20
21
Contributors:   Thomas Maurer
22
                Lucian Plesea (provided checksum code)
23
*/
24
25
#include "Defines.h"
26
#include "Lerc2.h"
27
28
#include <climits>
29
#include <cstdint>
30
31
USING_NAMESPACE_LERC
32
using namespace std;
33
34
0
static void ignore_ret_val(bool) {}
35
36
// -------------------------------------------------------------------------- ;
37
38
Lerc2::Lerc2()
39
0
{
40
0
  Init();
41
0
}
42
43
// -------------------------------------------------------------------------- ;
44
45
Lerc2::Lerc2(int nDim, int nCols, int nRows, const Byte* pMaskBits)
46
0
{
47
0
  Init();
48
0
  ignore_ret_val(Set(nDim, nCols, nRows, pMaskBits));
49
0
}
50
51
// -------------------------------------------------------------------------- ;
52
53
bool Lerc2::SetEncoderToOldVersion(int version)
54
0
{
55
0
  if (version < 2 || version > kCurrVersion)
56
0
    return false;
57
58
0
  if (version < 4 && m_headerInfo.nDim > 1)
59
0
    return false;
60
61
0
  m_headerInfo.version = version;
62
63
0
  return true;
64
0
}
65
66
// -------------------------------------------------------------------------- ;
67
68
void Lerc2::Init()
69
0
{
70
0
  m_microBlockSize    = 8;
71
0
  m_maxValToQuantize  = 0;
72
0
  m_encodeMask        = true;
73
0
  m_writeDataOneSweep = false;
74
0
  m_imageEncodeMode   = IEM_Tiling;
75
76
0
  m_headerInfo.RawInit();
77
0
  m_headerInfo.version = kCurrVersion;
78
0
  m_headerInfo.microBlockSize = m_microBlockSize;
79
0
}
80
81
// -------------------------------------------------------------------------- ;
82
83
bool Lerc2::Set(int nDim, int nCols, int nRows, const Byte* pMaskBits)
84
0
{
85
0
  if (nDim > 1 && m_headerInfo.version < 4)
86
0
    return false;
87
88
0
  if (!m_bitMask.SetSize(nCols, nRows))
89
0
    return false;
90
91
0
  if (pMaskBits)
92
0
  {
93
0
    memcpy(m_bitMask.Bits(), pMaskBits, m_bitMask.Size());
94
0
    m_headerInfo.numValidPixel = m_bitMask.CountValidBits();
95
0
  }
96
0
  else
97
0
  {
98
0
    m_headerInfo.numValidPixel = nCols * nRows;
99
0
    m_bitMask.SetAllValid();
100
0
  }
101
102
0
  m_headerInfo.nDim  = nDim;
103
0
  m_headerInfo.nCols = nCols;
104
0
  m_headerInfo.nRows = nRows;
105
106
0
  return true;
107
0
}
108
109
// -------------------------------------------------------------------------- ;
110
111
//// if the Lerc2 header should ever shrink in size to less than below, then update it (very unlikely)
112
//
113
//unsigned int Lerc2::MinNumBytesNeededToReadHeader()
114
//{
115
//  unsigned int numBytes = (unsigned int)FileKey().length();
116
//  numBytes += 7 * sizeof(int);
117
//  numBytes += 3 * sizeof(double);
118
//  return numBytes;
119
//}
120
121
// -------------------------------------------------------------------------- ;
122
123
bool Lerc2::GetHeaderInfo(const Byte* pByte, size_t nBytesRemaining, struct HeaderInfo& hd)
124
0
{
125
0
  if (!pByte || !IsLittleEndianSystem())
126
0
    return false;
127
128
0
  return ReadHeader(&pByte, nBytesRemaining, hd);
129
0
}
130
131
// -------------------------------------------------------------------------- ;
132
// -------------------------------------------------------------------------- ;
133
134
unsigned int Lerc2::ComputeNumBytesHeaderToWrite(const struct HeaderInfo& hd)
135
0
{
136
0
  unsigned int numBytes = (unsigned int)FileKey().length();
137
0
  numBytes += 1 * sizeof(int);
138
0
  numBytes += (hd.version >= 3 ? 1 : 0) * sizeof(unsigned int);
139
0
  numBytes += (hd.version >= 4 ? 7 : 6) * sizeof(int);
140
0
  numBytes += 3 * sizeof(double);
141
0
  return numBytes;
142
0
}
143
144
// -------------------------------------------------------------------------- ;
145
146
bool Lerc2::WriteHeader(Byte** ppByte, const struct HeaderInfo& hd)
147
0
{
148
0
  if (!ppByte)
149
0
    return false;
150
151
0
  Byte* ptr = *ppByte;
152
153
0
  string fileKey = FileKey();
154
0
  size_t len = fileKey.length();
155
0
  memcpy(ptr, fileKey.c_str(), len);
156
0
  ptr += len;
157
158
0
  memcpy(ptr, &hd.version, sizeof(int));
159
0
  ptr += sizeof(int);
160
161
0
  if (hd.version >= 3)
162
0
  {
163
0
    unsigned int checksum = 0;
164
0
    memcpy(ptr, &checksum, sizeof(unsigned int));    // place holder to be filled by the real check sum later
165
0
    ptr += sizeof(unsigned int);
166
0
  }
167
168
0
  vector<int> intVec;
169
0
  intVec.push_back(hd.nRows);
170
0
  intVec.push_back(hd.nCols);
171
172
0
  if (hd.version >= 4)
173
0
  {
174
0
    intVec.push_back(hd.nDim);
175
0
  }
176
177
0
  intVec.push_back(hd.numValidPixel);
178
0
  intVec.push_back(hd.microBlockSize);
179
0
  intVec.push_back(hd.blobSize);
180
0
  intVec.push_back((int)hd.dt);
181
182
0
  len = intVec.size() * sizeof(int);
183
0
  memcpy(ptr, &intVec[0], len);
184
0
  ptr += len;
185
186
0
  vector<double> dblVec;
187
0
  dblVec.push_back(hd.maxZError);
188
0
  dblVec.push_back(hd.zMin);
189
0
  dblVec.push_back(hd.zMax);
190
191
0
  len = dblVec.size() * sizeof(double);
192
0
  memcpy(ptr, &dblVec[0], len);
193
0
  ptr += len;
194
195
0
  *ppByte = ptr;
196
0
  return true;
197
0
}
198
199
// -------------------------------------------------------------------------- ;
200
201
bool Lerc2::ReadHeader(const Byte** ppByte, size_t& nBytesRemainingInOut, struct HeaderInfo& hd)
202
0
{
203
0
  if (!ppByte || !*ppByte)
204
0
    return false;
205
206
0
  const Byte* ptr = *ppByte;
207
0
  size_t nBytesRemaining = nBytesRemainingInOut;
208
209
0
  string fileKey = FileKey();
210
0
  size_t keyLen = fileKey.length();
211
212
0
  hd.RawInit();
213
214
0
  if (nBytesRemaining < keyLen || memcmp(ptr, fileKey.c_str(), keyLen))
215
0
    return false;
216
217
0
  ptr += keyLen;
218
0
  nBytesRemaining -= keyLen;
219
220
0
  if (nBytesRemaining < sizeof(int) || !memcpy(&(hd.version), ptr, sizeof(int)))
221
0
    return false;
222
223
0
  ptr += sizeof(int);
224
0
  nBytesRemaining -= sizeof(int);
225
226
0
  if (hd.version > kCurrVersion)    // this reader is outdated
227
0
    return false;
228
229
0
  if (hd.version >= 3)
230
0
  {
231
0
    if (nBytesRemaining < sizeof(unsigned int) || !memcpy(&(hd.checksum), ptr, sizeof(unsigned int)))
232
0
      return false;
233
234
0
    ptr += sizeof(unsigned int);
235
0
    nBytesRemaining -= sizeof(unsigned int);
236
0
  }
237
238
0
  int nInts = (hd.version >= 4) ? 7 : 6;
239
0
  vector<int> intVec(nInts, 0);
240
0
  vector<double> dblVec(3, 0);
241
242
0
  size_t len = sizeof(int) * intVec.size();
243
244
0
  if (nBytesRemaining < len || !memcpy(&intVec[0], ptr, len))
245
0
    return false;
246
247
0
  ptr += len;
248
0
  nBytesRemaining -= len;
249
250
0
  len = sizeof(double) * dblVec.size();
251
252
0
  if (nBytesRemaining < len || !memcpy(&dblVec[0], ptr, len))
253
0
    return false;
254
255
0
  ptr += len;
256
0
  nBytesRemaining -= len;
257
258
0
  int i = 0;
259
0
  hd.nRows          = intVec[i++];
260
0
  hd.nCols          = intVec[i++];
261
0
  hd.nDim           = (hd.version >= 4) ? intVec[i++] : 1;
262
0
  hd.numValidPixel  = intVec[i++];
263
0
  hd.microBlockSize = intVec[i++];
264
0
  hd.blobSize       = intVec[i++];
265
0
  const int dt      = intVec[i++];
266
0
  if (hd.nRows <= 0 || hd.nCols <= 0 || hd.nDim <= 0 || hd.numValidPixel < 0
267
0
    || hd.microBlockSize <= 0 || hd.blobSize <= 0 || dt < DT_Char || dt > DT_Double)
268
0
    return false;
269
0
  hd.dt             = static_cast<DataType>(dt);
270
271
0
  hd.maxZError      = dblVec[0];
272
0
  hd.zMin           = dblVec[1];
273
0
  hd.zMax           = dblVec[2];
274
275
0
  const uint64_t numPixel = (uint64_t)hd.nRows * hd.nCols;
276
0
  if (numPixel > (uint64_t)INT_MAX || (uint64_t)hd.numValidPixel > numPixel)
277
0
    return false;
278
279
0
  *ppByte = ptr;
280
0
  nBytesRemainingInOut = nBytesRemaining;
281
282
0
  return true;
283
0
}
284
285
// -------------------------------------------------------------------------- ;
286
287
bool Lerc2::WriteMask(Byte** ppByte) const
288
0
{
289
0
  if (!ppByte)
290
0
    return false;
291
292
0
  int numValid = m_headerInfo.numValidPixel;
293
0
  int numTotal = m_headerInfo.nCols * m_headerInfo.nRows;
294
295
0
  bool needMask = numValid > 0 && numValid < numTotal;
296
297
0
  Byte* ptr = *ppByte;
298
299
0
  if (needMask && m_encodeMask)
300
0
  {
301
0
    Byte* pArrRLE;
302
0
    size_t numBytesRLE;
303
0
    RLE rle;
304
0
    if (!rle.compress((const Byte*)m_bitMask.Bits(), m_bitMask.Size(), &pArrRLE, numBytesRLE, false))
305
0
      return false;
306
307
0
    int numBytesMask = (int)numBytesRLE;
308
0
    memcpy(ptr, &numBytesMask, sizeof(int));    // num bytes for compressed mask
309
0
    ptr += sizeof(int);
310
0
    memcpy(ptr, pArrRLE, numBytesRLE);
311
0
    ptr += numBytesRLE;
312
313
0
    delete[] pArrRLE;
314
0
  }
315
0
  else
316
0
  {
317
0
    memset(ptr, 0, sizeof(int));    // indicates no mask stored
318
0
    ptr += sizeof(int);
319
0
  }
320
321
0
  *ppByte = ptr;
322
0
  return true;
323
0
}
324
325
// -------------------------------------------------------------------------- ;
326
327
bool Lerc2::ReadMask(const Byte** ppByte, size_t& nBytesRemainingInOut)
328
0
{
329
0
  if (!ppByte)
330
0
    return false;
331
332
0
  int numValid = m_headerInfo.numValidPixel;
333
0
  int w = m_headerInfo.nCols;
334
0
  int h = m_headerInfo.nRows;
335
336
0
  const Byte* ptr = *ppByte;
337
0
  size_t nBytesRemaining = nBytesRemainingInOut;
338
339
0
  int numBytesMask;
340
0
  if (nBytesRemaining < sizeof(int) || !memcpy(&numBytesMask, ptr, sizeof(int)))
341
0
    return false;
342
343
0
  ptr += sizeof(int);
344
0
  nBytesRemaining -= sizeof(int);
345
346
0
  if (numValid == 0 || numValid == w * h)
347
0
  {
348
0
    if (numBytesMask != 0)
349
0
      return false;
350
0
  }
351
352
0
  if (!m_bitMask.SetSize(w, h))
353
0
    return false;
354
355
0
  if (numValid == 0)
356
0
    m_bitMask.SetAllInvalid();
357
0
  else if (numValid == w * h)
358
0
    m_bitMask.SetAllValid();
359
0
  else if (numBytesMask > 0)    // read it in
360
0
  {
361
0
    if (nBytesRemaining < static_cast<size_t>(numBytesMask))
362
0
      return false;
363
364
0
    RLE rle;
365
0
    if (!rle.decompress(ptr, nBytesRemaining, m_bitMask.Bits(), m_bitMask.Size()))
366
0
      return false;
367
368
0
    ptr += numBytesMask;
369
0
    nBytesRemaining -= numBytesMask;
370
0
  }
371
  // else use previous mask
372
373
0
  *ppByte = ptr;
374
0
  nBytesRemainingInOut = nBytesRemaining;
375
376
0
  return true;
377
0
}
378
379
// -------------------------------------------------------------------------- ;
380
381
bool Lerc2::DoChecksOnEncode(Byte* pBlobBegin, Byte* pBlobEnd) const
382
0
{
383
0
  if ((size_t)(pBlobEnd - pBlobBegin) != (size_t)m_headerInfo.blobSize)
384
0
    return false;
385
386
0
  if (m_headerInfo.version >= 3)
387
0
  {
388
0
    int blobSize = (int)(pBlobEnd - pBlobBegin);
389
0
    int nBytes = (int)(FileKey().length() + sizeof(int) + sizeof(unsigned int));    // start right after the checksum entry
390
0
    if (blobSize < nBytes)
391
0
      return false;
392
0
    unsigned int checksum = ComputeChecksumFletcher32(pBlobBegin + nBytes, blobSize - nBytes);
393
394
0
    nBytes -= sizeof(unsigned int);
395
0
    memcpy(pBlobBegin + nBytes, &checksum, sizeof(unsigned int));
396
0
  }
397
398
0
  return true;
399
0
}
400
401
// -------------------------------------------------------------------------- ;
402
403
// from  https://en.wikipedia.org/wiki/Fletcher's_checksum
404
// modified from ushorts to bytes (by Lucian Plesea)
405
406
unsigned int Lerc2::ComputeChecksumFletcher32(const Byte* pByte, int len)
407
0
{
408
0
  unsigned int sum1 = 0xffff, sum2 = 0xffff;
409
0
  unsigned int words = len / 2;
410
411
0
  while (words)
412
0
  {
413
0
    unsigned int tlen = (words >= 359) ? 359 : words;
414
0
    words -= tlen;
415
0
    do {
416
0
      sum1 += (*pByte++ << 8);
417
0
      sum2 += sum1 += *pByte++;
418
0
    } while (--tlen);
419
420
0
    sum1 = (sum1 & 0xffff) + (sum1 >> 16);
421
0
    sum2 = (sum2 & 0xffff) + (sum2 >> 16);
422
0
  }
423
424
  // add the straggler byte if it exists
425
0
  if (len & 1)
426
0
    sum2 += sum1 += (*pByte << 8);
427
428
  // second reduction step to reduce sums to 16 bits
429
0
  sum1 = (sum1 & 0xffff) + (sum1 >> 16);
430
0
  sum2 = (sum2 & 0xffff) + (sum2 >> 16);
431
432
0
  return sum2 << 16 | sum1;
433
0
}
434
435
// -------------------------------------------------------------------------- ;
436
437
//struct MyLessThanOp
438
//{
439
//  inline bool operator() (const pair<unsigned int, unsigned int>& p0,
440
//                          const pair<unsigned int, unsigned int>& p1)  { return p0.first < p1.first; }
441
//};
442
443
// -------------------------------------------------------------------------- ;
444
445
void Lerc2::SortQuantArray(const vector<unsigned int>& quantVec, vector<pair<unsigned int, unsigned int> >& sortedQuantVec)
446
0
{
447
0
  int numElem = (int)quantVec.size();
448
0
  sortedQuantVec.resize(numElem);
449
450
0
  for (int i = 0; i < numElem; i++)
451
0
    sortedQuantVec[i] = pair<unsigned int, unsigned int>(quantVec[i], i);
452
453
  //std::sort(sortedQuantVec.begin(), sortedQuantVec.end(), MyLessThanOp());
454
455
0
  std::sort(sortedQuantVec.begin(), sortedQuantVec.end(),
456
0
    [](const pair<unsigned int, unsigned int>& p0,
457
0
       const pair<unsigned int, unsigned int>& p1) { return p0.first < p1.first; });
458
0
}
459
460
// -------------------------------------------------------------------------- ;
461