Coverage Report

Created: 2025-12-03 08:24

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