Coverage Report

Created: 2025-06-13 06:29

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