Coverage Report

Created: 2026-09-06 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/lerc/src/LercLib/Lerc.cpp
Line
Count
Source
1
/*
2
Copyright 2015 - 2026 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
#include "Defines.h"
25
#include "Lerc.h"
26
#include "Lerc2.h"
27
#include <cstring>
28
#include <functional>
29
#include <limits>
30
#include <typeinfo>
31
32
#ifdef HAVE_LERC1_DECODE
33
  #include "Lerc1Decode/CntZImage.h"
34
#endif
35
36
using namespace std;
37
USING_NAMESPACE_LERC
38
39
// -------------------------------------------------------------------------- ;
40
41
ErrCode Lerc::ComputeCompressedSize(const void* pData, int version, DataType dt, int nDepth, int nCols, int nRows, int nBands,
42
  int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded, const unsigned char* pUsesNoData, const double* noDataValues)
43
0
{
44
0
#define LERC_ARG_1 version, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded, pUsesNoData, noDataValues
45
46
0
  switch (dt)
47
0
  {
48
0
  case DT_Char:    return ComputeCompressedSizeTempl((const signed char*)pData, LERC_ARG_1);
49
0
  case DT_Byte:    return ComputeCompressedSizeTempl((const Byte*)pData, LERC_ARG_1);
50
0
  case DT_Short:   return ComputeCompressedSizeTempl((const short*)pData, LERC_ARG_1);
51
0
  case DT_UShort:  return ComputeCompressedSizeTempl((const unsigned short*)pData, LERC_ARG_1);
52
0
  case DT_Int:     return ComputeCompressedSizeTempl((const int*)pData, LERC_ARG_1);
53
0
  case DT_UInt:    return ComputeCompressedSizeTempl((const unsigned int*)pData, LERC_ARG_1);
54
0
  case DT_Float:   return ComputeCompressedSizeTempl((const float*)pData, LERC_ARG_1);
55
0
  case DT_Double:  return ComputeCompressedSizeTempl((const double*)pData, LERC_ARG_1);
56
57
0
  default:
58
0
    return ErrCode::WrongParam;
59
0
  }
60
61
0
#undef LERC_ARG_1
62
0
}
63
64
// -------------------------------------------------------------------------- ;
65
66
ErrCode Lerc::Encode(const void* pData, int version, DataType dt, int nDepth, int nCols, int nRows, int nBands,
67
  int nMasks, const Byte* pValidBytes, double maxZErr, Byte* pBuffer, unsigned int numBytesBuffer,
68
  unsigned int& numBytesWritten, const unsigned char* pUsesNoData, const double* noDataValues)
69
0
{
70
0
#define LERC_ARG_2 version, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten, pUsesNoData, noDataValues
71
72
0
  switch (dt)
73
0
  {
74
0
  case DT_Char:    return EncodeTempl((const signed char*)pData, LERC_ARG_2);
75
0
  case DT_Byte:    return EncodeTempl((const Byte*)pData, LERC_ARG_2);
76
0
  case DT_Short:   return EncodeTempl((const short*)pData, LERC_ARG_2);
77
0
  case DT_UShort:  return EncodeTempl((const unsigned short*)pData, LERC_ARG_2);
78
0
  case DT_Int:     return EncodeTempl((const int*)pData, LERC_ARG_2);
79
0
  case DT_UInt:    return EncodeTempl((const unsigned int*)pData, LERC_ARG_2);
80
0
  case DT_Float:   return EncodeTempl((const float*)pData, LERC_ARG_2);
81
0
  case DT_Double:  return EncodeTempl((const double*)pData, LERC_ARG_2);
82
83
0
  default:
84
0
    return ErrCode::WrongParam;
85
0
  }
86
87
0
#undef LERC_ARG_2
88
0
}
89
90
// -------------------------------------------------------------------------- ;
91
92
ErrCode Lerc::GetLercInfo(const Byte* pLercBlob, unsigned int numBytesBlob, struct LercInfo& lercInfo, double* pMins, double* pMaxs, size_t nElem)
93
9
{
94
9
  lercInfo.RawInit();
95
96
  // first try Lerc2
97
9
  struct Lerc2::HeaderInfo lerc2Info;
98
9
  bool bHasMask = false;
99
9
  int nMasks = 0;
100
101
9
  if (Lerc2::GetHeaderInfo(pLercBlob, numBytesBlob, lerc2Info, bHasMask))
102
0
  {
103
0
    if (lerc2Info.blobSize < 0)
104
0
      return ErrCode::Failed;
105
106
0
    lercInfo.version = lerc2Info.version;
107
0
    lercInfo.nDepth = lerc2Info.nDepth;
108
0
    lercInfo.nCols = lerc2Info.nCols;
109
0
    lercInfo.nRows = lerc2Info.nRows;
110
0
    lercInfo.numValidPixel = lerc2Info.numValidPixel;    // for 1st band
111
0
    lercInfo.blobSize = (unsigned int)lerc2Info.blobSize;  // blob size per band is in [0 .. 2 GB]
112
0
    lercInfo.dt = (DataType)lerc2Info.dt;
113
0
    lercInfo.zMin = lerc2Info.zMin;
114
0
    lercInfo.zMax = lerc2Info.zMax;
115
0
    lercInfo.maxZError = lerc2Info.maxZError;
116
0
    lercInfo.nUsesNoDataValue = lerc2Info.bPassNoDataValues ? 1 : 0;
117
118
0
    bool bTryNextBlob = (lerc2Info.version <= 5) || (lerc2Info.nBlobsMore > 0);
119
120
0
    if (bHasMask || lercInfo.numValidPixel == 0)
121
0
      nMasks = 1;
122
123
0
    if (pMins && pMaxs)
124
0
    {
125
0
      ErrCode errCode = GetRanges(pLercBlob, numBytesBlob, 0, lerc2Info, pMins, pMaxs, nElem);    // band 0
126
0
      if (errCode != ErrCode::Ok)
127
0
        return errCode;
128
0
    }
129
130
0
    lercInfo.nBands = 1;
131
132
0
    if (lercInfo.blobSize > numBytesBlob)    // truncated blob, we won't be able to read this band
133
0
      return ErrCode::Failed;
134
135
0
    struct Lerc2::HeaderInfo hdInfo;
136
0
    while (bTryNextBlob && Lerc2::GetHeaderInfo(pLercBlob + lercInfo.blobSize, numBytesBlob - lercInfo.blobSize, hdInfo, bHasMask))
137
0
    {
138
0
      if (hdInfo.nDepth != lercInfo.nDepth
139
0
        || hdInfo.nCols != lercInfo.nCols
140
0
        || hdInfo.nRows != lercInfo.nRows
141
0
        || (int)hdInfo.dt != (int)lercInfo.dt
142
0
        || hdInfo.blobSize < 0)
143
0
      {
144
0
        return ErrCode::Failed;
145
0
      }
146
147
0
      bTryNextBlob = (hdInfo.version <= 5) || (hdInfo.nBlobsMore > 0);
148
149
0
      if (hdInfo.bPassNoDataValues)
150
0
        lercInfo.nUsesNoDataValue++;
151
152
0
      if (bHasMask || hdInfo.numValidPixel != lercInfo.numValidPixel)    // support mask per band
153
0
        nMasks = 2;
154
155
0
      if ((size_t)lercInfo.blobSize > (size_t)UINT_MAX - hdInfo.blobSize)    // guard against overflow
156
0
        return ErrCode::Failed;
157
158
0
      if ((size_t)lercInfo.blobSize + hdInfo.blobSize > (size_t)numBytesBlob)    // truncated blob, we won't be able to read this band
159
0
        return ErrCode::Failed;
160
161
0
      lercInfo.zMin = min(lercInfo.zMin, hdInfo.zMin);
162
0
      lercInfo.zMax = max(lercInfo.zMax, hdInfo.zMax);
163
0
      lercInfo.maxZError = max(lercInfo.maxZError, hdInfo.maxZError);  // with the new bitplane compression, maxZError can vary between bands
164
165
0
      if (pMins && pMaxs)
166
0
      {
167
0
        ErrCode errCode = GetRanges(pLercBlob + lercInfo.blobSize, numBytesBlob - lercInfo.blobSize, lercInfo.nBands, hdInfo, pMins, pMaxs, nElem);
168
0
        if (errCode != ErrCode::Ok)
169
0
          return errCode;
170
0
      }
171
172
0
      lercInfo.blobSize += hdInfo.blobSize;
173
0
      lercInfo.nBands++;
174
0
    }
175
176
0
    lercInfo.nMasks = nMasks > 1 ? lercInfo.nBands : nMasks;
177
    
178
0
    if (lercInfo.nUsesNoDataValue > 0)
179
0
      lercInfo.nUsesNoDataValue = lercInfo.nBands;    // if there is any noData used in any band, allow for different noData per band
180
181
0
    return ErrCode::Ok;
182
0
  }
183
184
185
9
#ifdef HAVE_LERC1_DECODE
186
  // only if not Lerc2, try legacy Lerc1
187
9
  unsigned int numBytesHeaderBand0 = CntZImage::computeNumBytesNeededToReadHeader(false);
188
9
  unsigned int numBytesHeaderBand1 = CntZImage::computeNumBytesNeededToReadHeader(true);
189
9
  const Byte* pByte = pLercBlob;
190
191
9
  lercInfo.zMin =  FLT_MAX;
192
9
  lercInfo.zMax = -FLT_MAX;
193
194
9
  CntZImage cntZImg;
195
9
  if (numBytesHeaderBand0 <= numBytesBlob && cntZImg.read(&pByte, pLercBlob + numBytesBlob, 1e12, true))    // read just the header
196
0
  {
197
0
    size_t nBytesRead = pByte - pLercBlob;
198
0
    size_t nBytesNeeded = 10 + 4 * sizeof(int) + 1 * sizeof(double);
199
200
0
    if (nBytesRead < nBytesNeeded)
201
0
      return ErrCode::Failed;
202
203
0
    const Byte* ptr = pLercBlob;
204
0
    ptr += 10 + 2 * sizeof(int);
205
206
0
    int height(0), width(0);
207
0
    memcpy(&height, ptr, sizeof(int));  ptr += sizeof(int);
208
0
    memcpy(&width,  ptr, sizeof(int));  ptr += sizeof(int);
209
0
    double maxZErrorInFile(0);
210
0
    memcpy(&maxZErrorInFile, ptr, sizeof(double));
211
212
0
    if (height < 0 || width < 0 || height > 40000 || width > 40000)  // guard against bogus numbers; size limitation for old Lerc1
213
0
      return ErrCode::Failed;
214
215
0
    if (sizeof(CntZ) * height * width > (size_t)INT_MAX)
216
0
      return ErrCode::Failed;
217
218
0
    lercInfo.nDepth = 1;
219
0
    lercInfo.nCols = width;
220
0
    lercInfo.nRows = height;
221
0
    lercInfo.dt = Lerc::DT_Float;
222
0
    lercInfo.maxZError = maxZErrorInFile;
223
224
0
    pByte = pLercBlob;
225
0
    bool onlyZPart = false;
226
227
0
    while (lercInfo.blobSize + numBytesHeaderBand1 < numBytesBlob)    // means there could be another band
228
0
    {
229
0
      if (!cntZImg.read(&pByte, pLercBlob + numBytesBlob, 1e12, false, onlyZPart))
230
0
        return (lercInfo.nBands > 0) ? ErrCode::Ok : ErrCode::Failed;    // no other band, we are done
231
232
0
      onlyZPart = true;
233
0
      lercInfo.blobSize = (int)(pByte - pLercBlob);
234
235
      // now that we have decoded it, we can go the extra mile and collect some extra info
236
0
      int numValidPixels = 0;
237
0
      float zMin =  FLT_MAX;
238
0
      float zMax = -FLT_MAX;
239
240
0
      for (int i = 0; i < height; i++)
241
0
      {
242
0
        for (int j = 0; j < width; j++)
243
0
          if (cntZImg(i, j).cnt > 0)
244
0
          {
245
0
            numValidPixels++;
246
0
            float z = cntZImg(i, j).z;
247
0
            zMax = max(zMax, z);
248
0
            zMin = min(zMin, z);
249
0
          }
250
0
      }
251
252
0
      lercInfo.numValidPixel = numValidPixels;
253
0
      lercInfo.zMin = std::min(lercInfo.zMin, (double)zMin);
254
0
      lercInfo.zMax = std::max(lercInfo.zMax, (double)zMax);
255
0
      lercInfo.nMasks = numValidPixels < width * height ? 1 : 0;
256
257
0
      if (pMins && pMaxs)
258
0
      {
259
0
        pMins[lercInfo.nBands] = zMin;
260
0
        pMaxs[lercInfo.nBands] = zMax;
261
0
      }
262
263
0
      lercInfo.nBands++;
264
0
    }
265
266
0
    return ErrCode::Ok;
267
0
  }
268
9
#endif
269
270
9
  return ErrCode::Failed;
271
9
}
272
273
// -------------------------------------------------------------------------- ;
274
275
ErrCode Lerc::Decode(const Byte* pLercBlob, unsigned int numBytesBlob, int nMasks, Byte* pValidBytes,
276
  int nDepth, int nCols, int nRows, int nBands, DataType dt, void* pData, unsigned char* pUsesNoData, double* noDataValues)
277
0
{
278
0
#define LERC_ARG_3 pLercBlob, numBytesBlob, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, pUsesNoData, noDataValues
279
280
0
  switch (dt)
281
0
  {
282
0
  case DT_Char:    return DecodeTempl((signed char*)pData, LERC_ARG_3);
283
0
  case DT_Byte:    return DecodeTempl((Byte*)pData, LERC_ARG_3);
284
0
  case DT_Short:   return DecodeTempl((short*)pData, LERC_ARG_3);
285
0
  case DT_UShort:  return DecodeTempl((unsigned short*)pData, LERC_ARG_3);
286
0
  case DT_Int:     return DecodeTempl((int*)pData, LERC_ARG_3);
287
0
  case DT_UInt:    return DecodeTempl((unsigned int*)pData, LERC_ARG_3);
288
0
  case DT_Float:   return DecodeTempl((float*)pData, LERC_ARG_3);
289
0
  case DT_Double:  return DecodeTempl((double*)pData, LERC_ARG_3);
290
291
0
  default:
292
0
    return ErrCode::WrongParam;
293
0
  }
294
295
0
#undef LERC_ARG_3
296
0
}
297
298
// -------------------------------------------------------------------------- ;
299
300
ErrCode Lerc::ConvertToDouble(const void* pDataIn, DataType dt, size_t nDataValues, double* pDataOut)
301
0
{
302
0
  switch (dt)
303
0
  {
304
0
  case DT_Char:    return ConvertToDoubleTempl((const signed char*)pDataIn, nDataValues, pDataOut);
305
0
  case DT_Byte:    return ConvertToDoubleTempl((const Byte*)pDataIn, nDataValues, pDataOut);
306
0
  case DT_Short:   return ConvertToDoubleTempl((const short*)pDataIn, nDataValues, pDataOut);
307
0
  case DT_UShort:  return ConvertToDoubleTempl((const unsigned short*)pDataIn, nDataValues, pDataOut);
308
0
  case DT_Int:     return ConvertToDoubleTempl((const int*)pDataIn, nDataValues, pDataOut);
309
0
  case DT_UInt:    return ConvertToDoubleTempl((const unsigned int*)pDataIn, nDataValues, pDataOut);
310
0
  case DT_Float:   return ConvertToDoubleTempl((const float*)pDataIn, nDataValues, pDataOut);
311
  //case DT_Double:  no convert double to double
312
313
0
  default:
314
0
    return ErrCode::WrongParam;
315
0
  }
316
0
}
317
318
// -------------------------------------------------------------------------- ;
319
// -------------------------------------------------------------------------- ;
320
321
template<class T>
322
ErrCode Lerc::ComputeCompressedSizeTempl(const T* pData, int version, int nDepth, int nCols, int nRows,
323
  int nBands, int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded,
324
  const unsigned char* pUsesNoData, const double* noDataValues)
325
0
{
326
0
  numBytesNeeded = 0;
327
328
0
  if (!pData || nDepth <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || maxZErr < 0)
329
0
    return ErrCode::WrongParam;
330
331
0
  if (!(nMasks == 0 || nMasks == 1 || nMasks == nBands) || (nMasks > 0 && !pValidBytes))
332
0
    return ErrCode::WrongParam;
333
334
0
  if (!CheckDimensions(nDepth, nCols, nRows, sizeof(T)))
335
0
    return ErrCode::DimensionsTooLarge;
336
337
0
  unsigned int numBytesWritten = 0;
338
339
0
  if (version >= 0 && version <= 5)
340
0
  {
341
0
    if (pUsesNoData)
342
0
      for (int i = 0; i < nBands; i++)
343
0
        if (pUsesNoData[i])
344
0
          return ErrCode::WrongParam;
345
346
0
    return EncodeInternal_v5(pData, version, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr,
347
0
      numBytesNeeded, nullptr, 0, numBytesWritten);
348
0
  }
349
0
  else
350
0
  {
351
0
    return EncodeInternal(pData, version, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr,
352
0
      numBytesNeeded, nullptr, 0, numBytesWritten, pUsesNoData, noDataValues);
353
0
  }
354
0
}
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<signed char>(signed char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<unsigned char>(unsigned char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<short>(short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<unsigned short>(unsigned short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<int>(int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<unsigned int>(unsigned int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<float>(float const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<double>(double const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*)
355
356
// -------------------------------------------------------------------------- ;
357
358
template<class T>
359
ErrCode Lerc::EncodeTempl(const T* pData, int version, int nDepth, int nCols, int nRows, int nBands,
360
  int nMasks, const Byte* pValidBytes, double maxZErr, Byte* pBuffer, unsigned int numBytesBuffer,
361
  unsigned int& numBytesWritten, const unsigned char* pUsesNoData, const double* noDataValues)
362
0
{
363
0
  numBytesWritten = 0;
364
365
0
  if (!pData || nDepth <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || maxZErr < 0 || !pBuffer || !numBytesBuffer)
366
0
    return ErrCode::WrongParam;
367
368
0
  if (!(nMasks == 0 || nMasks == 1 || nMasks == nBands) || (nMasks > 0 && !pValidBytes))
369
0
    return ErrCode::WrongParam;
370
371
0
  if (!CheckDimensions(nDepth, nCols, nRows, sizeof(T)))
372
0
    return ErrCode::DimensionsTooLarge;
373
374
0
  memset(pBuffer, 0, (size_t)numBytesBuffer);
375
376
0
  unsigned int numBytesNeeded = 0;
377
378
0
  if (version >= 0 && version <= 5)
379
0
  {
380
0
    if (pUsesNoData)
381
0
      for (int i = 0; i < nBands; i++)
382
0
        if (pUsesNoData[i])
383
0
          return ErrCode::WrongParam;
384
385
0
    return EncodeInternal_v5(pData, version, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr,
386
0
      numBytesNeeded, pBuffer, numBytesBuffer, numBytesWritten);
387
0
  }
388
0
  else
389
0
  {
390
0
    return EncodeInternal(pData, version, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr,
391
0
      numBytesNeeded, pBuffer, numBytesBuffer, numBytesWritten, pUsesNoData, noDataValues);
392
0
  }
393
0
}
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<signed char>(signed char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<unsigned char>(unsigned char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<short>(short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<unsigned short>(unsigned short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<int>(int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<unsigned int>(unsigned int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<float>(float const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<double>(double const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
394
395
// -------------------------------------------------------------------------- ;
396
397
template<class T>
398
ErrCode Lerc::DecodeTempl(T* pData, const Byte* pLercBlob, unsigned int numBytesBlob,
399
  int nDepth, int nCols, int nRows, int nBands, int nMasks, Byte* pValidBytes,
400
  unsigned char* pUsesNoData, double* noDataValues)
401
0
{
402
0
  if (!pData || nDepth <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || !pLercBlob || !numBytesBlob)
403
0
    return ErrCode::WrongParam;
404
405
0
  if (!(nMasks == 0 || nMasks == 1 || nMasks == nBands) || (nMasks > 0 && !pValidBytes))
406
0
    return ErrCode::WrongParam;
407
408
0
  if (!CheckDimensions(nDepth, nCols, nRows, sizeof(T)))
409
0
    return ErrCode::DimensionsTooLarge;
410
411
0
  const Byte* pByte = pLercBlob;
412
0
  Lerc2::HeaderInfo hdInfo;
413
0
  bool bHasMask = false;
414
415
0
  if (Lerc2::GetHeaderInfo(pByte, numBytesBlob, hdInfo, bHasMask) && hdInfo.version >= 1)    // if Lerc2
416
0
  {
417
0
    LercInfo lercInfo;
418
0
    ErrCode errCode = GetLercInfo(pLercBlob, numBytesBlob, lercInfo);    // fast for Lerc2, does most checks
419
0
    if (errCode != ErrCode::Ok)
420
0
      return errCode;
421
422
    // caller must provide enough space for the masks that are there (e.g., if they differ between bands)
423
0
    if (nMasks < lercInfo.nMasks)    // 0, 1, or nBands
424
0
      return ErrCode::WrongParam;
425
426
    // caller cannot ask for more bands than are there
427
0
    if (nBands > lercInfo.nBands)
428
0
      return ErrCode::WrongParam;
429
430
    // if Lerc blob has noData values not covered by the mask, caller must get it (make sure caller cannot miss it)
431
0
    if (lercInfo.nUsesNoDataValue && nDepth > 1)
432
0
    {
433
0
      if (!pUsesNoData || !noDataValues)
434
0
        return ErrCode::HasNoData;
435
436
0
      try
437
0
      {
438
0
        memset(pUsesNoData, 0, nBands);
439
0
        memset(noDataValues, 0, nBands * sizeof(double));
440
0
      }
441
0
      catch (...)
442
0
      {
443
0
        return ErrCode::HasNoData;
444
0
      }
445
0
    }
446
447
0
    size_t nBytesRemaining = numBytesBlob;
448
0
    Lerc2 lerc2;
449
0
    BitMask bitMask;
450
451
0
    for (int iBand = 0; iBand < nBands; iBand++)
452
0
    {
453
0
      if (((size_t)(pByte - pLercBlob) < numBytesBlob) && Lerc2::GetHeaderInfo(pByte, nBytesRemaining, hdInfo, bHasMask))
454
0
      {
455
0
        if (hdInfo.nDepth != nDepth || hdInfo.nCols != nCols || hdInfo.nRows != nRows || hdInfo.blobSize < 0)
456
0
          return ErrCode::Failed;
457
458
0
        if ((pByte - pLercBlob) + (size_t)hdInfo.blobSize > numBytesBlob)  // corrupted blob
459
0
          return ErrCode::Failed;
460
461
0
        size_t nPix = (size_t)iBand * nRows * nCols;
462
0
        T* arr = pData + nPix * nDepth;
463
464
0
        bool bGetMask = iBand < nMasks;
465
466
0
        if (bGetMask && !bitMask.SetSize(nCols, nRows))
467
0
          return ErrCode::Failed;
468
469
0
        if (!lerc2.Decode(&pByte, nBytesRemaining, arr, bGetMask ? bitMask.Bits() : nullptr))
470
0
          return ErrCode::Failed;
471
472
0
        if (lercInfo.nUsesNoDataValue && nDepth > 1)
473
0
        {
474
0
          pUsesNoData[iBand] = hdInfo.bPassNoDataValues ? 1 : 0;
475
0
          noDataValues[iBand] = hdInfo.noDataValOrig;
476
477
0
          if (hdInfo.bPassNoDataValues && !RemapNoData(arr, bitMask, hdInfo))
478
0
            return ErrCode::Failed;
479
0
        }
480
481
0
        if (bGetMask && !Convert(bitMask, pValidBytes + nPix))
482
0
          return ErrCode::Failed;
483
0
      }
484
0
    }  // iBand
485
0
  }  // Lerc2
486
487
0
  else    // might be old Lerc1
488
0
  {
489
0
#ifdef HAVE_LERC1_DECODE
490
0
    unsigned int numBytesHeaderBand0 = CntZImage::computeNumBytesNeededToReadHeader(false);
491
0
    unsigned int numBytesHeaderBand1 = CntZImage::computeNumBytesNeededToReadHeader(true);
492
0
    const Byte* pByte1 = pLercBlob;
493
0
    CntZImage zImg;
494
495
0
    for (int iBand = 0; iBand < nBands; iBand++)
496
0
    {
497
0
      unsigned int numBytesHeader = iBand == 0 ? numBytesHeaderBand0 : numBytesHeaderBand1;
498
0
      if ((size_t)(pByte1 - pLercBlob) + numBytesHeader > numBytesBlob)  // corrupted blob or wrong nBands
499
0
        return ErrCode::Failed;
500
501
0
      bool onlyZPart = iBand > 0;
502
0
      if (!zImg.read(&pByte1, pLercBlob + numBytesBlob, 1e12, false, onlyZPart))
503
0
        return ErrCode::Failed;
504
505
0
      if (zImg.getWidth() != nCols || zImg.getHeight() != nRows)
506
0
        return ErrCode::Failed;
507
508
0
      size_t nPix = (size_t)iBand * nRows * nCols;
509
0
      T* arr = pData + nPix;
510
0
      Byte* pDst = iBand < nMasks ? pValidBytes + nPix : nullptr;
511
512
0
      if (!Convert(zImg, arr, pDst, iBand == 0))
513
0
        return ErrCode::Failed;
514
0
    }
515
#else
516
    return ErrCode::Failed;
517
#endif
518
0
  }
519
520
0
  return ErrCode::Ok;
521
0
}
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<signed char>(signed char*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<unsigned char>(unsigned char*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<short>(short*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<unsigned short>(unsigned short*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<int>(int*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<unsigned int>(unsigned int*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<float>(float*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<double>(double*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*)
522
523
// -------------------------------------------------------------------------- ;
524
// -------------------------------------------------------------------------- ;
525
526
template<class T>
527
ErrCode Lerc::EncodeInternal_v5(const T* pData, int version, int nDepth, int nCols, int nRows, int nBands,
528
  int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded,
529
  Byte* pBuffer, unsigned int numBytesBuffer, unsigned int& numBytesWritten)
530
0
{
531
0
  numBytesNeeded = 0;
532
0
  numBytesWritten = 0;
533
534
0
  Lerc2 lerc2;
535
0
  if (version >= 0 && !lerc2.SetEncoderToOldVersion(version))
536
0
    return ErrCode::WrongParam;
537
538
0
  Byte* pDst = pBuffer;
539
540
0
  const size_t nPix = (size_t)nCols * nRows;
541
0
  const size_t nElem = nPix * nDepth;
542
543
0
  const Byte* pPrevByteMask = nullptr;
544
0
  vector<T> dataBuffer;
545
0
  vector<Byte> maskBuffer, prevMaskBuffer;
546
0
  BitMask bitMask;
547
548
  // loop over the bands
549
0
  for (int iBand = 0; iBand < nBands; iBand++)
550
0
  {
551
0
    bool bEncMsk = (iBand == 0);
552
553
    // using the proper section of valid bytes, check this band for NaN
554
0
    const T* arr = pData + nElem * iBand;
555
0
    const Byte* pByteMask = (nMasks > 0) ? (pValidBytes + ((nMasks > 1) ? nPix * iBand : 0)) : nullptr;
556
557
0
    ErrCode errCode = CheckForNaN(arr, nDepth, nCols, nRows, pByteMask);
558
0
    if (errCode != ErrCode::Ok && errCode != ErrCode::NaN)
559
0
      return errCode;
560
561
0
    if (errCode == ErrCode::NaN)    // found NaN values
562
0
    {
563
0
      if (!Resize(dataBuffer, nElem) || !Resize(maskBuffer, nPix))
564
0
        return ErrCode::Failed;
565
566
0
      memcpy(&dataBuffer[0], arr, nElem * sizeof(T));
567
0
      pByteMask ? memcpy(&maskBuffer[0], pByteMask, nPix) : memset(&maskBuffer[0], 1, nPix);
568
569
0
      if (!ReplaceNaNValues(dataBuffer, maskBuffer, nDepth, nCols, nRows))
570
0
        return ErrCode::Failed;
571
572
0
      if (iBand > 0 && MasksDiffer(&maskBuffer[0], pPrevByteMask, nPix))
573
0
        bEncMsk = true;
574
575
0
      if (iBand < nBands - 1)
576
0
      {
577
        // keep current mask as new previous band mask
578
0
        prevMaskBuffer = maskBuffer;
579
0
        pPrevByteMask = &prevMaskBuffer[0];
580
0
      }
581
582
0
      arr = &dataBuffer[0];
583
0
      pByteMask = &maskBuffer[0];
584
0
    }
585
586
0
    else    // no NaN in this band, the common case
587
0
    {
588
0
      if (iBand > 0 && MasksDiffer(pByteMask, pPrevByteMask, nPix))
589
0
        bEncMsk = true;
590
591
0
      pPrevByteMask = pByteMask;
592
0
    }
593
594
0
    if (bEncMsk)
595
0
    {
596
0
      if (pByteMask && !Convert(pByteMask, nCols, nRows, bitMask))
597
0
        return ErrCode::Failed;
598
599
0
      if (!lerc2.Set(nDepth, nCols, nRows, pByteMask ? bitMask.Bits() : nullptr))
600
0
        return ErrCode::Failed;
601
0
    }
602
603
0
    unsigned int nBytes = lerc2.ComputeNumBytesNeededToWrite(arr, maxZErr, bEncMsk);
604
0
    if (nBytes <= 0)
605
0
      return ErrCode::Failed;
606
607
0
    if ((size_t)numBytesNeeded + nBytes > (size_t)UINT_MAX)  // keep total blob size (over all bands) <= 4 GB
608
0
      return ErrCode::DimensionsTooLarge;
609
610
0
    numBytesNeeded += nBytes;
611
612
0
    if (pBuffer)
613
0
    {
614
0
      if ((size_t)(pDst - pBuffer) + nBytes > numBytesBuffer)    // check we have enough space left
615
0
        return ErrCode::BufferTooSmall;
616
617
0
      if (!lerc2.Encode(arr, &pDst))
618
0
        return ErrCode::Failed;
619
0
    }
620
0
  }  // iBand
621
622
0
  numBytesWritten = (unsigned int)(pDst - pBuffer);
623
0
  return ErrCode::Ok;
624
0
}
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<signed char>(signed char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<unsigned char>(unsigned char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<short>(short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<unsigned short>(unsigned short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<int>(int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<unsigned int>(unsigned int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<float>(float const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<double>(double const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&)
625
626
// -------------------------------------------------------------------------- ;
627
628
template<class T>
629
ErrCode Lerc::EncodeInternal(const T* pData, int version, int nDepth, int nCols, int nRows, int nBands,
630
  int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded,
631
  Byte* pBuffer, unsigned int numBytesBuffer, unsigned int& numBytesWritten,
632
  const unsigned char* pUsesNoData, const double* noDataValues)
633
0
{
634
0
  numBytesNeeded = 0;
635
0
  numBytesWritten = 0;
636
637
0
  if (version >= 0 && version <= 5)
638
0
    return ErrCode::WrongParam;
639
640
0
  Lerc2 lerc2;
641
642
#ifdef ENCODE_VERIFY
643
  Lerc2 lerc2Verify;
644
#endif
645
646
0
  if (version >= 0 && !lerc2.SetEncoderToOldVersion(version))
647
0
    return ErrCode::WrongParam;
648
649
0
  if (pUsesNoData && !noDataValues)
650
0
    for (int i = 0; i < nBands; i++)
651
0
      if (pUsesNoData[i])
652
0
        return ErrCode::WrongParam;
653
654
0
  Byte* pDst = pBuffer;
655
656
0
  const size_t nPix = (size_t)nCols * nRows;
657
0
  const size_t nElem = nPix * nDepth;
658
659
0
  const Byte* pPrevByteMask = nullptr;
660
0
  vector<T> dataBuffer;
661
0
  vector<Byte> maskBuffer, prevMaskBuffer;
662
0
  BitMask bitMask;
663
664
  // allocate buffer for 1 band
665
0
  if (!Resize(dataBuffer, nElem) || !Resize(maskBuffer, nPix))
666
0
    return ErrCode::Failed;
667
668
0
  bool bIsFltOrDbl = (typeid(T) == typeid(float) || typeid(T) == typeid(double));
669
0
  bool bAnyMaskModified = false;
670
0
  ErrCode errCode = ErrCode::Ok;
671
672
  // loop over the bands
673
0
  for (int iBand = 0; iBand < nBands; iBand++)
674
0
  {
675
0
    bool bEncMsk = (iBand == 0);
676
677
    // get the data and mask for this band
678
0
    const T* arrOrig = pData + nElem * iBand;
679
0
    const Byte* pByteMaskOrig = (nMasks > 0) ? (pValidBytes + ((nMasks > 1) ? nPix * iBand : 0)) : nullptr;
680
681
    // copy to buffer so we can modify it
682
0
    memcpy(&dataBuffer[0], arrOrig, nElem * sizeof(T));
683
0
    pByteMaskOrig ? memcpy(&maskBuffer[0], pByteMaskOrig, nPix) : memset(&maskBuffer[0], 1, nPix);
684
685
0
    double maxZErrL = maxZErr;    // maxZErrL can get modified in the filter functions below
686
687
0
    bool bPassNoDataValue = (pUsesNoData && (pUsesNoData[iBand] > 0));
688
0
    const double noDataOrig = bPassNoDataValue ? noDataValues[iBand] : 0;
689
690
0
    double noDataL = noDataOrig;    // noDataL can get modified in the filter functions below
691
692
0
    bool bIsFltDblAllInt = false;    // are the flt numbers all integer really? Double can be used for int numbers beyond 32 bit range
693
0
    bool bModifiedMask = false;    // can turn true if NaN or noData found at valid pixels
694
0
    bool bNeedNoData = false;    // can only turn true for nDepth > 1, and mix of valid and invalid values at the same pixel (special case)
695
0
    errCode = ErrCode::Ok;
696
697
0
    double minVal(+1), maxVal(-1);
698
0
    lerc2.ClearMinMax();
699
700
0
    if (bIsFltOrDbl)    // if flt type, filter out NaN and / or noData values and update the mask if possible
701
0
    {
702
0
      errCode = FilterNoDataAndNaN(dataBuffer, maskBuffer, nDepth, nCols, nRows, maxZErrL, bPassNoDataValue, noDataL,
703
0
        bModifiedMask, bNeedNoData, bIsFltDblAllInt, minVal, maxVal);
704
0
    }
705
0
    else if (bPassNoDataValue)    // if int type (no NaN), and no noData value specified, nothing to do
706
0
    {
707
0
      errCode = FilterNoData(dataBuffer, maskBuffer, nDepth, nCols, nRows, maxZErrL, bPassNoDataValue, noDataL,
708
0
        bModifiedMask, bNeedNoData, minVal, maxVal);
709
0
    }
710
711
0
    if (errCode != ErrCode::Ok)
712
0
      return errCode;
713
714
0
    if (bModifiedMask)
715
0
      bAnyMaskModified = true;
716
717
0
    bool bCompareMasks = (nMasks > 1) || bAnyMaskModified;
718
719
0
    if (bCompareMasks && (iBand > 0) && MasksDiffer(&maskBuffer[0], pPrevByteMask, nPix))
720
0
      bEncMsk = true;
721
722
0
    if (nBands > 1 && iBand < nBands - 1)
723
0
    {
724
      // keep current mask as new previous band mask
725
0
      prevMaskBuffer = maskBuffer;
726
0
      pPrevByteMask = &prevMaskBuffer[0];
727
0
    }
728
729
0
    const T* arrL = &dataBuffer[0];
730
0
    const Byte* pByteMaskL = &maskBuffer[0];
731
732
0
    if (bEncMsk)
733
0
    {
734
0
      bool bAllValid = !memchr(pByteMaskL, 0, nPix);
735
736
0
      if (!bAllValid && !Convert(pByteMaskL, nCols, nRows, bitMask))
737
0
        return ErrCode::Failed;
738
739
0
      if (!lerc2.Set(nDepth, nCols, nRows, !bAllValid ? bitMask.Bits() : nullptr))
740
0
        return ErrCode::Failed;
741
0
    }
742
743
    // set other flags
744
0
    if ( !lerc2.SetNoDataValues(bNeedNoData, noDataL, noDataOrig)
745
0
      || !lerc2.SetNumBlobsMoreToCome(nBands - 1 - iBand)
746
0
      || !lerc2.SetIsAllInt(bIsFltDblAllInt))
747
0
      return ErrCode::Failed;
748
749
0
    if (nDepth == 1 && (maxVal >= minVal)
750
0
      && !lerc2.SetMinMax(nDepth, minVal, maxVal))
751
0
      return ErrCode::Failed;
752
753
0
    unsigned int nBytes = lerc2.ComputeNumBytesNeededToWrite(arrL, maxZErrL, bEncMsk);
754
0
    if (nBytes <= 0)
755
0
      return ErrCode::Failed;
756
757
0
    if ((size_t)numBytesNeeded + nBytes > (size_t)UINT_MAX)  // keep total blob size (over all bands) <= 4 GB
758
0
      return ErrCode::DimensionsTooLarge;
759
760
0
    numBytesNeeded += nBytes;
761
762
0
    if (pBuffer)
763
0
    {
764
0
      if ((size_t)(pDst - pBuffer) + nBytes > numBytesBuffer)    // check we have enough space left
765
0
        return ErrCode::BufferTooSmall;
766
767
#ifdef ENCODE_VERIFY
768
      const Byte* pDst0 = pDst;
769
#endif
770
771
0
      if (!lerc2.Encode(arrL, &pDst))
772
0
        return ErrCode::Failed;
773
774
#ifdef ENCODE_VERIFY
775
      size_t blobSize = pDst - pDst0;
776
777
      if (!DecodeAndCompareToInput(pDst0, blobSize, maxZErrL, lerc2Verify, arrL, pByteMaskL,
778
        arrOrig, pByteMaskOrig, bPassNoDataValue, noDataOrig, bModifiedMask))
779
      {
780
        return ErrCode::Failed;
781
      }
782
#endif
783
784
0
    }
785
0
  }  // iBand
786
787
0
  numBytesWritten = (unsigned int)(pDst - pBuffer);
788
0
  return ErrCode::Ok;
789
0
}
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<signed char>(signed char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<unsigned char>(unsigned char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<short>(short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<unsigned short>(unsigned short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<int>(int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<unsigned int>(unsigned int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<float>(float const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<double>(double const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*)
790
791
// -------------------------------------------------------------------------- ;
792
793
#ifdef HAVE_LERC1_DECODE
794
template<class T>
795
bool Lerc::Convert(const CntZImage& zImg, T* arr, Byte* pByteMask, bool bMustFillMask)
796
0
{
797
0
  if (!arr || !zImg.getSize())
798
0
    return false;
799
800
0
  const bool fltPnt = (typeid(*arr) == typeid(double)) || (typeid(*arr) == typeid(float));
801
802
0
  int h = zImg.getHeight();
803
0
  int w = zImg.getWidth();
804
805
0
  const CntZ* srcPtr = zImg.getData();
806
0
  T* dstPtr = arr;
807
0
  int num = w * h;
808
809
0
  if (pByteMask)
810
0
  {
811
0
    memset(pByteMask, 0, num);
812
813
0
    for (int k = 0; k < num; k++)
814
0
    {
815
0
      if (srcPtr->cnt > 0)
816
0
      {
817
0
        *dstPtr = fltPnt ? (T)srcPtr->z : (T)floor(srcPtr->z + 0.5);
818
0
        pByteMask[k] = 1;
819
0
      }
820
821
0
      srcPtr++;
822
0
      dstPtr++;
823
0
    }
824
0
  }
825
0
  else
826
0
  {
827
0
    for (int k = 0; k < num; k++)
828
0
    {
829
0
      if (srcPtr->cnt > 0)
830
0
      {
831
0
        *dstPtr = fltPnt ? (T)srcPtr->z : (T)floor(srcPtr->z + 0.5);
832
0
      }
833
0
      else if (bMustFillMask)
834
0
        return false;
835
836
0
      srcPtr++;
837
0
      dstPtr++;
838
0
    }
839
0
  }
840
841
0
  return true;
842
0
}
Unexecuted instantiation: bool LercNS::Lerc::Convert<signed char>(LercNS::CntZImage const&, signed char*, unsigned char*, bool)
Unexecuted instantiation: bool LercNS::Lerc::Convert<unsigned char>(LercNS::CntZImage const&, unsigned char*, unsigned char*, bool)
Unexecuted instantiation: bool LercNS::Lerc::Convert<short>(LercNS::CntZImage const&, short*, unsigned char*, bool)
Unexecuted instantiation: bool LercNS::Lerc::Convert<unsigned short>(LercNS::CntZImage const&, unsigned short*, unsigned char*, bool)
Unexecuted instantiation: bool LercNS::Lerc::Convert<int>(LercNS::CntZImage const&, int*, unsigned char*, bool)
Unexecuted instantiation: bool LercNS::Lerc::Convert<unsigned int>(LercNS::CntZImage const&, unsigned int*, unsigned char*, bool)
Unexecuted instantiation: bool LercNS::Lerc::Convert<float>(LercNS::CntZImage const&, float*, unsigned char*, bool)
Unexecuted instantiation: bool LercNS::Lerc::Convert<double>(LercNS::CntZImage const&, double*, unsigned char*, bool)
843
#endif
844
845
// -------------------------------------------------------------------------- ;
846
847
template<class T>
848
ErrCode Lerc::ConvertToDoubleTempl(const T* pDataIn, size_t nDataValues, double* pDataOut)
849
0
{
850
0
  if (!pDataIn || !nDataValues || !pDataOut)
851
0
    return ErrCode::WrongParam;
852
853
0
  for (size_t k = 0; k < nDataValues; k++)
854
0
    pDataOut[k] = pDataIn[k];
855
856
0
  return ErrCode::Ok;
857
0
}
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<signed char>(signed char const*, unsigned long, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<unsigned char>(unsigned char const*, unsigned long, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<short>(short const*, unsigned long, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<unsigned short>(unsigned short const*, unsigned long, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<int>(int const*, unsigned long, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<unsigned int>(unsigned int const*, unsigned long, double*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<float>(float const*, unsigned long, double*)
858
859
// -------------------------------------------------------------------------- ;
860
861
template<class T> ErrCode Lerc::CheckForNaN(const T* arr, int nDepth, int nCols, int nRows, const Byte* pByteMask)
862
0
{
863
0
  if (!arr || nDepth <= 0 || nCols <= 0 || nRows <= 0)
864
0
    return ErrCode::WrongParam;
865
866
0
  if (typeid(T) != typeid(double) && typeid(T) != typeid(float))
867
0
    return ErrCode::Ok;
868
869
0
  for (size_t k = 0, i = 0; i < (size_t)nRows; i++)
870
0
  {
871
0
    bool bFoundNaN = false;
872
0
    const T* rowArr = &(arr[i * nCols * nDepth]);
873
874
0
    if (!pByteMask)    // all valid
875
0
    {
876
0
      size_t num = (size_t)nCols * nDepth;
877
0
      for (size_t m = 0; m < num; m++)
878
0
        if (std::isnan((double)rowArr[m]))
879
0
          bFoundNaN = true;
880
0
    }
881
0
    else    // not all valid
882
0
    {
883
0
      for (size_t n = 0, j = 0; j < (size_t)nCols; j++, k++, n += nDepth)
884
0
        if (pByteMask[k])
885
0
        {
886
0
          for (int m = 0; m < nDepth; m++)
887
0
            if (std::isnan((double)rowArr[n + m]))
888
0
              bFoundNaN = true;
889
0
        }
890
0
    }
891
892
0
    if (bFoundNaN)
893
0
      return ErrCode::NaN;
894
0
  }
895
896
0
  return ErrCode::Ok;
897
0
}
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<signed char>(signed char const*, int, int, int, unsigned char const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<unsigned char>(unsigned char const*, int, int, int, unsigned char const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<short>(short const*, int, int, int, unsigned char const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<unsigned short>(unsigned short const*, int, int, int, unsigned char const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<int>(int const*, int, int, int, unsigned char const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<unsigned int>(unsigned int const*, int, int, int, unsigned char const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<float>(float const*, int, int, int, unsigned char const*)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<double>(double const*, int, int, int, unsigned char const*)
898
899
// -------------------------------------------------------------------------- ;
900
901
template<class T> bool Lerc::ReplaceNaNValues(std::vector<T>& dataBuffer, std::vector<Byte>& maskBuffer, int nDepth, int nCols, int nRows)
902
0
{
903
0
  if (nDepth <= 0 || nCols <= 0 || nRows <= 0 || dataBuffer.size() != (size_t)nDepth * nCols * nRows || maskBuffer.size() != (size_t)nCols * nRows)
904
0
    return false;
905
906
0
  T noDataValue = 0;
907
0
  {
908
    #if defined _WIN32
909
      #pragma warning(disable: 4756)    // would trigger build warning in linux
910
    #endif
911
912
0
    noDataValue = (T)((typeid(T) == typeid(float)) ? -FLT_MAX : -DBL_MAX);
913
0
  }
914
915
0
  for (size_t k = 0, i = 0; i < (size_t)nRows; i++)
916
0
  {
917
0
    T* rowArr = &(dataBuffer[i * nCols * nDepth]);
918
919
0
    for (size_t n = 0, j = 0; j < (size_t)nCols; j++, k++, n += nDepth)
920
0
    {
921
0
      if (maskBuffer[k])
922
0
      {
923
0
        int cntNaN = 0;
924
925
0
        for (int m = 0; m < nDepth; m++)
926
0
          if (std::isnan((double)rowArr[n + m]))
927
0
          {
928
0
            cntNaN++;
929
0
            rowArr[n + m] = noDataValue;
930
0
          }
931
932
0
        if (cntNaN == nDepth)
933
0
          maskBuffer[k] = 0;
934
0
      }
935
0
    }
936
0
  }
937
938
0
  return true;
939
0
}
Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<signed char>(std::__1::vector<signed char, std::__1::allocator<signed char> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int)
Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<unsigned char>(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int)
Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<short>(std::__1::vector<short, std::__1::allocator<short> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int)
Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<unsigned short>(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int)
Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<int>(std::__1::vector<int, std::__1::allocator<int> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int)
Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int)
Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<float>(std::__1::vector<float, std::__1::allocator<float> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int)
Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<double>(std::__1::vector<double, std::__1::allocator<double> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int)
940
941
// -------------------------------------------------------------------------- ;
942
943
template<class T> bool Lerc::Resize(std::vector<T>& buffer, size_t nElem)
944
0
{
945
0
  try
946
0
  {
947
0
    buffer.resize(nElem);
948
0
  }
949
0
  catch (...)
950
0
  {
951
0
    return false;
952
0
  }
953
954
0
  return (buffer.size() == nElem);
955
0
}
Unexecuted instantiation: bool LercNS::Lerc::Resize<signed char>(std::__1::vector<signed char, std::__1::allocator<signed char> >&, unsigned long)
Unexecuted instantiation: bool LercNS::Lerc::Resize<unsigned char>(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, unsigned long)
Unexecuted instantiation: bool LercNS::Lerc::Resize<short>(std::__1::vector<short, std::__1::allocator<short> >&, unsigned long)
Unexecuted instantiation: bool LercNS::Lerc::Resize<unsigned short>(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >&, unsigned long)
Unexecuted instantiation: bool LercNS::Lerc::Resize<int>(std::__1::vector<int, std::__1::allocator<int> >&, unsigned long)
Unexecuted instantiation: bool LercNS::Lerc::Resize<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, unsigned long)
Unexecuted instantiation: bool LercNS::Lerc::Resize<float>(std::__1::vector<float, std::__1::allocator<float> >&, unsigned long)
Unexecuted instantiation: bool LercNS::Lerc::Resize<double>(std::__1::vector<double, std::__1::allocator<double> >&, unsigned long)
956
957
// -------------------------------------------------------------------------- ;
958
959
bool Lerc::Convert(const Byte* pByteMask, int nCols, int nRows, BitMask& bitMask)
960
0
{
961
0
  if (!pByteMask || nCols <= 0 || nRows <= 0)
962
0
    return false;
963
964
0
  if (!bitMask.SetSize(nCols, nRows))
965
0
    return false;
966
967
0
  bitMask.SetAllValid();
968
969
0
  for (int k = 0, i = 0; i < nRows; i++)
970
0
    for (int j = 0; j < nCols; j++, k++)
971
0
      if (!pByteMask[k])
972
0
        bitMask.SetInvalid(k);
973
974
0
  return true;
975
0
}
976
977
// -------------------------------------------------------------------------- ;
978
979
bool Lerc::Convert(const BitMask& bitMask, Byte* pByteMask)
980
0
{
981
0
  int nCols = bitMask.GetWidth();
982
0
  int nRows = bitMask.GetHeight();
983
984
0
  if (nCols <= 0 || nRows <= 0 || !pByteMask)
985
0
    return false;
986
987
0
  memset(pByteMask, 0, (size_t)nCols * nRows);
988
989
0
  for (int k = 0, i = 0; i < nRows; i++)
990
0
    for (int j = 0; j < nCols; j++, k++)
991
0
      if (bitMask.IsValid(k))
992
0
        pByteMask[k] = 1;
993
994
0
  return true;
995
0
}
996
997
// -------------------------------------------------------------------------- ;
998
999
bool Lerc::MasksDiffer(const Byte* p0, const Byte* p1, size_t n)
1000
0
{
1001
0
  if (p0 == p1)
1002
0
    return false;
1003
1004
0
  if (!p0)    // means all valid
1005
0
    return memchr(p1, 0, n);    // any invalid?
1006
0
  else if (!p1)
1007
0
    return memchr(p0, 0, n);
1008
0
  else
1009
0
    return memcmp(p0, p1, n);
1010
0
}
1011
1012
// -------------------------------------------------------------------------- ;
1013
1014
ErrCode Lerc::GetRanges(const Byte* pLercBlob, unsigned int numBytesBlob, int iBand,
1015
  const struct Lerc2::HeaderInfo& lerc2Info, double* pMins, double* pMaxs, size_t nElem)
1016
0
{
1017
0
  const int nDepth = lerc2Info.nDepth;
1018
1019
0
  if (nDepth <= 0 || iBand < 0 || !pMins || !pMaxs)
1020
0
    return ErrCode::WrongParam;
1021
1022
0
  if (nElem < ((size_t)iBand + 1) * (size_t)nDepth)
1023
0
    return ErrCode::BufferTooSmall;
1024
1025
0
  if (nDepth == 1)
1026
0
  {
1027
0
    pMins[iBand] = lerc2Info.zMin;
1028
0
    pMaxs[iBand] = lerc2Info.zMax;
1029
0
  }
1030
0
  else
1031
0
  {
1032
0
    if (lerc2Info.bPassNoDataValues)    // for nDepth > 1, and mix of valid and invalid values at same pixel, better fail
1033
0
      return ErrCode::HasNoData;        // than return min or max values that contain noData (to be fixed in next codec version)
1034
1035
    // read header, mask, ranges, and copy them out
1036
0
    Lerc2 lerc2;
1037
0
    if (!lerc2.GetRanges(pLercBlob, numBytesBlob, &pMins[iBand * nDepth], &pMaxs[iBand * nDepth]))
1038
0
      return ErrCode::Failed;
1039
0
  }
1040
1041
0
  return ErrCode::Ok;
1042
0
}
1043
1044
// -------------------------------------------------------------------------- ;
1045
1046
template<class T>
1047
bool Lerc::RemapNoData(T* data, const BitMask& bitMask, const struct Lerc2::HeaderInfo& lerc2Info)
1048
0
{
1049
0
  int nCols = lerc2Info.nCols;
1050
0
  int nRows = lerc2Info.nRows;
1051
0
  int nDepth = lerc2Info.nDepth;
1052
1053
0
  if (!data || nCols <= 0 || nRows <= 0 || nDepth <= 0)
1054
0
    return false;
1055
1056
0
  const T noDataOld = (T)lerc2Info.noDataVal;
1057
0
  const T noDataNew = (T)lerc2Info.noDataValOrig;
1058
1059
0
  if (noDataNew != noDataOld)
1060
0
  {
1061
0
    bool bUseMask = (bitMask.GetWidth() == nCols) && (bitMask.GetHeight() == nRows);
1062
1063
0
    for (long k = 0, i = 0; i < nRows; i++)
1064
0
    {
1065
0
      T* rowArr = &(data[i * nCols * nDepth]);
1066
1067
0
      for (long n = 0, j = 0; j < nCols; j++, k++, n += nDepth)
1068
0
        if (!bUseMask || bitMask.IsValid(k))
1069
0
          for (long m = 0; m < nDepth; m++)
1070
0
            if (rowArr[n + m] == noDataOld)
1071
0
              rowArr[n + m] = noDataNew;
1072
0
    }
1073
0
  }
1074
1075
0
  return true;
1076
0
}
Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<signed char>(signed char*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&)
Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<unsigned char>(unsigned char*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&)
Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<short>(short*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&)
Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<unsigned short>(unsigned short*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&)
Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<int>(int*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&)
Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<unsigned int>(unsigned int*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&)
Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<float>(float*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&)
Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<double>(double*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&)
1077
1078
// -------------------------------------------------------------------------- ;
1079
1080
template<class T>
1081
bool Lerc::DecodeAndCompareToInput(const Byte* pLercBlob, size_t blobSize, double maxZErr, Lerc2& lerc2Verify,
1082
  const T* pData, const Byte* pByteMask, const T* pDataOrig, const Byte* pByteMaskOrig,
1083
  bool bInputHasNoData, double origNoDataA, bool bModifiedMask)
1084
{
1085
  if (!pLercBlob || !pData || !pDataOrig)
1086
    return false;
1087
1088
  const Byte* bytePtr = pLercBlob;
1089
  size_t nBytesRemaining = blobSize;
1090
1091
  bool bHasMask(false);
1092
  Lerc2::HeaderInfo hd;
1093
  if (!Lerc2::GetHeaderInfo(bytePtr, nBytesRemaining, hd, bHasMask))
1094
    return false;
1095
1096
  std::vector<T> arrDec;
1097
  try
1098
  {
1099
    arrDec.assign(hd.nRows * hd.nCols * hd.nDepth, 0);
1100
  }
1101
  catch (...)
1102
  {
1103
    return false;
1104
  }
1105
1106
  BitMask bitMaskDec;
1107
  if (!bitMaskDec.SetSize(hd.nCols, hd.nRows))
1108
    return false;
1109
1110
  bitMaskDec.SetAllInvalid();
1111
1112
  if (!lerc2Verify.Decode(&bytePtr, nBytesRemaining, &arrDec[0], bitMaskDec.Bits()))
1113
    return false;
1114
1115
  // compare decoded bit mask and data array against the input to lerc encode (as after that orig input had the noData value remapped, NaN removed, bit mask altered)
1116
  {
1117
    bool bHasMaskBug(false);
1118
    double maxDelta = 0;
1119
1120
    for (int k = 0, i = 0; i < hd.nRows; i++)
1121
      for (int j = 0; j < hd.nCols; j++, k++)
1122
        if (bitMaskDec.IsValid(k))
1123
        {
1124
          if (pByteMask && !pByteMask[k])
1125
            bHasMaskBug = true;
1126
1127
          for (int n = k * hd.nDepth, m = 0; m < hd.nDepth; m++, n++)
1128
          {
1129
            double d = fabs((double)arrDec[n] - (double)pData[n]);
1130
            if (d > maxDelta)
1131
              maxDelta = d;
1132
          }
1133
        }
1134
        else if (!pByteMask || pByteMask[k])
1135
          bHasMaskBug = true;
1136
1137
    if (bHasMaskBug || maxDelta > maxZErr * 1.1)    // consider float rounding errors
1138
      return false;
1139
  }
1140
1141
  if (!bInputHasNoData && !bModifiedMask)    // any NaN in the input means either modify the mask or replace it by noData value
1142
    return true;
1143
1144
  const bool bIsFltOrDbl = (typeid(T) == typeid(double) || typeid(T) == typeid(float));
1145
  const bool bHaveNoDataVal = (hd.version >= 6 && hd.bPassNoDataValues && hd.nDepth > 1);
1146
1147
  if (bHaveNoDataVal && hd.noDataValOrig != origNoDataA)
1148
    return false;
1149
1150
  if (bHaveNoDataVal && hd.noDataVal != hd.noDataValOrig)
1151
  {
1152
    // remap the noData value from internal to orig
1153
    if (!RemapNoData(&arrDec[0], bitMaskDec, hd))
1154
      return false;
1155
  }
1156
1157
  // compare the final result to orig bit mask and data array as it was handed to the Compress() function
1158
  {
1159
    T noDataOrig = (T)origNoDataA;
1160
    double maxDelta = 0;
1161
    bool bHasBug(false);
1162
1163
    for (int k = 0, i = 0; i < hd.nRows; i++)
1164
      for (int j = 0; j < hd.nCols; j++, k++)
1165
        if (!pByteMaskOrig || pByteMaskOrig[k])
1166
        {
1167
          if (!bitMaskDec.IsValid(k))    // then the orig data values must be noData or NaN
1168
          {
1169
            for (int n = k * hd.nDepth, m = 0; m < hd.nDepth; m++, n++)
1170
            {
1171
              T zOrig = pDataOrig[n];
1172
              bool bIsNoData = (bInputHasNoData && zOrig == noDataOrig) || (bIsFltOrDbl && std::isnan((double)zOrig));
1173
1174
              if (!bIsNoData)
1175
                bHasBug = true;
1176
            }
1177
          }
1178
          else    // valid pixel
1179
          {
1180
            for (int n = k * hd.nDepth, m = 0; m < hd.nDepth; m++, n++)
1181
            {
1182
              T zOrig = pDataOrig[n];
1183
              T z = arrDec[n];
1184
1185
              if (z == zOrig)    // valid value or noData
1186
                continue;
1187
1188
              if (bIsFltOrDbl && std::isnan((double)zOrig))
1189
                zOrig = noDataOrig;
1190
1191
              if (bInputHasNoData && (z == noDataOrig || zOrig == noDataOrig) && (z != zOrig))
1192
                bHasBug = true;
1193
1194
              if (!bHaveNoDataVal || z != noDataOrig)    // is valid
1195
              {
1196
                double d = fabs((double)z - (double)zOrig);
1197
                if (d > maxDelta)
1198
                  maxDelta = d;
1199
              }
1200
            }
1201
          }
1202
        }
1203
        else if (bitMaskDec.IsValid(k))
1204
          bHasBug = true;
1205
1206
    if (bHasBug || maxDelta > maxZErr * 1.1)    // consider float rounding errors
1207
      return false;
1208
  }
1209
1210
  return true;
1211
}
1212
1213
// -------------------------------------------------------------------------- ;
1214
1215
template<class T>
1216
bool Lerc::GetTypeRange(const T, std::pair<double, double>& range)
1217
0
{
1218
0
  range.first = 0;
1219
1220
0
  if (typeid(T) == typeid(Byte))
1221
0
    range.second = UCHAR_MAX;
1222
0
  else if (typeid(T) == typeid(unsigned short))
1223
0
    range.second = USHRT_MAX;
1224
0
  else if (typeid(T) == typeid(unsigned int) || typeid(T) == typeid(unsigned long))
1225
0
  range.second = UINT_MAX;
1226
1227
0
  else if (typeid(T) == typeid(signed char))
1228
0
    range = std::pair<double, double>(CHAR_MIN, CHAR_MAX);
1229
0
  else if (typeid(T) == typeid(short))
1230
0
    range = std::pair<double, double>(SHRT_MIN, SHRT_MAX);
1231
0
  else if (typeid(T) == typeid(int) || typeid(T) == typeid(long))
1232
0
    range = std::pair<double, double>(INT_MIN, INT_MAX);
1233
0
  else
1234
0
    return false;
1235
1236
0
  return true;
1237
0
}
Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<signed char>(signed char, std::__1::pair<double, double>&)
Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<unsigned char>(unsigned char, std::__1::pair<double, double>&)
Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<short>(short, std::__1::pair<double, double>&)
Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<unsigned short>(unsigned short, std::__1::pair<double, double>&)
Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<int>(int, std::__1::pair<double, double>&)
Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<unsigned int>(unsigned int, std::__1::pair<double, double>&)
Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<float>(float, std::__1::pair<double, double>&)
Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<double>(double, std::__1::pair<double, double>&)
1238
1239
// -------------------------------------------------------------------------- ;
1240
1241
template<class T>
1242
ErrCode Lerc::FilterNoData(std::vector<T>& dataBuffer, std::vector<Byte>& maskBuffer, int nDepth, int nCols, int nRows,
1243
  double& maxZError, bool bPassNoDataValue, double& noDataValue, bool& bModifiedMask, bool& bNeedNoData,
1244
  double& minValA, double& maxValA)
1245
0
{
1246
0
  if (nDepth <= 0 || nCols <= 0 || nRows <= 0 || maxZError < 0)
1247
0
    return ErrCode::WrongParam;
1248
1249
0
  if ((dataBuffer.size() != (size_t)nDepth * nCols * nRows) || (maskBuffer.size() != (size_t)nCols * nRows))
1250
0
    return ErrCode::Failed;
1251
1252
0
  bModifiedMask = false;
1253
0
  bNeedNoData = false;
1254
1255
0
  if (!bPassNoDataValue)    // nothing to do
1256
0
    return ErrCode::Ok;
1257
1258
0
  std::pair<double, double> typeRange;
1259
0
  if (!GetTypeRange(dataBuffer[0], typeRange))
1260
0
    return ErrCode::Failed;
1261
1262
0
  if (noDataValue < typeRange.first || noDataValue > typeRange.second)
1263
0
    return ErrCode::WrongParam;
1264
1265
0
  T origNoData = (T)noDataValue;
1266
1267
0
  double minVal = DBL_MAX;
1268
0
  double maxVal = -DBL_MAX;
1269
1270
  // check for noData in valid pixels
1271
0
  for (int k = 0, i = 0; i < nRows; i++)
1272
0
  {
1273
0
    T* rowArr = &(dataBuffer[(size_t)i * nCols * nDepth]);
1274
1275
0
    for (int n = 0, j = 0; j < nCols; j++, k++, n += nDepth)
1276
0
      if (maskBuffer[k])
1277
0
      {
1278
0
        int cntInvalid = 0;
1279
1280
0
        for (int m = 0; m < nDepth; m++)
1281
0
        {
1282
0
          T z = rowArr[n + m];
1283
1284
0
          if (z == origNoData)
1285
0
            cntInvalid++;
1286
0
          else
1287
0
          {
1288
0
            if (z < minVal)
1289
0
              minVal = z;
1290
0
            if (z > maxVal)
1291
0
              maxVal = z;
1292
0
          }
1293
0
        }
1294
1295
0
        if (cntInvalid == nDepth)
1296
0
        {
1297
0
          maskBuffer[k] = 0;
1298
0
          bModifiedMask = true;
1299
0
        }
1300
0
        else if (cntInvalid > 0)    // found mix of valid and invalid values at the same pixel
1301
0
          bNeedNoData = true;
1302
0
      }
1303
0
  }
1304
1305
0
  double maxZErrL = (std::max)(0.5, floor(maxZError));    // same mapping for int types as in Lerc2.cpp
1306
0
  double dist = floor(maxZErrL);
1307
1308
0
  if (minVal == DBL_MAX && maxVal == -DBL_MAX)    // if the tile has no valid data
1309
0
  {
1310
0
    minValA = maxValA = 0;
1311
0
    maxZError = 0.5;
1312
0
    return ErrCode::Ok;
1313
0
  }
1314
1315
0
  minValA = minVal;
1316
0
  maxValA = maxVal;
1317
1318
  // check the orig noData value is far enough away from the valid range
1319
0
  if ((origNoData >= minVal - dist) && (origNoData <= maxVal + dist))
1320
0
  {
1321
0
    maxZError = 0.5;    // fall back to int lossless
1322
0
    return ErrCode::Ok;
1323
0
  }
1324
1325
0
  if (bNeedNoData)
1326
0
  {
1327
0
    double minDist = floor(maxZErrL) + 1;
1328
0
    double remapVal = minVal - minDist;
1329
0
    T newNoData = origNoData;
1330
1331
0
    if (remapVal >= typeRange.first)
1332
0
    {
1333
0
      newNoData = (T)remapVal;
1334
0
    }
1335
0
    else
1336
0
    {
1337
0
      maxZErrL = 0.5;    // repeat with int lossless
1338
0
      remapVal = minVal - 1;
1339
1340
0
      if (remapVal >= typeRange.first)
1341
0
      {
1342
0
        newNoData = (T)remapVal;
1343
0
      }
1344
0
      else
1345
0
      {
1346
0
        remapVal = maxVal + 1;    // try to map closer to valid range from top
1347
1348
0
        if ((remapVal <= typeRange.second) && (remapVal < origNoData))
1349
0
          newNoData = (T)remapVal;
1350
0
      }
1351
0
    }
1352
1353
0
    if (newNoData != origNoData)
1354
0
    {
1355
0
      for (int k = 0, i = 0; i < nRows; i++)
1356
0
      {
1357
0
        T* rowArr = &(dataBuffer[(size_t)i * nCols * nDepth]);
1358
1359
0
        for (int n = 0, j = 0; j < nCols; j++, k++, n += nDepth)
1360
0
          if (maskBuffer[k])
1361
0
            for (int m = 0; m < nDepth; m++)
1362
0
              if (rowArr[n + m] == origNoData)
1363
0
                rowArr[n + m] = newNoData;
1364
0
      }
1365
1366
0
      noDataValue = newNoData;
1367
0
    }
1368
0
  }
1369
1370
0
  if (maxZError != maxZErrL)
1371
0
    maxZError = maxZErrL;
1372
1373
0
  return ErrCode::Ok;
1374
0
}
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<signed char>(std::__1::vector<signed char, std::__1::allocator<signed char> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<unsigned char>(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<short>(std::__1::vector<short, std::__1::allocator<short> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<unsigned short>(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<int>(std::__1::vector<int, std::__1::allocator<int> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<float>(std::__1::vector<float, std::__1::allocator<float> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<double>(std::__1::vector<double, std::__1::allocator<double> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&)
1375
1376
// -------------------------------------------------------------------------- ;
1377
1378
template<class T>
1379
ErrCode Lerc::FilterNoDataAndNaN(std::vector<T>& dataBuffer, std::vector<Byte>& maskBuffer, int nDepth, int nCols, int nRows,
1380
  double& maxZError, bool bPassNoDataValue, double& noDataValue, bool& bModifiedMask, bool& bNeedNoData, bool& bIsFltDblAllInt,
1381
  double& minValA, double& maxValA)
1382
0
{
1383
0
  if (nDepth <= 0 || nCols <= 0 || nRows <= 0 || maxZError < 0)
1384
0
    return ErrCode::WrongParam;
1385
1386
0
  if ((dataBuffer.size() != (size_t)nDepth * nCols * nRows) || (maskBuffer.size() != (size_t)nCols * nRows))
1387
0
    return ErrCode::Failed;
1388
1389
0
  if (typeid(T) != typeid(double) && typeid(T) != typeid(float))    // only for float or double
1390
0
    return ErrCode::Failed;
1391
1392
0
  bModifiedMask = false;
1393
0
  bNeedNoData = false;
1394
0
  bIsFltDblAllInt = false;
1395
1396
0
  bool bHasNoDataValuesLeft = false;
1397
0
  bool bIsFloat4 = (typeid(T) == typeid(float));
1398
0
  bool bAllInt = true;
1399
0
  bool bHasNaN = false;
1400
1401
0
  T origNoData(0);
1402
1403
0
  if (bPassNoDataValue)
1404
0
  {
1405
0
    if (bIsFloat4 && (noDataValue < -FLT_MAX || noDataValue > FLT_MAX))
1406
0
      return ErrCode::WrongParam;
1407
1408
0
    origNoData = (T)noDataValue;
1409
0
  }
1410
0
  else
1411
0
    origNoData = (T)(bIsFloat4 ? -FLT_MAX : -DBL_MAX);
1412
1413
  // only treat int values as int's if within this range, incl orig noData
1414
0
  const double lowIntLimit = (double)(bIsFloat4 ? -((long)1 << 23) : -((int64_t)1 << 53));
1415
0
  const double highIntLimit = (double)(bIsFloat4 ? ((long)1 << 23) : ((int64_t)1 << 53));
1416
1417
0
  double minVal = DBL_MAX;
1418
0
  double maxVal = -DBL_MAX;
1419
1420
  // check for NaN or noData in valid pixels
1421
0
  for (int k = 0, i = 0; i < nRows; i++)
1422
0
  {
1423
0
    T* rowArr = &(dataBuffer[(size_t)i * nCols * nDepth]);
1424
1425
0
    for (int n = 0, j = 0; j < nCols; j++, k++, n += nDepth)
1426
0
      if (maskBuffer[k])
1427
0
      {
1428
0
        int cntInvalidValues = 0;
1429
1430
0
        for (int m = 0; m < nDepth; m++)
1431
0
        {
1432
0
          T& zVal = rowArr[n + m];
1433
1434
0
          if (std::isnan((double)zVal))
1435
0
          {
1436
0
            bHasNaN = true;
1437
0
            cntInvalidValues++;
1438
1439
0
            if (bPassNoDataValue && nDepth > 1)
1440
0
              zVal = origNoData;    // replace NaN
1441
0
            else if (nDepth == 1)
1442
0
              zVal = 0;
1443
0
          }
1444
0
          else if (bPassNoDataValue && zVal == origNoData)
1445
0
          {
1446
0
            cntInvalidValues++;
1447
0
          }
1448
0
          else
1449
0
          {
1450
0
            if (zVal < minVal)
1451
0
              minVal = zVal;
1452
0
            if (zVal > maxVal)
1453
0
              maxVal = zVal;
1454
1455
0
            if (bAllInt && !IsInt(zVal))
1456
0
              bAllInt = false;
1457
0
          }
1458
0
        }
1459
1460
0
        if (cntInvalidValues == nDepth)
1461
0
        {
1462
0
          maskBuffer[k] = 0;
1463
0
          bModifiedMask = true;
1464
0
        }
1465
0
        else if (cntInvalidValues > 0)    // found mix of valid and invalid values at the same pixel
1466
0
          bHasNoDataValuesLeft = true;
1467
0
      }
1468
0
  }
1469
1470
0
  if (minVal == DBL_MAX && maxVal == -DBL_MAX)    // if the tile has no valid data
1471
0
  {
1472
0
    minValA = maxValA = 0;
1473
0
    maxZError = 0;
1474
0
    return ErrCode::Ok;
1475
0
  }
1476
1477
0
  minValA = minVal;
1478
0
  maxValA = maxVal;
1479
0
  bNeedNoData = bHasNoDataValuesLeft;
1480
1481
0
  if (bHasNaN && nDepth > 1 && bHasNoDataValuesLeft && !bPassNoDataValue)
1482
0
  {
1483
0
    return ErrCode::NaN;    // Lerc cannot handle this case, cannot pick a noData value on the tile level
1484
0
  }
1485
1486
  // now NaN's are gone, either moved to the mask or replaced by noData value
1487
1488
0
  double maxZErrL = maxZError;
1489
1490
0
  if (bAllInt)
1491
0
  {
1492
0
    bAllInt &= (minVal >= lowIntLimit) && (minVal <= highIntLimit)
1493
0
      && (maxVal >= lowIntLimit) && (maxVal <= highIntLimit);
1494
1495
0
    if (bHasNoDataValuesLeft)
1496
0
      bAllInt &= IsInt(origNoData) && (origNoData >= lowIntLimit) && (origNoData <= highIntLimit);
1497
1498
0
    if (bAllInt)
1499
0
      maxZErrL = (std::max)(0.5, floor(maxZError));    // same mapping for int types as in Lerc2.cpp
1500
0
  }
1501
1502
0
  bIsFltDblAllInt = bAllInt;
1503
1504
0
  if (maxZErrL == 0)    // if flt lossless, we are done
1505
0
    return ErrCode::Ok;
1506
1507
0
  if (bPassNoDataValue)
1508
0
  {
1509
    // check the orig noData value is far enough away from the valid range
1510
0
    double dist = bAllInt ? floor(maxZErrL) : 2 * maxZErrL;
1511
1512
0
    if ((origNoData >= minVal - dist) && (origNoData <= maxVal + dist))
1513
0
    {
1514
0
      maxZError = bAllInt ? 0.5 : 0;    // fall back to lossless
1515
0
      return ErrCode::Ok;
1516
0
    }
1517
0
  }
1518
1519
0
  if (bHasNoDataValuesLeft)    // try to remap noData to new noData just below the global minimum
1520
0
  {
1521
0
    T remapVal = origNoData;
1522
0
    bool bRemapNoData = FindNewNoDataBelowValidMin(minVal, maxZErrL, bAllInt, lowIntLimit, remapVal);
1523
1524
0
    if (bRemapNoData)
1525
0
    {
1526
0
      if (remapVal != origNoData)
1527
0
      {
1528
0
        for (int k = 0, i = 0; i < nRows; i++)
1529
0
        {
1530
0
          T* rowArr = &(dataBuffer[(size_t)i * nCols * nDepth]);
1531
1532
0
          for (int n = 0, j = 0; j < nCols; j++, k++, n += nDepth)
1533
0
            if (maskBuffer[k])
1534
0
              for (int m = 0; m < nDepth; m++)
1535
0
                if (rowArr[n + m] == origNoData)
1536
0
                  rowArr[n + m] = remapVal;
1537
0
        }
1538
1539
0
        noDataValue = remapVal;
1540
0
      }
1541
0
    }
1542
0
    else if ((double)origNoData >= minVal)    // sufficient distance of origNoData to valid range has been checked above
1543
0
    {
1544
0
      maxZErrL = bAllInt ? 0.5 : 0;    // need lossless if noData cannot be mapped below valid range
1545
0
    }
1546
0
  }
1547
1548
0
  if (maxZError != maxZErrL)
1549
0
    maxZError = maxZErrL;
1550
1551
0
  return ErrCode::Ok;
1552
0
}
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<signed char>(std::__1::vector<signed char, std::__1::allocator<signed char> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<unsigned char>(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<short>(std::__1::vector<short, std::__1::allocator<short> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<unsigned short>(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<int>(std::__1::vector<int, std::__1::allocator<int> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<float>(std::__1::vector<float, std::__1::allocator<float> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&)
Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<double>(std::__1::vector<double, std::__1::allocator<double> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&)
1553
1554
// -------------------------------------------------------------------------- ;
1555
1556
template<class T>
1557
bool Lerc::FindNewNoDataBelowValidMin(double minVal, double maxZErr, bool bAllInt, double lowIntLimit, T& newNoDataVal)
1558
0
{
1559
0
  if (bAllInt)
1560
0
  {
1561
0
    std::vector<T> noDataCandVec;
1562
1563
0
    { // collect dist candidates
1564
0
      std::vector<double> distCandVec = { 4 * maxZErr, 1, 10, 100, 1000, 10000 };    // only int candidates
1565
1566
0
      for (double dist : distCandVec)
1567
0
        noDataCandVec.push_back((T)(minVal - dist));
1568
1569
0
      double candForLargeMinVal = (minVal > 0 ? floor(minVal / 2) : minVal * 2);    // also int
1570
0
      noDataCandVec.push_back((T)candForLargeMinVal);
1571
0
    }
1572
1573
    // sort them in descending order
1574
0
    std::sort(noDataCandVec.begin(), noDataCandVec.end(), std::greater<double>());
1575
1576
    // take the first one that satisfies the condition
1577
0
    for (T noDataVal : noDataCandVec)
1578
0
    {
1579
0
      if ((noDataVal > (T)lowIntLimit) && (noDataVal < (T)(minVal - 2 * maxZErr)) && IsInt(noDataVal))
1580
0
      {
1581
0
        newNoDataVal = noDataVal;
1582
0
        return true;
1583
0
      }
1584
0
    }
1585
0
  }
1586
0
  else
1587
0
  {
1588
0
    std::vector<T> noDataCandVec;
1589
1590
0
    { // dist candidates
1591
0
      std::vector<double> distCandVec = { 4 * maxZErr, 0.0001, 0.001, 0.01, 0.1, 1, 10, 100, 1000, 10000 };
1592
1593
0
      for (double dist : distCandVec)
1594
0
        noDataCandVec.push_back((T)(minVal - dist));
1595
1596
0
      double candForLargeMinVal = (minVal > 0 ? minVal / 2 : minVal * 2);
1597
0
      noDataCandVec.push_back((T)candForLargeMinVal);
1598
0
    }
1599
1600
    // sort them in descending order
1601
0
    std::sort(noDataCandVec.begin(), noDataCandVec.end(), std::greater<double>());
1602
1603
0
    bool bIsFloat4 = (typeid(T) == typeid(float));
1604
0
    T lowestVal = (T)(bIsFloat4 ? -FLT_MAX : -DBL_MAX);
1605
1606
    // take the first one that satisfies the condition
1607
0
    for (T noDataVal : noDataCandVec)
1608
0
    {
1609
0
      if ((noDataVal > lowestVal) && (noDataVal < (T)(minVal - 2 * maxZErr)))
1610
0
      {
1611
0
        newNoDataVal = noDataVal;
1612
0
        return true;
1613
0
      }
1614
0
    }
1615
0
  }
1616
1617
0
  return false;
1618
0
}
Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<signed char>(double, double, bool, double, signed char&)
Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<unsigned char>(double, double, bool, double, unsigned char&)
Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<short>(double, double, bool, double, short&)
Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<unsigned short>(double, double, bool, double, unsigned short&)
Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<int>(double, double, bool, double, int&)
Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<unsigned int>(double, double, bool, double, unsigned int&)
Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<float>(double, double, bool, double, float&)
Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<double>(double, double, bool, double, double&)
1619
1620
// -------------------------------------------------------------------------- ;
1621
1622
bool Lerc::CheckDimensions(int nDepth, int nCols, int nRows, size_t sizeOfDataElement)
1623
0
{
1624
  // here we guard against too large input dimensions that might cause a possible int32 overflow later;
1625
  // we limit the size of input data per band to 2 GB, so any product [height * width * depth * sizeof(data element)] <= INT_MAX;
1626
  // (see the corresponding size and dimension checks in Lerc2::ReadHeader(...));
1627
1628
0
  if (nDepth <= 0 || nCols <= 0 || nRows <= 0)
1629
0
    return false;
1630
1631
0
  const uint64_t numPixel = (uint64_t)nRows * nCols;
1632
0
  const uint64_t maxint32 = (uint64_t)INT_MAX;
1633
0
  const uint64_t nbpp = sizeOfDataElement;
1634
1635
0
  if (numPixel > maxint32 || nbpp > maxint32 || nbpp * nDepth > maxint32 || nbpp * nDepth * numPixel > maxint32)
1636
0
    return false;
1637
1638
0
  return true;
1639
0
}
1640
1641
// -------------------------------------------------------------------------- ;