• 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

71.31
/third_party/LercLib/Lerc2.h
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
*/
23

24
#ifndef LERC2_H
25
#define LERC2_H
26

27
#include <algorithm>
28
#include <cfloat>
29
#include <cmath>
30
#include <limits>
31
#include <string>
32
#include <typeinfo>
33
#include "Defines.h"
34
#include "BitMask.h"
35
#include "BitStuffer2.h"
36
#include "Huffman.h"
37
#include "RLE.h"
38

39
NAMESPACE_LERC_START
40

41
/**   Lerc2 v1
42
 *
43
 *    -- allow for lossless compression of all common data types
44
 *    -- avoid data type conversions and copies
45
 *    -- optimized compression for segmented rasters (10-15x lossless)
46
 *    -- micro block is 8x8 fixed, only gets doubled to 16x16 if bit rate < 1 bpp
47
 *    -- cnt is replaced by bit mask
48
 *    -- Lerc blob header has data range [min, max]
49
 *    -- harden consistency checks to detect if the byte blob has been tampered with
50
 *    -- drop support for big endian, this is legacy now
51
 *
52
 *    Lerc2 v2
53
 *
54
 *    -- add Huffman coding for better lossless compression of 8 bit data types Char, Byte
55
 *
56
 *    Lerc2 v3
57
 *
58
 *    -- add checksum for the entire byte blob, for more rigorous detection of compressed data corruption
59
 *    -- for the main bit stuffing routine, use an extra uint buffer for guaranteed memory alignment
60
 *    -- this also allows dropping the NumExtraBytesToAllocate functions
61
 *
62
 *    Lerc2 v4
63
 *
64
 *    -- allow array per pixel, nDim values per pixel. Such as RGB, complex number, or larger arrays per pixel
65
 *    -- extend Huffman coding for 8 bit data types from delta only to trying both delta and orig
66
 *    -- for integer data types, allow to drop bit planes containing only random noise
67
 *
68
 */
69

70
class Lerc2
71
{
72
public:
73
  Lerc2();
74
  Lerc2(int nDim, int nCols, int nRows, const Byte* pMaskBits = nullptr);    // valid / invalid bits as byte array
75
  ~Lerc2()  {}
7,805✔
76

77
  bool SetEncoderToOldVersion(int version);    // call this to encode compatible to an old decoder
78

79
  bool Set(int nDim, int nCols, int nRows, const Byte* pMaskBits = nullptr);
80

81
  template<class T>
82
  unsigned int ComputeNumBytesNeededToWrite(const T* arr, double maxZError, bool encodeMask);
83

84
  //static unsigned int MinNumBytesNeededToReadHeader();
85

86
  /// dst buffer already allocated;  byte ptr is moved like a file pointer
87
  template<class T>
88
  bool Encode(const T* arr, Byte** ppByte);
89

90
  // data types supported by Lerc2
91
  enum DataType {DT_Char = 0, DT_Byte, DT_Short, DT_UShort, DT_Int, DT_UInt, DT_Float, DT_Double, DT_Undefined};
92

93
  struct HeaderInfo
94
  {
95
    int version;
96
    unsigned int checksum;
97
    int nRows,
98
        nCols,
99
        nDim,
100
        numValidPixel,
101
        microBlockSize,
102
        blobSize;
103

104
    DataType dt;
105

106
    double  maxZError,
107
            zMin,    // if nDim > 1, this is the overall range
108
            zMax;
109

110
    void RawInit()  { memset(this, 0, sizeof(struct HeaderInfo)); }
17,701✔
111

112
    bool TryHuffman() const  { return version > 1 && (dt == DT_Byte || dt == DT_Char) && maxZError == 0.5; }
12,410✔
113
  };
114

115
  static bool GetHeaderInfo(const Byte* pByte, size_t nBytesRemaining, struct HeaderInfo& headerInfo);
116

117
  /// dst buffer already allocated;  byte ptr is moved like a file pointer
118
  template<class T>
119
  bool Decode(const Byte** ppByte, size_t& nBytesRemaining, T* arr, Byte* pMaskBits = nullptr);    // if mask ptr is not 0, mask bits are returned (even if all valid or same as previous)
120

121
private:
122
  static const int kCurrVersion = 4;    // 2: added Huffman coding to 8 bit types DT_Char, DT_Byte;
123
                                        // 3: changed the bit stuffing to using a uint aligned buffer,
124
                                        //    added Fletcher32 checksum
125
                                        // 4: allow nDim values per pixel
126

127
  enum ImageEncodeMode { IEM_Tiling = 0, IEM_DeltaHuffman, IEM_Huffman };
128
  enum BlockEncodeMode { BEM_RawBinary = 0, BEM_BitStuffSimple, BEM_BitStuffLUT };
129

130
  int         m_microBlockSize,
131
              m_maxValToQuantize;
132
  BitMask     m_bitMask;
133
  HeaderInfo  m_headerInfo;
134
  BitStuffer2 m_bitStuffer2;
135
  bool        m_encodeMask,
136
              m_writeDataOneSweep;
137
  ImageEncodeMode  m_imageEncodeMode;
138

139
  std::vector<double> m_zMinVec, m_zMaxVec;
140
  std::vector<std::pair<unsigned short, unsigned int> > m_huffmanCodes;    // <= 256 codes, 1.5 kB
141

142
private:
143
  static std::string FileKey()  { return "Lerc2 "; }
21,643✔
144
  static bool IsLittleEndianSystem()  { int n = 1;  return (1 == *((Byte*)&n)) && (4 == sizeof(int)); }
20,260✔
145
  void Init();
146

147
  static unsigned int ComputeNumBytesHeaderToWrite(const struct HeaderInfo& hd);
148
  static bool WriteHeader(Byte** ppByte, const struct HeaderInfo& hd);
149
  static bool ReadHeader(const Byte** ppByte, size_t& nBytesRemaining, struct HeaderInfo& hd);
150

151
  bool WriteMask(Byte** ppByte) const;
152
  bool ReadMask(const Byte** ppByte, size_t& nBytesRemaining);
153

154
  bool DoChecksOnEncode(Byte* pBlobBegin, Byte* pBlobEnd) const;
155
  static unsigned int ComputeChecksumFletcher32(const Byte* pByte, int len);
156

157
  static void AddUIntToCounts(int* pCounts, unsigned int val, int nBits);
158
  static void AddIntToCounts(int* pCounts, int val, int nBits);
159

160
  template<class T>
161
  bool TryBitPlaneCompression(const T* data, double eps, double& newMaxZError) const;
162

163
  template<class T>
164
  bool WriteDataOneSweep(const T* data, Byte** ppByte) const;
165

166
  template<class T>
167
  bool ReadDataOneSweep(const Byte** ppByte, size_t& nBytesRemaining, T* data) const;
168

169
  template<class T>
170
  bool WriteTiles(const T* data, Byte** ppByte, int& numBytes, std::vector<double>& zMinVec, std::vector<double>& zMaxVec) const;
171

172
  template<class T>
173
  bool ReadTiles(const Byte** ppByte, size_t& nBytesRemaining, T* data) const;
174

175
  template<class T>
176
  bool GetValidDataAndStats(const T* data, int i0, int i1, int j0, int j1, int iDim,
177
    T* dataBuf, T& zMinA, T& zMaxA, int& numValidPixel, bool& tryLutA) const;
178

179
  static double ComputeMaxVal(double zMin, double zMax, double maxZError);
180

181
  template<class T>
182
  bool NeedToQuantize(int numValidPixel, T zMin, T zMax) const;
183

184
  template<class T>
185
  bool Quantize(const T* dataBuf, int num, T zMin, std::vector<unsigned int>& quantVec) const;
186

187
  template<class T>
188
  int NumBytesTile(int numValidPixel, T zMin, T zMax, bool tryLut, BlockEncodeMode& blockEncodeMode,
189
                   const std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec) const;
190

191
  template<class T>
192
  bool WriteTile(const T* dataBuf, int num, Byte** ppByte, int& numBytesWritten, int j0, T zMin, T zMax,
193
    const std::vector<unsigned int>& quantVec, BlockEncodeMode blockEncodeMode,
194
    const std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec) const;
195

196
  template<class T>
197
  bool ReadTile(const Byte** ppByte, size_t& nBytesRemaining, T* data, int i0, int i1, int j0, int j1, int iDim,
198
                std::vector<unsigned int>& bufferVec) const;
199

200
  template<class T>
201
  int TypeCode(T z, DataType& dtUsed) const;
202

203
  DataType GetDataTypeUsed(int typeCode) const;
204

205
  static DataType ValidateDataType(int dt);
206

207
  static bool WriteVariableDataType(Byte** ppByte, double z, DataType dtUsed);
208

209
  static double ReadVariableDataType(const Byte** ppByte, DataType dtUsed);
210

211
  template<class T> DataType GetDataType(T z) const;
212

213
  static unsigned int GetMaxValToQuantize(DataType dt);
214

215
  static unsigned int GetDataTypeSize(DataType dt);
216

217
  static void SortQuantArray(const std::vector<unsigned int>& quantVec,
218
    std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec);
219

220
  template<class T>
221
  void ComputeHuffmanCodes(const T* data, int& numBytes, ImageEncodeMode& imageEncodeMode,
222
    std::vector<std::pair<unsigned short, unsigned int> >& codes) const;
223

224
  template<class T>
225
  void ComputeHistoForHuffman(const T* data, std::vector<int>& histo, std::vector<int>& deltaHisto) const;
226

227
  template<class T>
228
  bool EncodeHuffman(const T* data, Byte** ppByte) const;
229

230
  template<class T>
231
  bool DecodeHuffman(const Byte** ppByte, size_t& nBytesRemaining, T* data) const;
232

233
  template<class T>
234
  bool WriteMinMaxRanges(const T* data, Byte** ppByte) const;
235

236
  template<class T>
237
  bool ReadMinMaxRanges(const Byte** ppByte, size_t& nBytesRemaining, const T* data);
238

239
  bool CheckMinMaxRanges(bool& minMaxEqual) const;
240

241
  template<class T>
242
  bool FillConstImage(T* data) const;
243
};
244

245
// -------------------------------------------------------------------------- ;
246
// -------------------------------------------------------------------------- ;
247

248
template<class T>
249
unsigned int Lerc2::ComputeNumBytesNeededToWrite(const T* arr, double maxZError, bool encodeMask)
5,181✔
250
{
251
  if (!arr || !IsLittleEndianSystem())
5,181✔
252
    return 0;
×
253

254
  // header
255
  unsigned int nBytesHeaderMask = ComputeNumBytesHeaderToWrite(m_headerInfo);
5,181✔
256

257
  // valid / invalid mask
258
  int numValid = m_headerInfo.numValidPixel;
5,181✔
259
  int numTotal = m_headerInfo.nCols * m_headerInfo.nRows;
5,181✔
260

261
  bool needMask = numValid > 0 && numValid < numTotal;
5,181✔
262

263
  m_encodeMask = encodeMask;
5,181✔
264

265
  nBytesHeaderMask += 1 * sizeof(int);    // the mask encode numBytes
5,181✔
266

267
  if (needMask && encodeMask)
5,181✔
268
  {
269
    RLE rle;
9✔
270
    size_t n = rle.computeNumBytesRLE((const Byte*)m_bitMask.Bits(), m_bitMask.Size());
9✔
271
    nBytesHeaderMask += (unsigned int)n;
9✔
272
  }
273

274
  m_headerInfo.dt = GetDataType(arr[0]);
5,181✔
275

276
  if (m_headerInfo.dt == DT_Undefined)
5,181✔
277
    return 0;
×
278

279
  if (maxZError == 777)    // cheat code
5,181✔
280
    maxZError = -0.01;
×
281

282
  if (m_headerInfo.dt < DT_Float)    // integer types
5,181✔
283
  {
284
    // interpret a negative maxZError as bit plane epsilon; dflt = 0.01;
285
    if (maxZError < 0 && (!TryBitPlaneCompression(arr, -maxZError, maxZError)))
5,128✔
286
      maxZError = 0;
×
287

288
    maxZError = std::max(0.5, floor(maxZError));
5,128✔
289
  }
290
  else if (maxZError < 0)    // don't allow bit plane compression for float or double yet
53✔
291
    return 0;
×
292

293
  m_headerInfo.maxZError = maxZError;
5,181✔
294
  m_headerInfo.zMin = 0;
5,181✔
295
  m_headerInfo.zMax = 0;
5,181✔
296
  m_headerInfo.microBlockSize = m_microBlockSize;
5,181✔
297
  m_headerInfo.blobSize = nBytesHeaderMask;
5,181✔
298

299
  if (numValid == 0)
5,181✔
300
    return nBytesHeaderMask;
9✔
301

302
  m_maxValToQuantize = GetMaxValToQuantize(m_headerInfo.dt);
5,172✔
303

304
  Byte* ptr = nullptr;    // only emulate the writing and just count the bytes needed
5,172✔
305
  int nBytesTiling = 0;
5,172✔
306

307
  if (!WriteTiles(arr, &ptr, nBytesTiling, m_zMinVec, m_zMaxVec))    // also fills the min max ranges
5,172✔
308
    return 0;
×
309

310
  m_headerInfo.zMin = *std::min_element(m_zMinVec.begin(), m_zMinVec.end());
5,172✔
311
  m_headerInfo.zMax = *std::max_element(m_zMaxVec.begin(), m_zMaxVec.end());
5,172✔
312

313
  if (m_headerInfo.zMin == m_headerInfo.zMax)    // image is const
5,172✔
314
    return nBytesHeaderMask;
1,699✔
315

316
  int nDim = m_headerInfo.nDim;
3,473✔
317

318
  if (m_headerInfo.version >= 4)
3,473✔
319
  {
320
    // add the min max ranges behind the mask and before the main data;
321
    // so we do not write it if no valid pixel or all same value const
322
    m_headerInfo.blobSize += 2 * nDim * sizeof(T);
342✔
323

324
    bool minMaxEqual = false;
342✔
325
    if (!CheckMinMaxRanges(minMaxEqual))
342✔
326
      return 0;
×
327

328
    if (minMaxEqual)
342✔
329
      return m_headerInfo.blobSize;    // all nDim bands are const
×
330
  }
331

332
  // data
333
  m_imageEncodeMode = IEM_Tiling;
3,473✔
334
  int nBytesData = nBytesTiling;
3,473✔
335
  int nBytesHuffman = 0;
3,473✔
336

337
  if (m_headerInfo.TryHuffman())
3,473✔
338
  {
339
    ImageEncodeMode huffmanEncMode;
340
    ComputeHuffmanCodes(arr, nBytesHuffman, huffmanEncMode, m_huffmanCodes);    // save Huffman codes for later use
3,327✔
341

342
    if (!m_huffmanCodes.empty() && nBytesHuffman < nBytesTiling)
3,327✔
343
    {
344
      m_imageEncodeMode = huffmanEncMode;
640✔
345
      nBytesData = nBytesHuffman;
640✔
346
    }
347
    else
348
      m_huffmanCodes.resize(0);
2,687✔
349
  }
350

351
  m_writeDataOneSweep = false;
3,473✔
352
  int nBytesDataOneSweep = (int)(numValid * nDim * sizeof(T));
3,473✔
353

354
  {
355
    // try with double block size to reduce block header overhead, if
356
    if ( (nBytesTiling * 8 < numTotal * nDim * 2)    // resulting bit rate < x (2 bpp)
3,473✔
357
      && (nBytesTiling < 4 * nBytesDataOneSweep)     // bit stuffing is effective
3,154✔
358
      && (nBytesHuffman == 0 || nBytesTiling < 2 * nBytesHuffman) )    // not much worse than huffman (otherwise huffman wins anyway)
3,154✔
359
    {
360
      m_headerInfo.microBlockSize = m_microBlockSize * 2;
3,154✔
361

362
      std::vector<double> zMinVec, zMaxVec;
3,154✔
363
      int nBytes2 = 0;
3,154✔
364
      if (!WriteTiles(arr, &ptr, nBytes2, zMinVec, zMaxVec))    // no huffman in here anymore
3,154✔
365
        return 0;
×
366

367
      if (nBytes2 <= nBytesData)
3,154✔
368
      {
369
        nBytesData = nBytes2;
627✔
370
        m_imageEncodeMode = IEM_Tiling;
627✔
371
        m_huffmanCodes.resize(0);
627✔
372
      }
373
      else
374
      {
375
        m_headerInfo.microBlockSize = m_microBlockSize;    // reset to orig
2,527✔
376
      }
377
    }
378
  }
379

380
  if (m_headerInfo.TryHuffman())
3,473✔
381
    nBytesData += 1;    // flag for image encode mode
3,327✔
382

383
  if (nBytesDataOneSweep <= nBytesData)
3,473✔
384
  {
385
    m_writeDataOneSweep = true;    // fallback: write data binary uncompressed in one sweep
24✔
386
    m_headerInfo.blobSize += 1 + nBytesDataOneSweep;    // header, mask, min max ranges, flag, data one sweep
24✔
387
  }
388
  else
389
  {
390
    m_writeDataOneSweep = false;
3,449✔
391
    m_headerInfo.blobSize += 1 + nBytesData;    // header, mask, min max ranges, flag(s), data
3,449✔
392
  }
393

394
  return m_headerInfo.blobSize;
3,473✔
395
}
396

397
// -------------------------------------------------------------------------- ;
398

399
template<class T>
400
bool Lerc2::Encode(const T* arr, Byte** ppByte)
5,181✔
401
{
402
  if (!arr || !ppByte || !IsLittleEndianSystem())
5,181✔
403
    return false;
×
404

405
  Byte* ptrBlob = *ppByte;    // keep a ptr to the start of the blob
5,181✔
406

407
  if (!WriteHeader(ppByte, m_headerInfo))
5,181✔
408
    return false;
×
409

410
  if (!WriteMask(ppByte))
5,181✔
411
    return false;
×
412

413
  if (m_headerInfo.numValidPixel == 0 || m_headerInfo.zMin == m_headerInfo.zMax)
5,181✔
414
  {
415
    return DoChecksOnEncode(ptrBlob, *ppByte);
1,708✔
416
  }
417

418
  if (m_headerInfo.version >= 4)
3,473✔
419
  {
420
    if (!WriteMinMaxRanges(arr, ppByte))
342✔
421
      return false;
×
422

423
    bool minMaxEqual = false;
342✔
424
    if (!CheckMinMaxRanges(minMaxEqual))
342✔
425
      return false;
×
426

427
    if (minMaxEqual)
342✔
428
      return DoChecksOnEncode(ptrBlob, *ppByte);
×
429
  }
430

431
  **ppByte = m_writeDataOneSweep ? 1 : 0;    // write flag
3,473✔
432
  (*ppByte)++;
3,473✔
433

434
  if (!m_writeDataOneSweep)
3,473✔
435
  {
436
    if (m_headerInfo.TryHuffman())
3,449✔
437
    {
438
      **ppByte = (Byte)m_imageEncodeMode;    // Huffman or tiling encode mode
3,327✔
439
      (*ppByte)++;
3,327✔
440

441
      if (!m_huffmanCodes.empty())   // Huffman, no tiling
3,327✔
442
      {
443
        if (m_imageEncodeMode != IEM_DeltaHuffman && m_imageEncodeMode != IEM_Huffman)
640✔
444
          return false;
640✔
445

446
        if (!EncodeHuffman(arr, ppByte))    // data bit stuffed
640✔
447
          return false;
×
448

449
        return DoChecksOnEncode(ptrBlob, *ppByte);
640✔
450
      }
451
    }
452

453
    int numBytes = 0;
2,809✔
454
    std::vector<double> zMinVec, zMaxVec;
2,809✔
455
    if (!WriteTiles(arr, ppByte, numBytes, zMinVec, zMaxVec))
2,809✔
456
      return false;
×
457
  }
458
  else
459
  {
460
    if (!WriteDataOneSweep(arr, ppByte))
24✔
461
      return false;
×
462
  }
463

464
  return DoChecksOnEncode(ptrBlob, *ppByte);
2,833✔
465
}
466

467
// -------------------------------------------------------------------------- ;
468

469
template<class T>
470
bool Lerc2::Decode(const Byte** ppByte, size_t& nBytesRemaining, T* arr, Byte* pMaskBits)
2,624✔
471
{
472
  if (!arr || !ppByte || !IsLittleEndianSystem())
2,624✔
473
    return false;
×
474

475
  const Byte* ptrBlob = *ppByte;    // keep a ptr to the start of the blob
2,624✔
476
  size_t nBytesRemaining00 = nBytesRemaining;
2,624✔
477

478
  if (!ReadHeader(ppByte, nBytesRemaining, m_headerInfo))
2,624✔
479
    return false;
×
480

481
  if (nBytesRemaining00 < (size_t)m_headerInfo.blobSize)
2,624✔
482
    return false;
×
483

484
  if (m_headerInfo.version >= 3)
2,624✔
485
  {
486
    int nBytes = (int)(FileKey().length() + sizeof(int) + sizeof(unsigned int));    // start right after the checksum entry
1,013✔
487
    if (m_headerInfo.blobSize < nBytes)
1,013✔
488
      return false;
×
489
    unsigned int checksum = ComputeChecksumFletcher32(ptrBlob + nBytes, m_headerInfo.blobSize - nBytes);
1,013✔
490
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
491
    // For fuzzing, ignore checksum verification
492
    (void)checksum;
493
#else
494
    if (checksum != m_headerInfo.checksum)
1,013✔
495
      return false;
×
496
#endif
497
  }
498

499
  if (!ReadMask(ppByte, nBytesRemaining))
2,624✔
500
    return false;
×
501

502
  if (pMaskBits)    // return proper mask bits even if they were not stored
2,624✔
503
    memcpy(pMaskBits, m_bitMask.Bits(), m_bitMask.Size());
51✔
504

505
  memset(arr, 0, m_headerInfo.nCols * m_headerInfo.nRows * m_headerInfo.nDim * sizeof(T));
2,624✔
506

507
  if (m_headerInfo.numValidPixel == 0)
2,624✔
508
    return true;
9✔
509

510
  if (m_headerInfo.zMin == m_headerInfo.zMax)    // image is const
2,615✔
511
  {
512
    if (!FillConstImage(arr))
576✔
513
      return false;
×
514

515
    return true;
576✔
516
  }
517

518
  if (m_headerInfo.version >= 4)
2,039✔
519
  {
520
    if (!ReadMinMaxRanges(ppByte, nBytesRemaining, arr))
987✔
521
      return false;
×
522

523
    bool minMaxEqual = false;
987✔
524
    if (!CheckMinMaxRanges(minMaxEqual))
987✔
525
      return false;
×
526

527
    if (minMaxEqual)    // if all bands are const, fill outgoing and done
987✔
528
    {
529
      if (!FillConstImage(arr))
×
530
        return false;
×
531

532
      return true;    // done
×
533
    }
534
  }
535

536
  if (nBytesRemaining < 1)
2,039✔
537
    return false;
×
538

539
  Byte readDataOneSweep = **ppByte;    // read flag
2,039✔
540
  (*ppByte)++;
2,039✔
541
  nBytesRemaining--;
2,039✔
542

543
  if (!readDataOneSweep)
2,039✔
544
  {
545
    if (m_headerInfo.TryHuffman())
2,015✔
546
    {
547
      if (nBytesRemaining < 1)
1,810✔
548
        return false;
×
549

550
      Byte flag = **ppByte;    // read flag Huffman / Lerc2
1,810✔
551
      (*ppByte)++;
1,810✔
552
      nBytesRemaining--;
1,810✔
553

554
      if (flag > 2 || (m_headerInfo.version < 4 && flag > 1))
1,810✔
555
        return false;
×
556

557
      m_imageEncodeMode = (ImageEncodeMode)flag;
1,810✔
558

559
      if (m_imageEncodeMode == IEM_DeltaHuffman || m_imageEncodeMode == IEM_Huffman)
1,810✔
560
      {
561
        if (!DecodeHuffman(ppByte, nBytesRemaining, arr))
513✔
562
          return false;
×
563

564
        return true;    // done.
513✔
565
      }
566
    }
567

568
    if (!ReadTiles(ppByte, nBytesRemaining, arr))
1,502✔
569
      return false;
×
570
  }
571
  else
572
  {
573
    if (!ReadDataOneSweep(ppByte, nBytesRemaining, arr))
24✔
574
      return false;
×
575
  }
576

577
  return true;
1,526✔
578
}
579

580
// -------------------------------------------------------------------------- ;
581
// -------------------------------------------------------------------------- ;
582

583
inline
584
void Lerc2::AddUIntToCounts(int* pCounts, unsigned int val, int nBits)
×
585
{
586
  pCounts[0] += val & 1;
×
587
  for (int i = 1; i < nBits; i++)
×
588
    pCounts[i] += (val >>= 1) & 1;
×
589
}
×
590

591
// -------------------------------------------------------------------------- ;
592

593
inline
594
void Lerc2::AddIntToCounts(int* pCounts, int val, int nBits)
×
595
{
596
  pCounts[0] += val & 1;
×
597
  for (int i = 1; i < nBits; i++)
×
598
    pCounts[i] += (val >>= 1) & 1;
×
599
}
×
600

601
// -------------------------------------------------------------------------- ;
602

603
// for the theory and math, see
604
// https://pdfs.semanticscholar.org/d064/2e2ad1a4c3b445b0d795770f604a5d9e269c.pdf
605

606
template<class T>
607
bool Lerc2::TryBitPlaneCompression(const T* data, double eps, double& newMaxZError) const
×
608
{
609
  newMaxZError = 0;    // lossless is the obvious fallback
×
610

611
  if (!data || eps <= 0)
×
612
    return false;
×
613

614
  const HeaderInfo& hd = m_headerInfo;
×
615
  const int nDim = hd.nDim;
×
616
  const int maxShift = 8 * GetDataTypeSize(hd.dt);
×
617
  const int minCnt = 5000;
×
618

619
  if (hd.numValidPixel < minCnt)    // not enough data for good stats
×
620
    return false;
×
621

622
  std::vector<int> cntDiffVec(nDim * maxShift, 0);
×
623
  int cnt = 0;
×
624

625
  if (nDim == 1 && hd.numValidPixel == hd.nCols * hd.nRows)    // special but common case
×
626
  {
627
    if (hd.dt == DT_Byte || hd.dt == DT_UShort || hd.dt == DT_UInt)    // unsigned int
×
628
    {
629
      for (int i = 0; i < hd.nRows - 1; i++)
×
630
        for (int k = i * hd.nCols, j = 0; j < hd.nCols - 1; j++, k++)
×
631
        {
632
          unsigned int c = ((unsigned int)data[k]) ^ ((unsigned int)data[k + 1]);
×
633
          AddUIntToCounts(&cntDiffVec[0], c, maxShift);
×
634
          cnt++;
×
635
          c = ((unsigned int)data[k]) ^ ((unsigned int)data[k + hd.nCols]);
×
636
          AddUIntToCounts(&cntDiffVec[0], c, maxShift);
×
637
          cnt++;
×
638
        }
×
639
    }
640
    else if (hd.dt == DT_Char || hd.dt == DT_Short || hd.dt == DT_Int)    // signed int
×
641
    {
642
      for (int i = 0; i < hd.nRows - 1; i++)
×
643
        for (int k = i * hd.nCols, j = 0; j < hd.nCols - 1; j++, k++)
×
644
        {
645
          int c = ((int)data[k]) ^ ((int)data[k + 1]);
×
646
          AddIntToCounts(&cntDiffVec[0], c, maxShift);
×
647
          cnt++;
×
648
          c = ((int)data[k]) ^ ((int)data[k + hd.nCols]);
×
649
          AddIntToCounts(&cntDiffVec[0], c, maxShift);
×
650
          cnt++;
×
651
        }
×
652
    }
653
    else
654
      return false;    // unsupported data type
×
655
  }
656

657
  else    // general case:  nDim > 1 or not all pixel valid
658
  {
659
    if (hd.dt == DT_Byte || hd.dt == DT_UShort || hd.dt == DT_UInt)    // unsigned int
×
660
    {
661
      for (int k = 0, m0 = 0, i = 0; i < hd.nRows; i++)
×
662
        for (int j = 0; j < hd.nCols; j++, k++, m0 += nDim)
×
663
          if (m_bitMask.IsValid(k))
×
664
          {
665
            if (j < hd.nCols - 1 && m_bitMask.IsValid(k + 1))    // hori
×
666
            {
667
              for (int s0 = 0, iDim = 0; iDim < nDim; iDim++, s0 += maxShift)
×
668
              {
669
                unsigned int c = ((unsigned int)data[m0 + iDim]) ^ ((unsigned int)data[m0 + iDim + nDim]);
×
670
                AddUIntToCounts(&cntDiffVec[s0], c, maxShift);
×
671
              }
672
              cnt++;
×
673
            }
674
            if (i < hd.nRows - 1 && m_bitMask.IsValid(k + hd.nCols))    // vert
×
675
            {
676
              for (int s0 = 0, iDim = 0; iDim < nDim; iDim++, s0 += maxShift)
×
677
              {
678
                unsigned int c = ((unsigned int)data[m0 + iDim]) ^ ((unsigned int)data[m0 + iDim + nDim * hd.nCols]);
×
679
                AddUIntToCounts(&cntDiffVec[s0], c, maxShift);
×
680
              }
681
              cnt++;
×
682
            }
683
          }
×
684
    }
685
    else if (hd.dt == DT_Char || hd.dt == DT_Short || hd.dt == DT_Int)    // signed int
×
686
    {
687
      for (int k = 0, m0 = 0, i = 0; i < hd.nRows; i++)
×
688
        for (int j = 0; j < hd.nCols; j++, k++, m0 += nDim)
×
689
          if (m_bitMask.IsValid(k))
×
690
          {
691
            if (j < hd.nCols - 1 && m_bitMask.IsValid(k + 1))    // hori
×
692
            {
693
              for (int s0 = 0, iDim = 0; iDim < nDim; iDim++, s0 += maxShift)
×
694
              {
695
                int c = ((int)data[m0 + iDim]) ^ ((int)data[m0 + iDim + nDim]);
×
696
                AddIntToCounts(&cntDiffVec[s0], c, maxShift);
×
697
              }
698
              cnt++;
×
699
            }
700
            if (i < hd.nRows - 1 && m_bitMask.IsValid(k + hd.nCols))    // vert
×
701
            {
702
              for (int s0 = 0, iDim = 0; iDim < nDim; iDim++, s0 += maxShift)
×
703
              {
704
                int c = ((int)data[m0 + iDim]) ^ ((int)data[m0 + iDim + nDim * hd.nCols]);
×
705
                AddIntToCounts(&cntDiffVec[s0], c, maxShift);
×
706
              }
707
              cnt++;
×
708
            }
709
          }
×
710
    }
711
    else
712
      return false;    // unsupported data type
×
713
  }
714

715
  if (cnt < minCnt)    // not enough data for good stats
×
716
    return false;
×
717

718
  int nCutFound = 0, lastPlaneKept = 0;
×
719
  const bool printAll = false;
×
720

721
  for (int s = maxShift - 1; s >= 0; s--)
×
722
  {
723
    if (printAll) printf("bit plane %2d: ", s);
724
    bool bCrit = true;
×
725

726
    for (int iDim = 0; iDim < nDim; iDim++)
×
727
    {
728
      double x = cntDiffVec[iDim * maxShift + s];
×
729
      double n = cnt;
×
730
      double m = x / n;
×
731
      //double stdDev = sqrt(x * x / n - m * m) / n;
732

733
      //printf("  %.4f +- %.4f  ", (float)(2 * m), (float)(2 * stdDev));
734
      if (printAll) printf("  %.4f ", (float)(2 * m));
735

736
      if (fabs(1 - 2 * m) >= eps)
×
737
        bCrit = false;
×
738
    }
739
    if (printAll) printf("\n");
740

741
    if (bCrit && nCutFound < 2)
×
742
    {
743
      if (nCutFound == 0)
×
744
        lastPlaneKept = s;
×
745

746
      if (nCutFound == 1 && s < lastPlaneKept - 1)
×
747
      {
748
        lastPlaneKept = s;
×
749
        nCutFound = 0;
×
750
        if (printAll) printf(" reset ");
751
      }
752

753
      nCutFound++;
×
754
      if (printAll && nCutFound == 1) printf("\n");
755
    }
756
  }
757

758
  lastPlaneKept = std::max(0, lastPlaneKept);
×
759
  if (printAll) printf("%d \n", lastPlaneKept);
760

761
  newMaxZError = (1 << lastPlaneKept) >> 1;    // turn lastPlaneKept into new maxZError
×
762

763
  return true;
×
764
}
765

766
// -------------------------------------------------------------------------- ;
767

768
template<class T>
769
bool Lerc2::WriteDataOneSweep(const T* data, Byte** ppByte) const
24✔
770
{
771
  if (!data || !ppByte)
24✔
772
    return false;
×
773

774
  Byte* ptr = (*ppByte);
24✔
775
  const HeaderInfo& hd = m_headerInfo;
24✔
776
  int nDim = hd.nDim;
24✔
777
  int len = nDim * sizeof(T);
24✔
778

779
  for (int k = 0, m0 = 0, i = 0; i < hd.nRows; i++)
86✔
780
    for (int j = 0; j < hd.nCols; j++, k++, m0 += nDim)
3,492✔
781
      if (m_bitMask.IsValid(k))
3,430✔
782
      {
783
        memcpy(ptr, &data[m0], len);
3,430✔
784
        ptr += len;
3,430✔
785
      }
786

787
  (*ppByte) = ptr;
24✔
788
  return true;
24✔
789
}
790

791
// -------------------------------------------------------------------------- ;
792

793
template<class T>
794
bool Lerc2::ReadDataOneSweep(const Byte** ppByte, size_t& nBytesRemaining, T* data) const
24✔
795
{
796
  if (!data || !ppByte || !(*ppByte))
24✔
797
    return false;
×
798

799
  const Byte* ptr = (*ppByte);
24✔
800
  const HeaderInfo& hd = m_headerInfo;
24✔
801
  int nDim = hd.nDim;
24✔
802
  int len = nDim * sizeof(T);
24✔
803

804
  size_t nValidPix = (size_t)m_bitMask.CountValidBits();
24✔
805

806
  if (nBytesRemaining < nValidPix * len)
24✔
807
    return false;
×
808

809
  for (int k = 0, m0 = 0, i = 0; i < hd.nRows; i++)
86✔
810
    for (int j = 0; j < hd.nCols; j++, k++, m0 += nDim)
3,492✔
811
      if (m_bitMask.IsValid(k))
3,430✔
812
      {
813
        memcpy(&data[m0], ptr, len);
3,430✔
814
        ptr += len;
3,430✔
815
      }
816

817
  (*ppByte) = ptr;
24✔
818
  nBytesRemaining -= nValidPix * len;
24✔
819

820
  return true;
24✔
821
}
822

823
// -------------------------------------------------------------------------- ;
824

825
template<class T>
826
bool Lerc2::WriteTiles(const T* data, Byte** ppByte, int& numBytes, std::vector<double>& zMinVec, std::vector<double>& zMaxVec) const
11,135✔
827
{
828
  if (!data || !ppByte)
11,135✔
829
    return false;
×
830

831
  numBytes = 0;
11,135✔
832
  int numBytesLerc = 0;
11,135✔
833

834
  std::vector<unsigned int> quantVec;
22,270✔
835
  std::vector<std::pair<unsigned int, unsigned int> > sortedQuantVec;
22,270✔
836

837
  const HeaderInfo& hd = m_headerInfo;
11,135✔
838
  int mbSize = hd.microBlockSize;
11,135✔
839
  int nDim = hd.nDim;
11,135✔
840

841
  std::vector<T> dataVec(mbSize * mbSize, 0);
22,270✔
842
  T* dataBuf = &dataVec[0];
11,135✔
843

844
  zMinVec.assign(nDim, DBL_MAX);
11,135✔
845
  zMaxVec.assign(nDim, -DBL_MAX);
11,135✔
846

847
  int numTilesVert = (hd.nRows + mbSize - 1) / mbSize;
11,135✔
848
  int numTilesHori = (hd.nCols + mbSize - 1) / mbSize;
11,135✔
849

850
  for (int iTile = 0; iTile < numTilesVert; iTile++)
155,882✔
851
  {
852
    int tileH = mbSize;
144,747✔
853
    int i0 = iTile * tileH;
144,747✔
854
    if (iTile == numTilesVert - 1)
144,747✔
855
      tileH = hd.nRows - i0;
11,135✔
856

857
    for (int jTile = 0; jTile < numTilesHori; jTile++)
2,319,464✔
858
    {
859
      int tileW = mbSize;
2,174,719✔
860
      int j0 = jTile * tileW;
2,174,719✔
861
      if (jTile == numTilesHori - 1)
2,174,719✔
862
        tileW = hd.nCols - j0;
144,747✔
863

864
      for (int iDim = 0; iDim < nDim; iDim++)
4,489,554✔
865
      {
866
        T zMin = 0, zMax = 0;
2,314,845✔
867
        int numValidPixel = 0;
2,314,845✔
868
        bool tryLut = false;
2,314,845✔
869

870
        if (!GetValidDataAndStats(data, i0, i0 + tileH, j0, j0 + tileW, iDim, dataBuf, zMin, zMax, numValidPixel, tryLut))
2,314,845✔
871
          return false;
×
872

873
        if (numValidPixel > 0)
2,314,845✔
874
        {
875
          zMinVec[iDim] = (std::min)(zMinVec[iDim], (double)zMin);
2,314,845✔
876
          zMaxVec[iDim] = (std::max)(zMaxVec[iDim], (double)zMax);
2,314,845✔
877
        }
878

879
        //tryLut = false;
880

881
        // if needed, quantize the data here once
882
        if ((*ppByte || tryLut) && NeedToQuantize(numValidPixel, zMin, zMax))
2,314,845✔
883
        {
884
          if (!Quantize(dataBuf, numValidPixel, zMin, quantVec))
728,526✔
885
            return false;
×
886

887
          if (tryLut)
728,526✔
888
            SortQuantArray(quantVec, sortedQuantVec);
709,569✔
889
        }
890

891
        BlockEncodeMode blockEncodeMode;
892
        int numBytesNeeded = NumBytesTile(numValidPixel, zMin, zMax, tryLut, blockEncodeMode, sortedQuantVec);
2,314,845✔
893
        numBytesLerc += numBytesNeeded;
2,314,845✔
894

895
        if (*ppByte)
2,314,845✔
896
        {
897
          int numBytesWritten = 0;
629,449✔
898

899
          if (!WriteTile(dataBuf, numValidPixel, ppByte, numBytesWritten, j0, zMin, zMax, quantVec, blockEncodeMode, sortedQuantVec))
629,449✔
900
            return false;
×
901

902
          if (numBytesWritten != numBytesNeeded)
629,449✔
903
            return false;
×
904
        }
905
      }
906
    }
907
  }
908

909
  numBytes += numBytesLerc;
11,135✔
910
  return true;
11,135✔
911
}
912

913
// -------------------------------------------------------------------------- ;
914

915
template<class T>
916
bool Lerc2::ReadTiles(const Byte** ppByte, size_t& nBytesRemaining, T* data) const
1,502✔
917
{
918
  if (!data || !ppByte || !(*ppByte))
1,502✔
UNCOV
919
    return false;
×
920

921
  std::vector<unsigned int> bufferVec;
3,006✔
922

923
  const HeaderInfo& hd = m_headerInfo;
1,502✔
924
  int mbSize = hd.microBlockSize;
1,502✔
925
  int nDim = hd.nDim;
1,502✔
926

927
  if (mbSize > 32)  // fail gracefully in case of corrupted blob for old version <= 2 which had no checksum
1,502✔
928
    return false;
×
929

930
  if( mbSize <= 0 || hd.nRows < 0 || hd.nCols < 0 ||
1,502✔
931
      hd.nRows > std::numeric_limits<int>::max() - (mbSize - 1) ||
4,506✔
932
      hd.nCols > std::numeric_limits<int>::max() - (mbSize - 1) )
1,502✔
933
  {
934
    return false;
×
935
  }
936
  int numTilesVert = (hd.nRows + mbSize - 1) / mbSize;
1,502✔
937
  int numTilesHori = (hd.nCols + mbSize - 1) / mbSize;
1,502✔
938

939
  for (int iTile = 0; iTile < numTilesVert; iTile++)
17,449✔
940
  {
941
    int tileH = mbSize;
15,947✔
942
    int i0 = iTile * tileH;
15,947✔
943
    if (iTile == numTilesVert - 1)
15,947✔
944
      tileH = hd.nRows - i0;
1,502✔
945

946
    for (int jTile = 0; jTile < numTilesHori; jTile++)
256,687✔
947
    {
948
      int tileW = mbSize;
240,740✔
949
      int j0 = jTile * tileW;
240,740✔
950
      if (jTile == numTilesHori - 1)
240,740✔
951
        tileW = hd.nCols - j0;
15,947✔
952

953
      for (int iDim = 0; iDim < nDim; iDim++)
494,761✔
954
      {
955
        if (!ReadTile(ppByte, nBytesRemaining, data, i0, i0 + tileH, j0, j0 + tileW, iDim, bufferVec))
254,021✔
956
          return false;
2✔
957
      }
958
    }
959
  }
960

961
  return true;
1,502✔
962
}
963

964
// -------------------------------------------------------------------------- ;
965

966
template<class T>
967
bool Lerc2::GetValidDataAndStats(const T* data, int i0, int i1, int j0, int j1, int iDim,
2,314,845✔
968
  T* dataBuf, T& zMin, T& zMax, int& numValidPixel, bool& tryLut) const
969
{
970
  const HeaderInfo& hd = m_headerInfo;
2,314,845✔
971

972
  if (!data || i0 < 0 || j0 < 0 || i1 > hd.nRows || j1 > hd.nCols || iDim < 0 || iDim > hd.nDim || !dataBuf)
2,314,845✔
973
    return false;
×
974

975
  zMin = 0;
2,314,845✔
976
  zMax = 0;
2,314,845✔
977
  tryLut = false;
2,314,845✔
978

979
  T prevVal = 0;
2,314,845✔
980
  int cnt = 0, cntSameVal = 0;
2,314,845✔
981
  int nDim = hd.nDim;
2,314,845✔
982

983
  if (hd.numValidPixel == hd.nCols * hd.nRows)    // all valid, no mask
2,314,845✔
984
  {
985
    for (int i = i0; i < i1; i++)
23,229,467✔
986
    {
987
      int k = i * hd.nCols + j0;
20,914,786✔
988
      int m = k * nDim + iDim;
20,914,786✔
989

990
      for (int j = j0; j < j1; j++, k++, m += nDim)
226,880,342✔
991
      {
992
        T val = data[m];
205,965,858✔
993
        dataBuf[cnt] = val;
205,965,858✔
994

995
        if (cnt > 0)
205,965,858✔
996
        {
997
          if (val < zMin)
203,651,081✔
998
            zMin = val;
696,827✔
999
          else if (val > zMax)
202,954,350✔
1000
            zMax = val;
714,394✔
1001

1002
          if (val == prevVal)
203,651,081✔
1003
            cntSameVal++;
188,847,021✔
1004
        }
1005
        else
1006
          zMin = zMax = val;    // init
2,314,731✔
1007

1008
        prevVal = val;
205,965,858✔
1009
        cnt++;
205,965,858✔
1010
      }
1011
    }
1012
  }
1013
  else    // not all valid, use mask
1014
  {
1015
    for (int i = i0; i < i1; i++)
217✔
1016
    {
1017
      int k = i * hd.nCols + j0;
110✔
1018
      int m = k * nDim + iDim;
110✔
1019

1020
      for (int j = j0; j < j1; j++, k++, m += nDim)
930✔
1021
        if (m_bitMask.IsValid(k))
820✔
1022
        {
1023
          T val = data[m];
413✔
1024
          dataBuf[cnt] = val;
413✔
1025

1026
          if (cnt > 0)
413✔
1027
          {
1028
            if (val < zMin)
306✔
1029
              zMin = val;
×
1030
            else if (val > zMax)
306✔
1031
              zMax = val;
×
1032

1033
            if (val == prevVal)
306✔
1034
              cntSameVal++;
306✔
1035
          }
1036
          else
1037
            zMin = zMax = val;    // init
107✔
1038

1039
          prevVal = val;
413✔
1040
          cnt++;
413✔
1041
        }
1042
    }
1043
  }
1044

1045
  if (cnt > 4)
2,314,845✔
1046
    tryLut = (zMax > zMin + hd.maxZError) && (2 * cntSameVal > cnt);
2,314,701✔
1047

1048
  numValidPixel = cnt;
2,314,845✔
1049
  return true;
2,314,845✔
1050
}
1051

1052
// -------------------------------------------------------------------------- ;
1053

1054
inline double Lerc2::ComputeMaxVal(double zMin, double zMax, double maxZError)
3,559,970✔
1055
{
1056
  double fac = 1 / (2 * maxZError);    // must match the code in Decode(), don't touch it
3,559,970✔
1057
  return (zMax - zMin) * fac;
3,559,970✔
1058
}
1059

1060
// -------------------------------------------------------------------------- ;
1061

1062
template<class T>
1063
bool Lerc2::NeedToQuantize(int numValidPixel, T zMin, T zMax) const
1,093,786✔
1064
{
1065
  if (numValidPixel == 0 || m_headerInfo.maxZError == 0)
1,093,786✔
1066
    return false;
×
1067

1068
  double maxVal = ComputeMaxVal(zMin, zMax, m_headerInfo.maxZError);
1,093,786✔
1069
  return !(maxVal > m_maxValToQuantize || (unsigned int)(maxVal + 0.5) == 0);
1,093,786✔
1070
}
1071

1072
// -------------------------------------------------------------------------- ;
1073

1074
template<class T>
1075
bool Lerc2::Quantize(const T* dataBuf, int num, T zMin, std::vector<unsigned int>& quantVec) const
728,526✔
1076
{
1077
  quantVec.resize(num);
728,526✔
1078

1079
  if (m_headerInfo.dt < DT_Float && m_headerInfo.maxZError == 0.5)    // int lossless
728,526✔
1080
  {
1081
    for (int i = 0; i < num; i++)
72,097,312✔
1082
      quantVec[i] = (unsigned int)(dataBuf[i] - zMin);    // ok, as char, short get promoted to int by C++ integral promotion rule
72,097,312✔
1083
  }
1084
  else    // float and/or lossy
1085
  {
1086
    double scale = 1 / (2 * m_headerInfo.maxZError);
15,661✔
1087
    double zMinDbl = (double)zMin;
15,661✔
1088

1089
    for (int i = 0; i < num; i++)
1,062,142✔
1090
      quantVec[i] = (unsigned int)(((double)dataBuf[i] - zMinDbl) * scale + 0.5);    // ok, consistent with ComputeMaxVal(...)
1,046,482✔
1091
      //quantVec[i] = (unsigned int)((dataBuf[i] - zMin) * scale + 0.5);    // bad, not consistent with ComputeMaxVal(...)
1092
  }
1093

1094
  return true;
728,526✔
1095
}
1096

1097
// -------------------------------------------------------------------------- ;
1098

1099
template<class T>
1100
int Lerc2::NumBytesTile(int numValidPixel, T zMin, T zMax, bool tryLut, BlockEncodeMode& blockEncodeMode,
2,314,845✔
1101
                         const std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec) const
1102
{
1103
  blockEncodeMode = BEM_RawBinary;
2,314,845✔
1104

1105
  if (numValidPixel == 0 || (zMin == 0 && zMax == 0))
2,314,845✔
1106
    return 1;
376,137✔
1107

1108
  double maxVal = 0, maxZError = m_headerInfo.maxZError;
1,938,706✔
1109
  int nBytesRaw = (int)(1 + numValidPixel * sizeof(T));
1,938,706✔
1110

1111
  if ((maxZError == 0 && zMax > zMin)
596✔
1112
    || (maxZError > 0 && (maxVal = ComputeMaxVal(zMin, zMax, maxZError)) > m_maxValToQuantize))
1,939,302✔
1113
  {
1114
    return nBytesRaw;
436✔
1115
  }
1116
  else
1117
  {
1118
    DataType dtUsed;
1119
    TypeCode(zMin, dtUsed);
1,938,270✔
1120
    int nBytes = 1 + GetDataTypeSize(dtUsed);
1,938,270✔
1121

1122
    unsigned int maxElem = (unsigned int)(maxVal + 0.5);
1,938,270✔
1123
    if (maxElem > 0)
1,938,270✔
1124
    {
1125
      nBytes += (!tryLut) ? m_bitStuffer2.ComputeNumBytesNeededSimple(numValidPixel, maxElem)
1,480,163✔
1126
                          : m_bitStuffer2.ComputeNumBytesNeededLut(sortedQuantVec, tryLut);
709,569✔
1127
    }
1128

1129
    if (nBytes < nBytesRaw)
1,938,270✔
1130
      blockEncodeMode = (!tryLut || maxElem == 0) ? BEM_BitStuffSimple : BEM_BitStuffLUT;
1,918,287✔
1131
    else
1132
      nBytes = nBytesRaw;
19,980✔
1133

1134
    return nBytes;
1,938,270✔
1135
  }
1136
}
1137

1138
// -------------------------------------------------------------------------- ;
1139

1140
template<class T>
1141
bool Lerc2::WriteTile(const T* dataBuf, int num, Byte** ppByte, int& numBytesWritten, int j0, T zMin, T zMax,
629,449✔
1142
  const std::vector<unsigned int>& quantVec, BlockEncodeMode blockEncodeMode,
1143
  const std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec) const
1144
{
1145
  Byte* ptr = *ppByte;
629,449✔
1146
  Byte comprFlag = ((j0 >> 3) & 15) << 2;    // use bits 2345 for integrity check
629,449✔
1147

1148
  if (num == 0 || (zMin == 0 && zMax == 0))    // special cases
629,449✔
1149
  {
1150
    *ptr++ = comprFlag | 2;    // set compression flag to 2 to mark tile as constant 0
100,003✔
1151
    numBytesWritten = 1;
100,003✔
1152
    *ppByte = ptr;
100,003✔
1153
    return true;
100,003✔
1154
  }
1155

1156
  if (blockEncodeMode == BEM_RawBinary)
529,446✔
1157
  {
1158
    *ptr++ = comprFlag | 0;    // write z's binary uncompressed
1,369✔
1159

1160
    memcpy(ptr, dataBuf, num * sizeof(T));
1,369✔
1161
    ptr += num * sizeof(T);
1,369✔
1162
  }
1163
  else
1164
  {
1165
    double maxVal = (m_headerInfo.maxZError > 0) ? ComputeMaxVal(zMin, zMax, m_headerInfo.maxZError) : 0;
528,077✔
1166

1167
    // write z's as int arr bit stuffed
1168
    unsigned int maxElem = (unsigned int)(maxVal + 0.5);
528,077✔
1169
    if (maxElem == 0)
528,077✔
1170
      comprFlag |= 3;    // set compression flag to 3 to mark tile as constant zMin
265,252✔
1171
    else
1172
      comprFlag |= 1;    // use bit stuffing
262,825✔
1173

1174
    DataType dtUsed;
1175
    int bits67 = TypeCode(zMin, dtUsed);
528,077✔
1176
    comprFlag |= bits67 << 6;
528,077✔
1177

1178
    *ptr++ = comprFlag;
528,077✔
1179

1180
    if (!WriteVariableDataType(&ptr, (double)zMin, dtUsed))
528,077✔
1181
      return false;
×
1182

1183
    if (maxElem > 0)
528,077✔
1184
    {
1185
      if ((int)quantVec.size() != num)
262,825✔
1186
        return false;
×
1187

1188
      if (blockEncodeMode == BEM_BitStuffSimple)
262,825✔
1189
      {
1190
        if (!m_bitStuffer2.EncodeSimple(&ptr, quantVec, m_headerInfo.version))
41,909✔
1191
          return false;
×
1192
      }
1193
      else if (blockEncodeMode == BEM_BitStuffLUT)
220,916✔
1194
      {
1195
        if (!m_bitStuffer2.EncodeLut(&ptr, sortedQuantVec, m_headerInfo.version))
220,916✔
1196
          return false;
×
1197
      }
1198
      else
1199
        return false;
×
1200
    }
1201
  }
1202

1203
  numBytesWritten = (int)(ptr - *ppByte);
529,446✔
1204
  *ppByte = ptr;
529,446✔
1205
  return true;
529,446✔
1206
}
1207

1208
// -------------------------------------------------------------------------- ;
1209

1210
template<class T>
1211
bool Lerc2::ReadTile(const Byte** ppByte, size_t& nBytesRemainingInOut, T* data, int i0, int i1, int j0, int j1, int iDim,
254,023✔
1212
                     std::vector<unsigned int>& bufferVec) const
1213
{
1214
  const Byte* ptr = *ppByte;
254,023✔
1215
  size_t nBytesRemaining = nBytesRemainingInOut;
254,023✔
1216

1217
  if (nBytesRemaining < 1)
254,023✔
1218
    return false;
×
1219

1220
  Byte comprFlag = *ptr++;
254,023✔
1221
  nBytesRemaining--;
254,023✔
1222

1223
  int bits67 = comprFlag >> 6;
254,023✔
1224
  int testCode = (comprFlag >> 2) & 15;    // use bits 2345 for integrity check
254,023✔
1225
  if (testCode != ((j0 >> 3) & 15))
254,023✔
1226
    return false;
×
1227

1228
  const HeaderInfo& hd = m_headerInfo;
254,023✔
1229
  int nCols = hd.nCols;
254,023✔
1230
  int nDim = hd.nDim;
254,023✔
1231

1232
  comprFlag &= 3;
254,023✔
1233

1234
  if (comprFlag == 2)    // entire tile is constant 0 (all the valid pixels)
254,023✔
1235
  {
1236
    for (int i = i0; i < i1; i++)
494,573✔
1237
    {
1238
      int k = i * nCols + j0;
449,749✔
1239
      int m = k * nDim + iDim;
449,749✔
1240

1241
      for (int j = j0; j < j1; j++, k++, m += nDim)
5,529,660✔
1242
        if (m_bitMask.IsValid(k))
5,079,910✔
1243
          data[m] = 0;
5,079,990✔
1244
    }
1245

1246
    *ppByte = ptr;
44,824✔
1247
    nBytesRemainingInOut = nBytesRemaining;
44,824✔
1248
    return true;
44,824✔
1249
  }
1250

1251
  else if (comprFlag == 0)    // read z's binary uncompressed
209,199✔
1252
  {
1253
    const T* srcPtr = (const T*)ptr;
2,160✔
1254
    int cnt = 0;
2,160✔
1255

1256
    for (int i = i0; i < i1; i++)
18,678✔
1257
    {
1258
      int k = i * nCols + j0;
16,518✔
1259
      int m = k * nDim + iDim;
16,518✔
1260

1261
      for (int j = j0; j < j1; j++, k++, m += nDim)
146,611✔
1262
        if (m_bitMask.IsValid(k))
130,093✔
1263
        {
1264
          if (nBytesRemaining < sizeof(T))
130,096✔
1265
            return false;
3✔
1266

1267
          data[m] = *srcPtr++;
130,093✔
1268
          nBytesRemaining -= sizeof(T);
130,093✔
1269

1270
          cnt++;
130,093✔
1271
        }
1272
    }
1273

1274
    ptr += cnt * sizeof(T);
2,160✔
1275
  }
1276
  else
1277
  {
1278
    // read z's as int arr bit stuffed
1279
    DataType dtUsed = GetDataTypeUsed(bits67);
207,039✔
1280
    if( dtUsed == DT_Undefined )
207,039✔
1281
      return false;
×
1282
    size_t n = GetDataTypeSize(dtUsed);
207,039✔
1283
    if (nBytesRemaining < n)
207,039✔
1284
      return false;
×
1285

1286
    double offset = ReadVariableDataType(&ptr, dtUsed);
207,039✔
1287
    nBytesRemaining -= n;
207,038✔
1288

1289
    if (comprFlag == 3)    // entire tile is constant zMin (all the valid pixels)
207,038✔
1290
    {
1291
      for (int i = i0; i < i1; i++)
905,018✔
1292
      {
1293
        int k = i * nCols + j0;
814,328✔
1294
        int m = k * nDim + iDim;
814,328✔
1295

1296
        for (int j = j0; j < j1; j++, k++, m += nDim)
8,764,730✔
1297
          if (m_bitMask.IsValid(k))
7,950,400✔
1298
            data[m] = (T)offset;
7,950,400✔
1299
      }
1300
    }
1301
    else
1302
    {
1303
      size_t maxElementCount = (i1 - i0) * (j1 - j0);
116,348✔
1304
      if (!m_bitStuffer2.Decode(&ptr, nBytesRemaining, bufferVec, maxElementCount, hd.version))
116,348✔
1305
        return false;
×
1306

1307
      double invScale = 2 * hd.maxZError;    // for int types this is int
116,349✔
1308
      double zMax = (hd.version >= 4 && nDim > 1) ? m_zMaxVec[iDim] : hd.zMax;
116,349✔
1309
      const unsigned int* srcPtr = bufferVec.data();
116,349✔
1310

1311
      if (bufferVec.size() == maxElementCount)    // all valid
116,348✔
1312
      {
1313
        for (int i = i0; i < i1; i++)
1,060,012✔
1314
        {
1315
          int k = i * nCols + j0;
943,728✔
1316
          int m = k * nDim + iDim;
943,728✔
1317

1318
          for (int j = j0; j < j1; j++, k++, m += nDim)
8,709,816✔
1319
          {
1320
            double z = offset + *srcPtr++ * invScale;
7,766,158✔
1321
            data[m] = (T)std::min(z, zMax);    // make sure we stay in the orig range
7,766,158✔
1322
          }
1323
        }
1324
      }
1325
      else    // not all valid
1326
      {
1327
#ifndef GDAL_COMPILATION
1328
        if (hd.version > 2)
1329
        {
1330
          for (int i = i0; i < i1; i++)
1331
          {
1332
            int k = i * nCols + j0;
1333
            int m = k * nDim + iDim;
1334

1335
            for (int j = j0; j < j1; j++, k++, m += nDim)
1336
              if (m_bitMask.IsValid(k))
1337
              {
1338
                double z = offset + *srcPtr++ * invScale;
1339
                data[m] = (T)std::min(z, zMax);    // make sure we stay in the orig range
1340
              }
1341
          }
1342
        }
1343
        else  // fail gracefully in case of corrupted blob for old version <= 2 which had no checksum
1344
#endif
1345
        {
1346
          size_t bufferVecIdx = 0;
×
1347

1348
          for (int i = i0; i < i1; i++)
×
1349
          {
1350
            int k = i * nCols + j0;
×
1351
            int m = k * nDim + iDim;
×
1352

1353
            for (int j = j0; j < j1; j++, k++, m += nDim)
×
1354
              if (m_bitMask.IsValid(k))
×
1355
              {
1356
                if (bufferVecIdx == bufferVec.size())  // fail gracefully in case of corrupted blob for old version <= 2 which had no checksum
×
1357
                  return false;
×
1358

1359
                double z = offset + bufferVec[bufferVecIdx] * invScale;
×
1360
                bufferVecIdx++;
×
1361
                data[m] = (T)std::min(z, zMax);    // make sure we stay in the orig range
×
1362
              }
1363
          }
1364
        }
1365
      }
1366
    }
1367
  }
1368

1369
  *ppByte = ptr;
209,132✔
1370
  nBytesRemainingInOut = nBytesRemaining;
209,132✔
1371
  return true;
209,132✔
1372
}
1373

1374
// -------------------------------------------------------------------------- ;
1375

1376
template<class T>
1377
int Lerc2::TypeCode(T z, DataType& dtUsed) const
2,466,344✔
1378
{
1379
  Byte b = (Byte)z;
2,466,344✔
1380
  DataType dt = m_headerInfo.dt;
2,466,344✔
1381
  switch (dt)
2,466,344✔
1382
  {
1383
    case DT_Short:
48✔
1384
    {
1385
      signed char c = (signed char)z;
48✔
1386
      int tc = (T)c == z ? 2 : (T)b == z ? 1 : 0;
48✔
1387
      dtUsed = (DataType)(dt - tc);
48✔
1388
      return tc;
48✔
1389
    }
1390
    case DT_UShort:
48✔
1391
    {
1392
      int tc = (T)b == z ? 1 : 0;
48✔
1393
      dtUsed = (DataType)(dt - 2 * tc);
48✔
1394
      return tc;
48✔
1395
    }
1396
    case DT_Int:
48✔
1397
    {
1398
      short s = (short)z;
48✔
1399
      unsigned short us = (unsigned short)z;
48✔
1400
      int tc = (T)b == z ? 3 : (T)s == z ? 2 : (T)us == z ? 1 : 0;
48✔
1401
      dtUsed = (DataType)(dt - tc);
48✔
1402
      return tc;
48✔
1403
    }
1404
    case DT_UInt:
48✔
1405
    {
1406
      unsigned short us = (unsigned short)z;
48✔
1407
      int tc = (T)b == z ? 2 : (T)us == z ? 1 : 0;
48✔
1408
      dtUsed = (DataType)(dt - 2 * tc);
48✔
1409
      return tc;
48✔
1410
    }
1411
    case DT_Float:
101✔
1412
    {
1413
      short s = (short)z;
101✔
1414
      int tc = (T)b == z ? 2 : (T)s == z ? 1 : 0;
101✔
1415
      dtUsed = tc == 0 ? dt : (tc == 1 ? DT_Short : DT_Byte);
101✔
1416
      return tc;
101✔
1417
    }
1418
    case DT_Double:
122✔
1419
    {
1420
      short s = (short)z;
122✔
1421
      int l = (int)z;
122✔
1422
      float f = (float)z;
122✔
1423
      int tc = (T)s == z ? 3 : (T)l == z ? 2 : (T)f == z ? 1 : 0;
122✔
1424
      dtUsed = tc == 0 ? dt : (DataType)(dt - 2 * tc + 1);
122✔
1425
      return tc;
122✔
1426
    }
1427
    default:
2,465,929✔
1428
    {
1429
      dtUsed = dt;
2,465,929✔
1430
      return 0;
2,465,929✔
1431
    }
1432
  }
1433
}
1434

1435
// -------------------------------------------------------------------------- ;
1436

1437
inline Lerc2::DataType Lerc2::ValidateDataType(int dt)
60✔
1438
{
1439
  if( dt >= DT_Char && dt <= DT_Double )
60✔
1440
    return static_cast<DataType>(dt);
60✔
1441
  return DT_Undefined;
×
1442
}
1443

1444
// -------------------------------------------------------------------------- ;
1445

1446
inline
1447
Lerc2::DataType Lerc2::GetDataTypeUsed(int tc) const
207,039✔
1448
{
1449
  DataType dt = m_headerInfo.dt;
207,039✔
1450
  switch (dt)
207,039✔
1451
  {
1452
    case DT_Short:
26✔
1453
    case DT_Int:     return ValidateDataType(dt - tc);
26✔
1454
    case DT_UShort:
26✔
1455
    case DT_UInt:    return ValidateDataType(dt - 2 * tc);
26✔
1456
    case DT_Float:   return tc == 0 ? dt : (tc == 1 ? DT_Short : DT_Byte);
4✔
1457
    case DT_Double:  return tc == 0 ? dt : ValidateDataType(dt - 2 * tc + 1);
8✔
1458
    default:
206,975✔
1459
      return dt;
206,975✔
1460
  }
1461
}
1462

1463
// -------------------------------------------------------------------------- ;
1464

1465
inline
1466
bool Lerc2::WriteVariableDataType(Byte** ppByte, double z, DataType dtUsed)
528,077✔
1467
{
1468
  Byte* ptr = *ppByte;
528,077✔
1469

1470
  switch (dtUsed)
528,077✔
1471
  {
1472
    case DT_Char:
13✔
1473
    {
1474
      *((signed char*)ptr) = (signed char)z;
13✔
1475
      ptr++;
13✔
1476
      break;
13✔
1477
    }
1478
    case DT_Byte:
528,056✔
1479
    {
1480
      *((Byte*)ptr) = (Byte)z;
528,056✔
1481
      ptr++;
528,056✔
1482
      break;
528,056✔
1483
    }
1484
    case DT_Short:
8✔
1485
    {
1486
      short s = (short)z;
8✔
1487
      memcpy(ptr, &s, sizeof(short));
8✔
1488
      ptr += 2;
8✔
1489
      break;
8✔
1490
    }
1491
    case DT_UShort:
×
1492
    {
1493
      unsigned short us = (unsigned short)z;
×
1494
      memcpy(ptr, &us, sizeof(unsigned short));
×
1495
      ptr += 2;
×
1496
      break;
×
1497
    }
1498
    case DT_Int:
×
1499
    {
1500
      int i = (int)z;
×
1501
      memcpy(ptr, &i, sizeof(int));
×
1502
      ptr += 4;
×
1503
      break;
×
1504
    }
1505
    case DT_UInt:
×
1506
    {
1507
      unsigned int n = (unsigned int)z;
×
1508
      memcpy(ptr, &n, sizeof(unsigned int));
×
1509
      ptr += 4;
×
1510
      break;
×
1511
    }
1512
    case DT_Float:
×
1513
    {
1514
      float f = (float)z;
×
1515
      memcpy(ptr, &f, sizeof(float));
×
1516
      ptr += 4;
×
1517
      break;
×
1518
    }
1519
    case DT_Double:
×
1520
    {
1521
      memcpy(ptr, &z, sizeof(double));
×
1522
      ptr += 8;
×
1523
      break;
×
1524
    }
1525

1526
    default:
×
1527
      return false;
×
1528
  }
1529

1530
  *ppByte = ptr;
528,077✔
1531
  return true;
528,077✔
1532
}
1533

1534
// -------------------------------------------------------------------------- ;
1535

1536
inline
1537
double Lerc2::ReadVariableDataType(const Byte** ppByte, DataType dtUsed)
207,038✔
1538
{
1539
  const Byte* ptr = *ppByte;
207,038✔
1540

1541
  switch (dtUsed)
207,038✔
1542
  {
1543
    case DT_Char:
13✔
1544
    {
1545
      signed char c = *((signed char*)ptr);
13✔
1546
      *ppByte = ptr + 1;
13✔
1547
      return c;
13✔
1548
    }
1549
    case DT_Byte:
207,017✔
1550
    {
1551
      Byte b = *((Byte*)ptr);
207,017✔
1552
      *ppByte = ptr + 1;
207,017✔
1553
      return b;
207,017✔
1554
    }
1555
    case DT_Short:
8✔
1556
    {
1557
      short s;
1558
      memcpy(&s, ptr, sizeof(short));
8✔
1559
      *ppByte = ptr + 2;
8✔
1560
      return s;
8✔
1561
    }
1562
    case DT_UShort:
×
1563
    {
1564
      unsigned short us;
1565
      memcpy(&us, ptr, sizeof(unsigned short));
×
1566
      *ppByte = ptr + 2;
×
1567
      return us;
×
1568
    }
1569
    case DT_Int:
×
1570
    {
1571
      int i;
1572
      memcpy(&i, ptr, sizeof(int));
×
1573
      *ppByte = ptr + 4;
×
1574
      return i;
×
1575
    }
1576
    case DT_UInt:
×
1577
    {
1578
      unsigned int n;
1579
      memcpy(&n, ptr, sizeof(unsigned int));
×
1580
      *ppByte = ptr + 4;
×
1581
      return n;
×
1582
    }
1583
    case DT_Float:
×
1584
    {
1585
      float f;
1586
      memcpy(&f, ptr, sizeof(float));
×
1587
      *ppByte = ptr + 4;
×
1588
      return f;
×
1589
    }
1590
    case DT_Double:
×
1591
    {
1592
      double d;
1593
      memcpy(&d, ptr, sizeof(double));
×
1594
      *ppByte = ptr + 8;
×
1595
      return d;
×
1596
    }
1597
    default:
×
1598
      return 0;
×
1599
  }
1600
}
1601

1602
// -------------------------------------------------------------------------- ;
1603

1604
template<class T>
1605
Lerc2::DataType Lerc2::GetDataType(T z) const
5,181✔
1606
{
1607
  const std::type_info& ti = typeid(z);
5,181✔
1608

1609
       if (ti == typeid(signed char))     return DT_Char;
5,181✔
1610
  else if (ti == typeid(Byte))            return DT_Byte;
5,180✔
1611
  else if (ti == typeid(short))           return DT_Short;
61✔
1612
  else if (ti == typeid(unsigned short))  return DT_UShort;
59✔
1613
  else if (ti == typeid(int ) && sizeof(int ) == 4)   return DT_Int;
57✔
1614
  else if (ti == typeid(long) && sizeof(long) == 4)   return DT_Int;
55✔
1615
  else if (ti == typeid(unsigned int ) && sizeof(unsigned int ) == 4)   return DT_UInt;
55✔
1616
  else if (ti == typeid(unsigned long) && sizeof(unsigned long) == 4)   return DT_UInt;
53✔
1617
  else if (ti == typeid(float))           return DT_Float;
53✔
1618
  else if (ti == typeid(double))          return DT_Double;
26✔
1619
  else
1620
    return DT_Undefined;
×
1621
}
1622

1623
// -------------------------------------------------------------------------- ;
1624

1625
inline
1626
unsigned int Lerc2::GetMaxValToQuantize(DataType dt)
5,172✔
1627
{
1628
  switch (dt)
5,172✔
1629
  {
1630
    case DT_Char:
5,123✔
1631
    case DT_Byte:    //return (1 <<  7) - 1;    // disabled: allow LUT mode for 8 bit segmented
1632
    case DT_Short:
1633
    case DT_UShort:  return (1 << 15) - 1;
5,123✔
1634

1635
    case DT_Int:
49✔
1636
    case DT_UInt:
1637
    case DT_Float:
1638
    case DT_Double:  return (1 << 30) - 1;
49✔
1639

1640
    default:
×
1641
      return 0;
×
1642
  }
1643
}
1644

1645
// -------------------------------------------------------------------------- ;
1646

1647
inline
1648
unsigned int Lerc2::GetDataTypeSize(DataType dt)
2,145,310✔
1649
{
1650
  switch (dt)
2,145,310✔
1651
  {
1652
    case DT_Char:
2,145,110✔
1653
    case DT_Byte:   return 1;
2,145,110✔
1654
    case DT_Short:
42✔
1655
    case DT_UShort: return 2;
42✔
1656
    case DT_Int:
160✔
1657
    case DT_UInt:
1658
    case DT_Float:  return 4;
160✔
1659
    case DT_Double: return 8;
×
1660

UNCOV
1661
    default:
×
UNCOV
1662
      return 0;
×
1663
  }
1664
}
1665

1666
// -------------------------------------------------------------------------- ;
1667

1668
template<class T>
1669
void Lerc2::ComputeHuffmanCodes(const T* data, int& numBytes, ImageEncodeMode& imageEncodeMode, std::vector<std::pair<unsigned short, unsigned int> >& codes) const
3,327✔
1670
{
1671
  std::vector<int> histo, deltaHisto;
6,654✔
1672
  ComputeHistoForHuffman(data, histo, deltaHisto);
3,327✔
1673

1674
  int nBytes0 = 0, nBytes1 = 0;
3,327✔
1675
  double avgBpp0 = 0, avgBpp1 = 0;
3,327✔
1676
  Huffman huffman0, huffman1;
6,654✔
1677

1678
  if (m_headerInfo.version >= 4)
3,327✔
1679
  {
1680
    if (!huffman0.ComputeCodes(histo) || !huffman0.ComputeCompressedSize(histo, nBytes0, avgBpp0))
204✔
1681
      nBytes0 = 0;
×
1682
  }
1683

1684
  if (!huffman1.ComputeCodes(deltaHisto) || !huffman1.ComputeCompressedSize(deltaHisto, nBytes1, avgBpp1))
3,327✔
1685
    nBytes1 = 0;
×
1686

1687
  if (nBytes0 > 0 && nBytes1 > 0)    // regular case, pick the better of the two
3,327✔
1688
  {
1689
    imageEncodeMode = (nBytes0 <= nBytes1) ? IEM_Huffman : IEM_DeltaHuffman;
204✔
1690
    codes = (nBytes0 <= nBytes1) ? huffman0.GetCodes() : huffman1.GetCodes();
204✔
1691
    numBytes = (std::min)(nBytes0, nBytes1);
204✔
1692
  }
1693
  else if (nBytes0 == 0 && nBytes1 == 0)    // rare case huffman cannot handle, fall back to tiling
3,123✔
1694
  {
1695
    imageEncodeMode = IEM_Tiling;
×
1696
    codes.resize(0);
×
1697
    numBytes = 0;
×
1698
  }
1699
  else    // rare also, pick the valid one, the other is 0
1700
  {
1701
    imageEncodeMode = (nBytes0 > nBytes1) ? IEM_Huffman : IEM_DeltaHuffman;
3,123✔
1702
    codes = (nBytes0 > nBytes1) ? huffman0.GetCodes() : huffman1.GetCodes();
3,123✔
1703
    numBytes = (std::max)(nBytes0, nBytes1);
3,123✔
1704
  }
1705
}
3,327✔
1706

1707
// -------------------------------------------------------------------------- ;
1708

1709
template<class T>
1710
void Lerc2::ComputeHistoForHuffman(const T* data, std::vector<int>& histo, std::vector<int>& deltaHisto) const
3,327✔
1711
{
1712
  histo.resize(256);
3,327✔
1713
  deltaHisto.resize(256);
3,327✔
1714

1715
  memset(&histo[0], 0, histo.size() * sizeof(int));
3,327✔
1716
  memset(&deltaHisto[0], 0, deltaHisto.size() * sizeof(int));
3,327✔
1717

1718
  int offset = (m_headerInfo.dt == DT_Char) ? 128 : 0;
3,327✔
1719
  int height = m_headerInfo.nRows;
3,327✔
1720
  int width = m_headerInfo.nCols;
3,327✔
1721
  int nDim = m_headerInfo.nDim;
3,327✔
1722

1723
  if (m_headerInfo.numValidPixel == width * height)    // all valid
3,327✔
1724
  {
1725
    for (int iDim = 0; iDim < nDim; iDim++)
6,718✔
1726
    {
1727
      T prevVal = 0;
3,391✔
1728
      for (int m = iDim, i = 0; i < height; i++)
423,843✔
1729
        for (int j = 0; j < width; j++, m += nDim)
59,179,520✔
1730
        {
1731
          T val = data[m];
58,759,100✔
1732
          T delta = val;
58,759,100✔
1733

1734
          if (j > 0)
58,759,100✔
1735
            delta -= prevVal;    // use overflow
58,338,680✔
1736
          else if (i > 0)
420,452✔
1737
            delta -= data[m - width * nDim];
417,061✔
1738
          else
1739
            delta -= prevVal;
3,391✔
1740

1741
          prevVal = val;
58,759,100✔
1742

1743
          histo[offset + (int)val]++;
58,759,100✔
1744
          deltaHisto[offset + (int)delta]++;
58,759,100✔
1745
        }
1746
    }
1747
  }
1748
  else    // not all valid
1749
  {
1750
    for (int iDim = 0; iDim < nDim; iDim++)
×
1751
    {
1752
      T prevVal = 0;
×
1753
      for (int k = 0, m = iDim, i = 0; i < height; i++)
×
1754
        for (int j = 0; j < width; j++, k++, m += nDim)
×
1755
          if (m_bitMask.IsValid(k))
×
1756
          {
1757
            T val = data[m];
×
1758
            T delta = val;
×
1759

1760
            if (j > 0 && m_bitMask.IsValid(k - 1))
×
1761
            {
1762
              delta -= prevVal;    // use overflow
×
1763
            }
1764
            else if (i > 0 && m_bitMask.IsValid(k - width))
×
1765
            {
1766
              delta -= data[m - width * nDim];
×
1767
            }
1768
            else
1769
              delta -= prevVal;
×
1770

1771
            prevVal = val;
×
1772

1773
            histo[offset + (int)val]++;
×
1774
            deltaHisto[offset + (int)delta]++;
×
1775
          }
1776
    }
1777
  }
1778
}
3,327✔
1779

1780
// -------------------------------------------------------------------------- ;
1781

1782
template<class T>
1783
bool Lerc2::EncodeHuffman(const T* data, Byte** ppByte) const
640✔
1784
{
1785
  if (!data || !ppByte)
640✔
1786
    return false;
×
1787

1788
  Huffman huffman;
1,280✔
1789
  if (!huffman.SetCodes(m_huffmanCodes) || !huffman.WriteCodeTable(ppByte, m_headerInfo.version))    // header and code table
640✔
1790
    return false;
×
1791

1792
  int offset = (m_headerInfo.dt == DT_Char) ? 128 : 0;
640✔
1793
  int height = m_headerInfo.nRows;
640✔
1794
  int width = m_headerInfo.nCols;
640✔
1795
  int nDim = m_headerInfo.nDim;
640✔
1796

1797
  unsigned int* arr = (unsigned int*)(*ppByte);
640✔
1798
  unsigned int* dstPtr = arr;
640✔
1799
  int bitPos = 0;
640✔
1800

1801
  if (m_imageEncodeMode == IEM_DeltaHuffman)
640✔
1802
  {
1803
    for (int iDim = 0; iDim < nDim; iDim++)
1,039✔
1804
    {
1805
      T prevVal = 0;
534✔
1806
      for (int k = 0, m = iDim, i = 0; i < height; i++)
62,570✔
1807
        for (int j = 0; j < width; j++, k++, m += nDim)
8,220,390✔
1808
          if (m_bitMask.IsValid(k))
8,158,350✔
1809
          {
1810
            T val = data[m];
8,158,350✔
1811
            T delta = val;
8,158,350✔
1812

1813
            if (j > 0 && m_bitMask.IsValid(k - 1))
8,158,350✔
1814
            {
1815
              delta -= prevVal;    // use overflow
8,096,320✔
1816
            }
1817
            else if (i > 0 && m_bitMask.IsValid(k - width))
62,036✔
1818
            {
1819
              delta -= data[m - width * nDim];
61,502✔
1820
            }
1821
            else
1822
              delta -= prevVal;
534✔
1823

1824
            prevVal = val;
8,158,350✔
1825

1826
            // bit stuff the huffman code for this delta
1827
            int kBin = offset + (int)delta;
8,158,350✔
1828
            int len = m_huffmanCodes[kBin].first;
8,158,350✔
1829
            if (len <= 0)
8,158,350✔
1830
              return false;
×
1831

1832
            unsigned int code = m_huffmanCodes[kBin].second;
8,158,350✔
1833

1834
            if (32 - bitPos >= len)
8,169,150✔
1835
            {
1836
              if (bitPos == 0)
8,051,220✔
1837
                *dstPtr = 0;
254,851✔
1838

1839
              *dstPtr |= code << (32 - bitPos - len);
8,051,220✔
1840
              bitPos += len;
8,051,220✔
1841
              if (bitPos == 32)
8,051,220✔
1842
              {
1843
                bitPos = 0;
254,357✔
1844
                dstPtr++;
254,357✔
1845
              }
1846
            }
1847
            else
1848
            {
1849
              bitPos += len - 32;
117,934✔
1850
              *dstPtr++ |= code >> bitPos;
117,934✔
1851
              *dstPtr = code << (32 - bitPos);
117,934✔
1852
            }
1853
          }
1854
    }
1855
  }
1856

1857
  else if (m_imageEncodeMode == IEM_Huffman)
135✔
1858
  {
1859
    for (int k = 0, m0 = 0, i = 0; i < height; i++)
5,583✔
1860
      for (int j = 0; j < width; j++, k++, m0 += nDim)
1,155,140✔
1861
        if (m_bitMask.IsValid(k))
1,149,700✔
1862
          for (int m = 0; m < nDim; m++)
2,299,390✔
1863
          {
1864
            T val = data[m0 + m];
1,149,700✔
1865

1866
            // bit stuff the huffman code for this val
1867
            int kBin = offset + (int)val;
1,149,700✔
1868
            int len = m_huffmanCodes[kBin].first;
1,149,700✔
1869
            if (len <= 0)
1,149,700✔
1870
              return false;
×
1871

1872
            unsigned int code = m_huffmanCodes[kBin].second;
1,149,700✔
1873

1874
            if (32 - bitPos >= len)
1,149,700✔
1875
            {
1876
              if (bitPos == 0)
1,013,540✔
1877
                *dstPtr = 0;
36,755✔
1878

1879
              *dstPtr |= code << (32 - bitPos - len);
1,013,540✔
1880
              bitPos += len;
1,013,540✔
1881
              if (bitPos == 32)
1,013,540✔
1882
              {
1883
                bitPos = 0;
36,620✔
1884
                dstPtr++;
36,620✔
1885
              }
1886
            }
1887
            else
1888
            {
1889
              bitPos += len - 32;
136,154✔
1890
              *dstPtr++ |= code >> bitPos;
136,154✔
1891
              *dstPtr = code << (32 - bitPos);
136,154✔
1892
            }
1893
          }
1894
  }
1895

1896
  else
1897
    return false;
×
1898

1899
  size_t numUInts = dstPtr - arr + (bitPos > 0 ? 1 : 0) + 1;    // add one more as the decode LUT can read ahead
640✔
1900
  *ppByte += numUInts * sizeof(unsigned int);
640✔
1901
  return true;
640✔
1902
}
1903

1904
// -------------------------------------------------------------------------- ;
1905

1906
template<class T>
1907
bool Lerc2::DecodeHuffman(const Byte** ppByte, size_t& nBytesRemainingInOut, T* data) const
513✔
1908
{
1909
  if (!data || !ppByte || !(*ppByte))
513✔
1910
    return false;
×
1911

1912
  Huffman huffman;
1,373✔
1913
  if (!huffman.ReadCodeTable(ppByte, nBytesRemainingInOut, m_headerInfo.version))    // header and code table
513✔
1914
    return false;
×
1915

1916
  int numBitsLUT = 0;
513✔
1917
  if (!huffman.BuildTreeFromCodes(numBitsLUT))
513✔
1918
    return false;
×
1919

1920
  int offset = (m_headerInfo.dt == DT_Char) ? 128 : 0;
513✔
1921
  int height = m_headerInfo.nRows;
513✔
1922
  int width = m_headerInfo.nCols;
513✔
1923
  int nDim = m_headerInfo.nDim;
513✔
1924

1925
  const unsigned int* arr = (const unsigned int*)(*ppByte);
513✔
1926
  const unsigned int* srcPtr = arr;
513✔
1927
  int bitPos = 0;
513✔
1928
  size_t nBytesRemaining = nBytesRemainingInOut;
513✔
1929

1930
  if (m_headerInfo.numValidPixel == width * height)    // all valid
513✔
1931
  {
1932
    if (m_imageEncodeMode == IEM_DeltaHuffman)
513✔
1933
    {
1934
      for (int iDim = 0; iDim < nDim; iDim++)
763✔
1935
      {
1936
        T prevVal = 0;
487✔
1937
        for (int m = iDim, i = 0; i < height; i++)
29,403✔
1938
          for (int j = 0; j < width; j++, m += nDim)
3,238,860✔
1939
          {
1940
            int val = 0;
3,209,940✔
1941
            if (nBytesRemaining >= 4 * sizeof(unsigned int))
3,209,940✔
1942
            {
1943
              if (!huffman.DecodeOneValue_NoOverrunCheck(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
3,201,200✔
1944
                return false;
347✔
1945
            }
1946
            else
1947
            {
1948
              if (!huffman.DecodeOneValue(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
8,741✔
1949
                return false;
347✔
1950
            }
1951

1952
            T delta = (T)(val - offset);
3,209,940✔
1953

1954
            if (j > 0)
3,209,940✔
1955
              delta += prevVal;    // use overflow
3,181,530✔
1956
            else if (i > 0)
28,409✔
1957
              delta += data[m - width * nDim];
28,431✔
1958
            else
1959
              delta += prevVal;
×
1960

1961
            data[m] = delta;
3,209,940✔
1962
            prevVal = delta;
3,209,940✔
1963
          }
1964
      }
1965
    }
1966

1967
    else if (m_imageEncodeMode == IEM_Huffman)
237✔
1968
    {
1969
      for (int k = 0, m0 = 0, i = 0; i < height; i++)
9,315✔
1970
        for (int j = 0; j < width; j++, k++, m0 += nDim)
1,659,020✔
1971
          for (int m = 0; m < nDim; m++)
3,327,530✔
1972
          {
1973
            int val = 0;
1,677,590✔
1974
            if (nBytesRemaining >= 4 * sizeof(unsigned int))
1,677,590✔
1975
            {
1976
              if (!huffman.DecodeOneValue_NoOverrunCheck(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
1,674,305✔
1977
                return false;
×
1978
            }
1979
            else
1980
            {
1981
              if (!huffman.DecodeOneValue(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
3,284✔
1982
                return false;
×
1983
            }
1984

1985
            data[m0 + m] = (T)(val - offset);
1,677,590✔
1986
          }
1987
    }
1988

1989
    else
1990
      return false;
×
1991
  }
1992

1993
  else    // not all valid
1994
  {
1995
    if (m_imageEncodeMode == IEM_DeltaHuffman)
×
1996
    {
1997
      for (int iDim = 0; iDim < nDim; iDim++)
×
1998
      {
1999
        T prevVal = 0;
×
2000
        for (int k = 0, m = iDim, i = 0; i < height; i++)
×
2001
          for (int j = 0; j < width; j++, k++, m += nDim)
×
2002
            if (m_bitMask.IsValid(k))
×
2003
            {
2004
              int val = 0;
×
2005
              if (nBytesRemaining >= 4 * sizeof(unsigned int))
×
2006
              {
2007
                if (!huffman.DecodeOneValue_NoOverrunCheck(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
×
2008
                  return false;
×
2009
              }
2010
              else
2011
              {
2012
                if (!huffman.DecodeOneValue(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
×
2013
                  return false;
×
2014
              }
2015

2016
              T delta = (T)(val - offset);
×
2017

2018
              if (j > 0 && m_bitMask.IsValid(k - 1))
×
2019
              {
2020
                delta += prevVal;    // use overflow
×
2021
              }
2022
              else if (i > 0 && m_bitMask.IsValid(k - width))
×
2023
              {
2024
                delta += data[m - width * nDim];
×
2025
              }
2026
              else
2027
                delta += prevVal;
×
2028

2029
              data[m] = delta;
×
2030
              prevVal = delta;
×
2031
            }
2032
      }
2033
    }
2034

2035
    else if (m_imageEncodeMode == IEM_Huffman)
×
2036
    {
2037
      for (int k = 0, m0 = 0, i = 0; i < height; i++)
×
2038
        for (int j = 0; j < width; j++, k++, m0 += nDim)
×
2039
          if (m_bitMask.IsValid(k))
×
2040
            for (int m = 0; m < nDim; m++)
×
2041
            {
2042
              int val = 0;
×
2043
              if (nBytesRemaining >= 4 * sizeof(unsigned int))
×
2044
              {
2045
                if (!huffman.DecodeOneValue_NoOverrunCheck(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
×
2046
                  return false;
×
2047
              }
2048
              else
2049
              {
2050
                if (!huffman.DecodeOneValue(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
×
2051
                  return false;
×
2052
              }
2053

2054
              data[m0 + m] = (T)(val - offset);
×
2055
            }
2056
    }
2057

2058
    else
2059
      return false;
×
2060
  }
2061

2062
  size_t numUInts = srcPtr - arr + (bitPos > 0 ? 1 : 0) + 1;    // add one more as the decode LUT can read ahead
513✔
2063
  size_t len = numUInts * sizeof(unsigned int);
513✔
2064

2065
  if (nBytesRemainingInOut < len)
513✔
2066
    return false;
×
2067

2068
  *ppByte += len;
513✔
2069
  nBytesRemainingInOut -= len;
513✔
2070
  return true;
513✔
2071
}
2072

2073
// -------------------------------------------------------------------------- ;
2074

2075
template<class T>
2076
bool Lerc2::WriteMinMaxRanges(const T* /*data*/, Byte** ppByte) const
342✔
2077
{
2078
  if (!ppByte || !(*ppByte))
342✔
2079
    return false;
×
2080

2081
  //printf("write min / max = %f  %f\n", m_zMinVec[0], m_zMaxVec[0]);
2082

2083
  int nDim = m_headerInfo.nDim;
342✔
2084
  if (/* nDim < 2 || */ (int)m_zMinVec.size() != nDim || (int)m_zMaxVec.size() != nDim)
342✔
2085
    return false;
×
2086

2087
  std::vector<T> zVec(nDim);
342✔
2088
  size_t len = nDim * sizeof(T);
342✔
2089

2090
  for (int i = 0; i < nDim; i++)
754✔
2091
    zVec[i] = (T)m_zMinVec[i];
412✔
2092

2093
  memcpy(*ppByte, &zVec[0], len);
342✔
2094
  (*ppByte) += len;
342✔
2095

2096
  for (int i = 0; i < nDim; i++)
754✔
2097
    zVec[i] = (T)m_zMaxVec[i];
412✔
2098

2099
  memcpy(*ppByte, &zVec[0], len);
342✔
2100
  (*ppByte) += len;
342✔
2101

2102
  return true;
342✔
2103
}
2104

2105
// -------------------------------------------------------------------------- ;
2106

2107
template<class T>
2108
bool Lerc2::ReadMinMaxRanges(const Byte** ppByte, size_t& nBytesRemaining, const T* /*data*/)
987✔
2109
{
2110
  if (!ppByte || !(*ppByte))
987✔
UNCOV
2111
    return false;
×
2112

2113
  int nDim = m_headerInfo.nDim;
987✔
2114

2115
  m_zMinVec.resize(nDim);
987✔
2116
  m_zMaxVec.resize(nDim);
987✔
2117

2118
  std::vector<T> zVec(nDim);
1,974✔
2119
  size_t len = nDim * sizeof(T);
987✔
2120

2121
  if (nBytesRemaining < len || !memcpy(&zVec[0], *ppByte, len))
987✔
2122
    return false;
×
2123

2124
  (*ppByte) += len;
987✔
2125
  nBytesRemaining -= len;
987✔
2126

2127
  for (int i = 0; i < nDim; i++)
2,538✔
2128
    m_zMinVec[i] = zVec[i];
1,551✔
2129

2130
  if (nBytesRemaining < len || !memcpy(&zVec[0], *ppByte, len))
987✔
2131
    return false;
×
2132

2133
  (*ppByte) += len;
987✔
2134
  nBytesRemaining -= len;
987✔
2135

2136
  for (int i = 0; i < nDim; i++)
2,538✔
2137
    m_zMaxVec[i] = zVec[i];
1,551✔
2138

2139
  //printf("read min / max = %f  %f\n", m_zMinVec[0], m_zMaxVec[0]);
2140

2141
  return true;
987✔
2142
}
2143

2144
// -------------------------------------------------------------------------- ;
2145

2146
inline
2147
bool Lerc2::CheckMinMaxRanges(bool& minMaxEqual) const
1,671✔
2148
{
2149
  int nDim = m_headerInfo.nDim;
1,671✔
2150
  if ((int)m_zMinVec.size() != nDim || (int)m_zMaxVec.size() != nDim)
1,671✔
2151
    return false;
×
2152

2153
  minMaxEqual = (0 == memcmp(&m_zMinVec[0], &m_zMaxVec[0], nDim * sizeof(m_zMinVec[0])));
1,671✔
2154
  return true;
1,671✔
2155
}
2156

2157
// -------------------------------------------------------------------------- ;
2158

2159
template<class T>
2160
bool Lerc2::FillConstImage(T* data) const
576✔
2161
{
2162
  if (!data)
576✔
2163
    return false;
×
2164

2165
  const HeaderInfo& hd = m_headerInfo;
576✔
2166
  int nCols = hd.nCols;
576✔
2167
  int nRows = hd.nRows;
576✔
2168
  int nDim = hd.nDim;
576✔
2169
  T z0 = (T)hd.zMin;
576✔
2170

2171
  if (nDim == 1)
576✔
2172
  {
2173
    for (int k = 0, i = 0; i < nRows; i++)
72,143✔
2174
      for (int j = 0; j < nCols; j++, k++)
9,231,438✔
2175
        if (m_bitMask.IsValid(k))
9,159,872✔
2176
          data[k] = z0;
9,159,468✔
2177
  }
2178
  else
2179
  {
2180
    std::vector<T> zBufVec(nDim, z0);
1✔
2181

2182
    if (hd.zMin != hd.zMax)
1✔
2183
    {
2184
      if ((int)m_zMinVec.size() != nDim)
×
2185
        return false;
×
2186

2187
      for (int m = 0; m < nDim; m++)
×
2188
        zBufVec[m] = (T)m_zMinVec[m];
×
2189
    }
2190

2191
    int len = nDim * sizeof(T);
1✔
2192
    for (int k = 0, m = 0, i = 0; i < nRows; i++)
3✔
2193
      for (int j = 0; j < nCols; j++, k++, m += nDim)
6✔
2194
        if (m_bitMask.IsValid(k))
4✔
2195
          memcpy(&data[m], &zBufVec[0], len);
3✔
2196
  }
2197

2198
  return true;
576✔
2199
}
2200

2201
// -------------------------------------------------------------------------- ;
2202

2203
NAMESPACE_LERC_END
2204
#endif
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