Coverage Report

Created: 2026-03-30 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
33.2k
{
37
33.2k
  Init();
38
33.2k
}
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
33.2k
{
67
33.2k
  m_microBlockSize    = 8;
68
33.2k
  m_maxValToQuantize  = 0;
69
33.2k
  m_encodeMask        = true;
70
33.2k
  m_writeDataOneSweep = false;
71
33.2k
  m_imageEncodeMode   = IEM_Tiling;
72
73
33.2k
  m_headerInfo.RawInit();
74
33.2k
  m_headerInfo.version = kCurrVersion;
75
33.2k
  m_headerInfo.microBlockSize = m_microBlockSize;
76
33.2k
}
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
106k
{
122
106k
  if (!pByte || !IsLittleEndianSystem())
123
0
    return false;
124
125
106k
  return ReadHeader(&pByte, nBytesRemaining, hd);
126
106k
}
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
139k
{
200
139k
  if (!ppByte || !*ppByte)
201
0
    return false;
202
203
139k
  const Byte* ptr = *ppByte;
204
139k
  size_t nBytesRemaining = nBytesRemainingInOut;
205
206
139k
  string fileKey = FileKey();
207
139k
  size_t keyLen = fileKey.length();
208
209
139k
  hd.RawInit();
210
211
139k
  if (nBytesRemaining < keyLen || memcmp(ptr, fileKey.c_str(), keyLen))
212
18.9k
    return false;
213
214
120k
  ptr += keyLen;
215
120k
  nBytesRemaining -= keyLen;
216
217
120k
  if (nBytesRemaining < sizeof(int) || !memcpy(&(hd.version), ptr, sizeof(int)))
218
37
    return false;
219
220
120k
  ptr += sizeof(int);
221
120k
  nBytesRemaining -= sizeof(int);
222
223
120k
  if (hd.version > kCurrVersion)    // this reader is outdated
224
102
    return false;
225
226
120k
  if (hd.version >= 3)
227
102k
  {
228
102k
    if (nBytesRemaining < sizeof(unsigned int) || !memcpy(&(hd.checksum), ptr, sizeof(unsigned int)))
229
55
      return false;
230
231
102k
    ptr += sizeof(unsigned int);
232
102k
    nBytesRemaining -= sizeof(unsigned int);
233
102k
  }
234
235
120k
  int nInts = (hd.version >= 4) ? 7 : 6;
236
120k
  vector<int> intVec(nInts, 0);
237
120k
  vector<double> dblVec(3, 0);
238
239
120k
  size_t len = sizeof(int) * intVec.size();
240
241
120k
  if (nBytesRemaining < len || !memcpy(&intVec[0], ptr, len))
242
92
    return false;
243
244
120k
  ptr += len;
245
120k
  nBytesRemaining -= len;
246
247
120k
  len = sizeof(double) * dblVec.size();
248
249
120k
  if (nBytesRemaining < len || !memcpy(&dblVec[0], ptr, len))
250
104
    return false;
251
252
119k
  ptr += len;
253
119k
  nBytesRemaining -= len;
254
255
119k
  int i = 0;
256
119k
  hd.nRows          = intVec[i++];
257
119k
  hd.nCols          = intVec[i++];
258
119k
  hd.nDim           = (hd.version >= 4) ? intVec[i++] : 1;
259
119k
  hd.numValidPixel  = intVec[i++];
260
119k
  hd.microBlockSize = intVec[i++];
261
119k
  hd.blobSize       = intVec[i++];
262
119k
  const int dt      = intVec[i++];
263
119k
  if( dt < DT_Char || dt > DT_Undefined )
264
460
    return false;
265
119k
  hd.dt             = static_cast<DataType>(dt);
266
267
119k
  hd.maxZError      = dblVec[0];
268
119k
  hd.zMin           = dblVec[1];
269
119k
  hd.zMax           = dblVec[2];
270
271
119k
  if (hd.nRows <= 0 || hd.nCols <= 0 || hd.nDim <= 0 || hd.numValidPixel < 0 || hd.microBlockSize <= 0 || hd.blobSize <= 0)
272
662
    return false;
273
274
118k
  *ppByte = ptr;
275
118k
  nBytesRemainingInOut = nBytesRemaining;
276
277
118k
  return true;
278
119k
}
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
32.7k
{
324
32.7k
  if (!ppByte)
325
0
    return false;
326
327
32.7k
  int numValid = m_headerInfo.numValidPixel;
328
32.7k
  int w = m_headerInfo.nCols;
329
32.7k
  int h = m_headerInfo.nRows;
330
331
32.7k
  const Byte* ptr = *ppByte;
332
32.7k
  size_t nBytesRemaining = nBytesRemainingInOut;
333
334
32.7k
  int numBytesMask;
335
32.7k
  if (nBytesRemaining < sizeof(int) || !memcpy(&numBytesMask, ptr, sizeof(int)))
336
126
    return false;
337
338
32.6k
  ptr += sizeof(int);
339
32.6k
  nBytesRemaining -= sizeof(int);
340
341
32.6k
  if (numValid == 0 || numValid == w * h)
342
4.69k
  {
343
4.69k
    if (numBytesMask != 0)
344
199
      return false;
345
4.69k
  }
346
347
32.4k
  if (!m_bitMask.SetSize(w, h))
348
0
    return false;
349
350
32.4k
  if (numValid == 0)
351
146
    m_bitMask.SetAllInvalid();
352
32.2k
  else if (numValid == w * h)
353
4.34k
    m_bitMask.SetAllValid();
354
27.9k
  else if (numBytesMask > 0)    // read it in
355
6.04k
  {
356
6.04k
    if (nBytesRemaining < static_cast<size_t>(numBytesMask))
357
4.44k
      return false;
358
359
1.60k
    RLE rle;
360
1.60k
    if (!rle.decompress(ptr, nBytesRemaining, m_bitMask.Bits(), m_bitMask.Size()))
361
637
      return false;
362
363
963
    ptr += numBytesMask;
364
963
    nBytesRemaining -= numBytesMask;
365
963
  }
366
  // else use previous mask
367
368
27.3k
  *ppByte = ptr;
369
27.3k
  nBytesRemainingInOut = nBytesRemaining;
370
371
27.3k
  return true;
372
32.4k
}
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
28.2k
{
403
28.2k
  unsigned int sum1 = 0xffff, sum2 = 0xffff;
404
28.2k
  unsigned int words = len / 2;
405
406
57.3k
  while (words)
407
29.1k
  {
408
29.1k
    unsigned int tlen = (words >= 359) ? 359 : words;
409
29.1k
    words -= tlen;
410
2.37M
    do {
411
2.37M
      sum1 += (*pByte++ << 8);
412
2.37M
      sum2 += sum1 += *pByte++;
413
2.37M
    } while (--tlen);
414
415
29.1k
    sum1 = (sum1 & 0xffff) + (sum1 >> 16);
416
29.1k
    sum2 = (sum2 & 0xffff) + (sum2 >> 16);
417
29.1k
  }
418
419
  // add the straggler byte if it exists
420
28.2k
  if (len & 1)
421
12.8k
    sum2 += sum1 += (*pByte << 8);
422
423
  // second reduction step to reduce sums to 16 bits
424
28.2k
  sum1 = (sum1 & 0xffff) + (sum1 >> 16);
425
28.2k
  sum2 = (sum2 & 0xffff) + (sum2 >> 16);
426
427
28.2k
  return sum2 << 16 | sum1;
428
28.2k
}
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