• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15899162844

26 Jun 2025 10:14AM UTC coverage: 71.088% (+0.004%) from 71.084%
15899162844

Pull #12623

github

web-flow
Merge c704a8392 into f5cb024d4
Pull Request #12623: gdal raster overview add: add a --overview-src option

209 of 244 new or added lines in 5 files covered. (85.66%)

96 existing lines in 44 files now uncovered.

574014 of 807474 relevant lines covered (71.09%)

250815.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.45
/third_party/LercLib/Lerc2.cpp
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
static void ignore_ret_val(bool) {}
×
32

33
// -------------------------------------------------------------------------- ;
34

35
Lerc2::Lerc2()
7,805✔
36
{
37
  Init();
7,805✔
38
}
7,805✔
39

40
// -------------------------------------------------------------------------- ;
41

42
Lerc2::Lerc2(int nDim, int nCols, int nRows, const Byte* pMaskBits)
×
43
{
44
  Init();
×
45
  ignore_ret_val(Set(nDim, nCols, nRows, pMaskBits));
×
46
}
×
47

48
// -------------------------------------------------------------------------- ;
49

50
bool Lerc2::SetEncoderToOldVersion(int version)
5,180✔
51
{
52
  if (version < 2 || version > kCurrVersion)
5,180✔
53
    return false;
×
54

55
  if (version < 4 && m_headerInfo.nDim > 1)
5,180✔
56
    return false;
×
57

58
  m_headerInfo.version = version;
5,180✔
59

60
  return true;
5,180✔
61
}
62

63
// -------------------------------------------------------------------------- ;
64

65
void Lerc2::Init()
7,805✔
66
{
67
  m_microBlockSize    = 8;
7,805✔
68
  m_maxValToQuantize  = 0;
7,805✔
69
  m_encodeMask        = true;
7,805✔
70
  m_writeDataOneSweep = false;
7,805✔
71
  m_imageEncodeMode   = IEM_Tiling;
7,805✔
72

73
  m_headerInfo.RawInit();
7,805✔
74
  m_headerInfo.version = kCurrVersion;
7,805✔
75
  m_headerInfo.microBlockSize = m_microBlockSize;
7,805✔
76
}
7,805✔
77

78
// -------------------------------------------------------------------------- ;
79

80
bool Lerc2::Set(int nDim, int nCols, int nRows, const Byte* pMaskBits)
5,181✔
81
{
82
  if (nDim > 1 && m_headerInfo.version < 4)
5,181✔
83
    return false;
×
84

85
  if (!m_bitMask.SetSize(nCols, nRows))
5,181✔
86
    return false;
×
87

88
  if (pMaskBits)
5,181✔
89
  {
90
    memcpy(m_bitMask.Bits(), pMaskBits, m_bitMask.Size());
18✔
91
    m_headerInfo.numValidPixel = m_bitMask.CountValidBits();
18✔
92
  }
93
  else
94
  {
95
    m_headerInfo.numValidPixel = nCols * nRows;
5,163✔
96
    m_bitMask.SetAllValid();
5,163✔
97
  }
98

99
  m_headerInfo.nDim  = nDim;
5,181✔
100
  m_headerInfo.nCols = nCols;
5,181✔
101
  m_headerInfo.nRows = nRows;
5,181✔
102

103
  return true;
5,181✔
104
}
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)
7,274✔
121
{
122
  if (!pByte || !IsLittleEndianSystem())
7,274✔
123
    return false;
×
124

125
  return ReadHeader(&pByte, nBytesRemaining, hd);
7,274✔
126
}
127

128
// -------------------------------------------------------------------------- ;
129
// -------------------------------------------------------------------------- ;
130

131
unsigned int Lerc2::ComputeNumBytesHeaderToWrite(const struct HeaderInfo& hd)
5,181✔
132
{
133
  unsigned int numBytes = (unsigned int)FileKey().length();
5,181✔
134
  numBytes += 1 * sizeof(int);
5,181✔
135
  numBytes += (hd.version >= 3 ? 1 : 0) * sizeof(unsigned int);
5,181✔
136
  numBytes += (hd.version >= 4 ? 7 : 6) * sizeof(int);
5,181✔
137
  numBytes += 3 * sizeof(double);
5,181✔
138
  return numBytes;
5,181✔
139
}
140

141
// -------------------------------------------------------------------------- ;
142

143
bool Lerc2::WriteHeader(Byte** ppByte, const struct HeaderInfo& hd)
5,181✔
144
{
145
  if (!ppByte)
5,181✔
146
    return false;
×
147

148
  Byte* ptr = *ppByte;
5,181✔
149

150
  string fileKey = FileKey();
10,362✔
151
  size_t len = fileKey.length();
5,181✔
152
  memcpy(ptr, fileKey.c_str(), len);
5,181✔
153
  ptr += len;
5,181✔
154

155
  memcpy(ptr, &hd.version, sizeof(int));
5,181✔
156
  ptr += sizeof(int);
5,181✔
157

158
  if (hd.version >= 3)
5,181✔
159
  {
160
    unsigned int checksum = 0;
370✔
161
    memcpy(ptr, &checksum, sizeof(unsigned int));    // place holder to be filled by the real check sum later
370✔
162
    ptr += sizeof(unsigned int);
370✔
163
  }
164

165
  vector<int> intVec;
10,362✔
166
  intVec.push_back(hd.nRows);
5,181✔
167
  intVec.push_back(hd.nCols);
5,181✔
168

169
  if (hd.version >= 4)
5,181✔
170
  {
171
    intVec.push_back(hd.nDim);
370✔
172
  }
173

174
  intVec.push_back(hd.numValidPixel);
5,181✔
175
  intVec.push_back(hd.microBlockSize);
5,181✔
176
  intVec.push_back(hd.blobSize);
5,181✔
177
  intVec.push_back((int)hd.dt);
5,181✔
178

179
  len = intVec.size() * sizeof(int);
5,181✔
180
  memcpy(ptr, &intVec[0], len);
5,181✔
181
  ptr += len;
5,181✔
182

183
  vector<double> dblVec;
5,181✔
184
  dblVec.push_back(hd.maxZError);
5,181✔
185
  dblVec.push_back(hd.zMin);
5,181✔
186
  dblVec.push_back(hd.zMax);
5,181✔
187

188
  len = dblVec.size() * sizeof(double);
5,181✔
189
  memcpy(ptr, &dblVec[0], len);
5,181✔
190
  ptr += len;
5,181✔
191

192
  *ppByte = ptr;
5,181✔
193
  return true;
5,181✔
194
}
195

196
// -------------------------------------------------------------------------- ;
197

198
bool Lerc2::ReadHeader(const Byte** ppByte, size_t& nBytesRemainingInOut, struct HeaderInfo& hd)
9,898✔
199
{
200
  if (!ppByte || !*ppByte)
9,898✔
UNCOV
201
    return false;
×
202

203
  const Byte* ptr = *ppByte;
9,898✔
204
  size_t nBytesRemaining = nBytesRemainingInOut;
9,898✔
205

206
  string fileKey = FileKey();
19,794✔
207
  size_t keyLen = fileKey.length();
9,896✔
208

209
  hd.RawInit();
9,896✔
210

211
  if (nBytesRemaining < keyLen || memcmp(ptr, fileKey.c_str(), keyLen))
9,896✔
212
    return false;
1,013✔
213

214
  ptr += keyLen;
8,883✔
215
  nBytesRemaining -= keyLen;
8,883✔
216

217
  if (nBytesRemaining < sizeof(int) || !memcpy(&(hd.version), ptr, sizeof(int)))
8,883✔
218
    return false;
×
219

220
  ptr += sizeof(int);
8,883✔
221
  nBytesRemaining -= sizeof(int);
8,883✔
222

223
  if (hd.version > kCurrVersion)    // this reader is outdated
8,883✔
224
    return false;
×
225

226
  if (hd.version >= 3)
8,883✔
227
  {
228
    if (nBytesRemaining < sizeof(unsigned int) || !memcpy(&(hd.checksum), ptr, sizeof(unsigned int)))
4,048✔
229
      return false;
×
230

231
    ptr += sizeof(unsigned int);
4,048✔
232
    nBytesRemaining -= sizeof(unsigned int);
4,048✔
233
  }
234

235
  int nInts = (hd.version >= 4) ? 7 : 6;
8,883✔
236
  vector<int> intVec(nInts, 0);
17,767✔
237
  vector<double> dblVec(3, 0);
17,766✔
238

239
  size_t len = sizeof(int) * intVec.size();
8,884✔
240

241
  if (nBytesRemaining < len || !memcpy(&intVec[0], ptr, len))
8,884✔
242
    return false;
×
243

244
  ptr += len;
8,885✔
245
  nBytesRemaining -= len;
8,885✔
246

247
  len = sizeof(double) * dblVec.size();
8,885✔
248

249
  if (nBytesRemaining < len || !memcpy(&dblVec[0], ptr, len))
8,884✔
250
    return false;
×
251

252
  ptr += len;
8,883✔
253
  nBytesRemaining -= len;
8,883✔
254

255
  int i = 0;
8,883✔
256
  hd.nRows          = intVec[i++];
8,883✔
257
  hd.nCols          = intVec[i++];
8,885✔
258
  hd.nDim           = (hd.version >= 4) ? intVec[i++] : 1;
8,884✔
259
  hd.numValidPixel  = intVec[i++];
8,884✔
260
  hd.microBlockSize = intVec[i++];
8,885✔
261
  hd.blobSize       = intVec[i++];
8,884✔
262
  const int dt      = intVec[i++];
8,884✔
263
  if( dt < DT_Char || dt > DT_Undefined )
8,885✔
264
    return false;
×
265
  hd.dt             = static_cast<DataType>(dt);
8,885✔
266

267
  hd.maxZError      = dblVec[0];
8,885✔
268
  hd.zMin           = dblVec[1];
8,885✔
269
  hd.zMax           = dblVec[2];
8,885✔
270

271
  if (hd.nRows <= 0 || hd.nCols <= 0 || hd.nDim <= 0 || hd.numValidPixel < 0 || hd.microBlockSize <= 0 || hd.blobSize <= 0)
8,885✔
272
    return false;
×
273

274
  *ppByte = ptr;
8,885✔
275
  nBytesRemainingInOut = nBytesRemaining;
8,885✔
276

277
  return true;
8,885✔
278
}
279

280
// -------------------------------------------------------------------------- ;
281

282
bool Lerc2::WriteMask(Byte** ppByte) const
5,181✔
283
{
284
  if (!ppByte)
5,181✔
285
    return false;
×
286

287
  int numValid = m_headerInfo.numValidPixel;
5,181✔
288
  int numTotal = m_headerInfo.nCols * m_headerInfo.nRows;
5,181✔
289

290
  bool needMask = numValid > 0 && numValid < numTotal;
5,181✔
291

292
  Byte* ptr = *ppByte;
5,181✔
293

294
  if (needMask && m_encodeMask)
5,181✔
295
  {
296
    Byte* pArrRLE;
297
    size_t numBytesRLE;
298
    RLE rle;
9✔
299
    if (!rle.compress((const Byte*)m_bitMask.Bits(), m_bitMask.Size(), &pArrRLE, numBytesRLE, false))
9✔
300
      return false;
×
301

302
    int numBytesMask = (int)numBytesRLE;
9✔
303
    memcpy(ptr, &numBytesMask, sizeof(int));    // num bytes for compressed mask
9✔
304
    ptr += sizeof(int);
9✔
305
    memcpy(ptr, pArrRLE, numBytesRLE);
9✔
306
    ptr += numBytesRLE;
9✔
307

308
    delete[] pArrRLE;
18✔
309
  }
310
  else
311
  {
312
    memset(ptr, 0, sizeof(int));    // indicates no mask stored
5,172✔
313
    ptr += sizeof(int);
5,172✔
314
  }
315

316
  *ppByte = ptr;
5,181✔
317
  return true;
5,181✔
318
}
319

320
// -------------------------------------------------------------------------- ;
321

322
bool Lerc2::ReadMask(const Byte** ppByte, size_t& nBytesRemainingInOut)
2,624✔
323
{
324
  if (!ppByte)
2,624✔
325
    return false;
×
326

327
  int numValid = m_headerInfo.numValidPixel;
2,624✔
328
  int w = m_headerInfo.nCols;
2,624✔
329
  int h = m_headerInfo.nRows;
2,624✔
330

331
  const Byte* ptr = *ppByte;
2,624✔
332
  size_t nBytesRemaining = nBytesRemainingInOut;
2,624✔
333

334
  int numBytesMask;
335
  if (nBytesRemaining < sizeof(int) || !memcpy(&numBytesMask, ptr, sizeof(int)))
2,624✔
336
    return false;
×
337

338
  ptr += sizeof(int);
2,624✔
339
  nBytesRemaining -= sizeof(int);
2,624✔
340

341
  if (numValid == 0 || numValid == w * h)
2,624✔
342
  {
343
    if (numBytesMask != 0)
2,615✔
344
      return false;
×
345
  }
346

347
  if (!m_bitMask.SetSize(w, h))
2,624✔
348
    return false;
×
349

350
  if (numValid == 0)
2,624✔
351
    m_bitMask.SetAllInvalid();
9✔
352
  else if (numValid == w * h)
2,615✔
353
    m_bitMask.SetAllValid();
2,606✔
354
  else if (numBytesMask > 0)    // read it in
9✔
355
  {
356
    if (nBytesRemaining < static_cast<size_t>(numBytesMask))
9✔
357
      return false;
×
358

359
    RLE rle;
9✔
360
    if (!rle.decompress(ptr, nBytesRemaining, m_bitMask.Bits(), m_bitMask.Size()))
9✔
361
      return false;
×
362

363
    ptr += numBytesMask;
9✔
364
    nBytesRemaining -= numBytesMask;
9✔
365
  }
366
  // else use previous mask
367

368
  *ppByte = ptr;
2,624✔
369
  nBytesRemainingInOut = nBytesRemaining;
2,624✔
370

371
  return true;
2,624✔
372
}
373

374
// -------------------------------------------------------------------------- ;
375

376
bool Lerc2::DoChecksOnEncode(Byte* pBlobBegin, Byte* pBlobEnd) const
5,181✔
377
{
378
  if ((size_t)(pBlobEnd - pBlobBegin) != (size_t)m_headerInfo.blobSize)
5,181✔
379
    return false;
×
380

381
  if (m_headerInfo.version >= 3)
5,181✔
382
  {
383
    int blobSize = (int)(pBlobEnd - pBlobBegin);
370✔
384
    int nBytes = (int)(FileKey().length() + sizeof(int) + sizeof(unsigned int));    // start right after the checksum entry
370✔
385
    if (blobSize < nBytes)
370✔
386
      return false;
×
387
    unsigned int checksum = ComputeChecksumFletcher32(pBlobBegin + nBytes, blobSize - nBytes);
370✔
388

389
    nBytes -= sizeof(unsigned int);
370✔
390
    memcpy(pBlobBegin + nBytes, &checksum, sizeof(unsigned int));
370✔
391
  }
392

393
  return true;
5,181✔
394
}
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)
1,383✔
402
{
403
  unsigned int sum1 = 0xffff, sum2 = 0xffff;
1,383✔
404
  unsigned int words = len / 2;
1,383✔
405

406
  while (words)
8,794✔
407
  {
408
    unsigned int tlen = (words >= 359) ? 359 : words;
7,411✔
409
    words -= tlen;
7,411✔
410
    do {
2,404,520✔
411
      sum1 += (*pByte++ << 8);
2,411,940✔
412
      sum2 += sum1 += *pByte++;
2,411,940✔
413
    } while (--tlen);
2,411,940✔
414

415
    sum1 = (sum1 & 0xffff) + (sum1 >> 16);
7,411✔
416
    sum2 = (sum2 & 0xffff) + (sum2 >> 16);
7,411✔
417
  }
418

419
  // add the straggler byte if it exists
420
  if (len & 1)
1,383✔
421
    sum2 += sum1 += (*pByte << 8);
629✔
422

423
  // second reduction step to reduce sums to 16 bits
424
  sum1 = (sum1 & 0xffff) + (sum1 >> 16);
1,383✔
425
  sum2 = (sum2 & 0xffff) + (sum2 >> 16);
1,383✔
426

427
  return sum2 << 16 | sum1;
1,383✔
428
}
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)
709,569✔
441
{
442
  int numElem = (int)quantVec.size();
709,569✔
443
  sortedQuantVec.resize(numElem);
709,569✔
444

445
  for (int i = 0; i < numElem; i++)
71,881,600✔
446
    sortedQuantVec[i] = pair<unsigned int, unsigned int>(quantVec[i], i);
71,172,000✔
447

448
  //std::sort(sortedQuantVec.begin(), sortedQuantVec.end(), MyLessThanOp());
449

450
  std::sort(sortedQuantVec.begin(), sortedQuantVec.end(),
709,569✔
451
    [](const pair<unsigned int, unsigned int>& p0,
371,995,000✔
452
       const pair<unsigned int, unsigned int>& p1) { return p0.first < p1.first; });
371,995,000✔
453
}
709,569✔
454

455
// -------------------------------------------------------------------------- ;
456

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc