Coverage Report

Created: 2026-02-14 09:00

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