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 #include "Defines.h"
25 #include "Lerc.h"
26 #include "Lerc2.h"
27 #include <typeinfo>
28 #include <limits>
29 
30 #ifdef HAVE_LERC1_DECODE
31 #include "Lerc1Decode/CntZImage.h"
32 #endif
33 
34 using namespace std;
35 USING_NAMESPACE_LERC
36 
37 // -------------------------------------------------------------------------- ;
38 
ComputeCompressedSize(const void * pData,int version,DataType dt,int nDim,int nCols,int nRows,int nBands,int nMasks,const Byte * pValidBytes,double maxZErr,unsigned int & numBytesNeeded)39 ErrCode Lerc::ComputeCompressedSize(const void* pData, int version, DataType dt, int nDim, int nCols, int nRows, int nBands,
40   int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded)
41 {
42   switch (dt)
43   {
44   case DT_Char:    return ComputeCompressedSizeTempl((const signed char*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
45   case DT_Byte:    return ComputeCompressedSizeTempl((const Byte*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
46   case DT_Short:   return ComputeCompressedSizeTempl((const short*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
47   case DT_UShort:  return ComputeCompressedSizeTempl((const unsigned short*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
48   case DT_Int:     return ComputeCompressedSizeTempl((const int*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
49   case DT_UInt:    return ComputeCompressedSizeTempl((const unsigned int*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
50   case DT_Float:   return ComputeCompressedSizeTempl((const float*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
51   case DT_Double:  return ComputeCompressedSizeTempl((const double*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
52 
53   default:
54     return ErrCode::WrongParam;
55   }
56 }
57 
58 // -------------------------------------------------------------------------- ;
59 
Encode(const void * pData,int version,DataType dt,int nDim,int nCols,int nRows,int nBands,int nMasks,const Byte * pValidBytes,double maxZErr,Byte * pBuffer,unsigned int numBytesBuffer,unsigned int & numBytesWritten)60 ErrCode Lerc::Encode(const void* pData, int version, DataType dt, int nDim, int nCols, int nRows, int nBands,
61   int nMasks, const Byte* pValidBytes, double maxZErr, Byte* pBuffer, unsigned int numBytesBuffer, unsigned int& numBytesWritten)
62 {
63   switch (dt)
64   {
65   case DT_Char:    return EncodeTempl((const signed char*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
66   case DT_Byte:    return EncodeTempl((const Byte*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
67   case DT_Short:   return EncodeTempl((const short*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
68   case DT_UShort:  return EncodeTempl((const unsigned short*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
69   case DT_Int:     return EncodeTempl((const int*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
70   case DT_UInt:    return EncodeTempl((const unsigned int*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
71   case DT_Float:   return EncodeTempl((const float*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
72   case DT_Double:  return EncodeTempl((const double*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
73 
74   default:
75     return ErrCode::WrongParam;
76   }
77 }
78 
79 // -------------------------------------------------------------------------- ;
80 
GetLercInfo(const Byte * pLercBlob,unsigned int numBytesBlob,struct LercInfo & lercInfo)81 ErrCode Lerc::GetLercInfo(const Byte* pLercBlob, unsigned int numBytesBlob, struct LercInfo& lercInfo)
82 {
83   lercInfo.RawInit();
84 
85   // first try Lerc2
86   struct Lerc2::HeaderInfo lerc2Info;
87   bool bHasMask = false;
88   int nMasks = 0;
89 
90   if (Lerc2::GetHeaderInfo(pLercBlob, numBytesBlob, lerc2Info, bHasMask))
91   {
92     lercInfo.version = lerc2Info.version;
93     lercInfo.nDim = lerc2Info.nDim;
94     lercInfo.nCols = lerc2Info.nCols;
95     lercInfo.nRows = lerc2Info.nRows;
96     lercInfo.numValidPixel = lerc2Info.numValidPixel;    // for 1st band
97     lercInfo.nBands = 1;
98     lercInfo.blobSize = lerc2Info.blobSize;
99     lercInfo.dt = (DataType)lerc2Info.dt;
100     lercInfo.zMin = lerc2Info.zMin;
101     lercInfo.zMax = lerc2Info.zMax;
102     lercInfo.maxZError = lerc2Info.maxZError;
103 
104     if (bHasMask || lercInfo.numValidPixel == 0)
105       nMasks = 1;
106 
107     if (lercInfo.blobSize > (int)numBytesBlob)    // truncated blob, we won't be able to read this band
108       return ErrCode::BufferTooSmall;
109 
110     struct Lerc2::HeaderInfo hdInfo;
111     while (Lerc2::GetHeaderInfo(pLercBlob + lercInfo.blobSize, numBytesBlob - lercInfo.blobSize, hdInfo, bHasMask))
112     {
113       if (hdInfo.nDim != lercInfo.nDim
114        || hdInfo.nCols != lercInfo.nCols
115        || hdInfo.nRows != lercInfo.nRows
116        || (int)hdInfo.dt != (int)lercInfo.dt)
117        //|| hdInfo.maxZError != lercInfo.maxZError)    // with the new bitplane compression, maxZError can vary between bands
118       {
119         return ErrCode::Failed;
120       }
121 
122       if (bHasMask || hdInfo.numValidPixel != lercInfo.numValidPixel)    // support mask per band
123         nMasks = 2;
124 
125       if (lercInfo.blobSize > std::numeric_limits<int>::max() - hdInfo.blobSize)
126         return ErrCode::Failed;
127 
128       lercInfo.blobSize += hdInfo.blobSize;
129 
130       if (lercInfo.blobSize > (int)numBytesBlob)    // truncated blob, we won't be able to read this band
131         return ErrCode::BufferTooSmall;
132 
133       lercInfo.nBands++;
134       lercInfo.zMin = min(lercInfo.zMin, hdInfo.zMin);
135       lercInfo.zMax = max(lercInfo.zMax, hdInfo.zMax);
136       lercInfo.maxZError = max(lercInfo.maxZError, hdInfo.maxZError);  // with the new bitplane compression, maxZError can vary between bands
137     }
138 
139     lercInfo.nMasks = nMasks > 1 ? lercInfo.nBands : nMasks;
140 
141     return ErrCode::Ok;
142   }
143 
144 
145 #ifdef HAVE_LERC1_DECODE
146   // only if not Lerc2, try legacy Lerc1
147   unsigned int numBytesHeaderBand0 = CntZImage::computeNumBytesNeededToReadHeader(false);
148   unsigned int numBytesHeaderBand1 = CntZImage::computeNumBytesNeededToReadHeader(true);
149   Byte* pByte = const_cast<Byte*>(pLercBlob);
150 
151   lercInfo.zMin =  FLT_MAX;
152   lercInfo.zMax = -FLT_MAX;
153 
154   CntZImage cntZImg;
155   if (numBytesHeaderBand0 <= numBytesBlob && cntZImg.read(&pByte, 1e12, true))    // read just the header
156   {
157     size_t nBytesRead = pByte - pLercBlob;
158     size_t nBytesNeeded = 10 + 4 * sizeof(int) + 1 * sizeof(double);
159 
160     if (nBytesRead < nBytesNeeded)
161       return ErrCode::Failed;
162 
163     Byte* ptr = const_cast<Byte*>(pLercBlob);
164     ptr += 10 + 2 * sizeof(int);
165 
166     int height(0), width(0);
167     memcpy(&height, ptr, sizeof(int));  ptr += sizeof(int);
168     memcpy(&width,  ptr, sizeof(int));  ptr += sizeof(int);
169     double maxZErrorInFile(0);
170     memcpy(&maxZErrorInFile, ptr, sizeof(double));
171 
172     if (height > 20000 || width > 20000)    // guard against bogus numbers; size limitation for old Lerc1
173       return ErrCode::Failed;
174 
175     lercInfo.nDim = 1;
176     lercInfo.nCols = width;
177     lercInfo.nRows = height;
178     lercInfo.dt = Lerc::DT_Float;
179     lercInfo.maxZError = maxZErrorInFile;
180 
181     Byte* pByte = const_cast<Byte*>(pLercBlob);
182     bool onlyZPart = false;
183 
184     while (lercInfo.blobSize + numBytesHeaderBand1 < numBytesBlob)    // means there could be another band
185     {
186       if (!cntZImg.read(&pByte, 1e12, false, onlyZPart))
187         return (lercInfo.nBands > 0) ? ErrCode::Ok : ErrCode::Failed;    // no other band, we are done
188 
189       onlyZPart = true;
190 
191       lercInfo.nBands++;
192       lercInfo.blobSize = (int)(pByte - pLercBlob);
193 
194       // now that we have decoded it, we can go the extra mile and collect some extra info
195       int numValidPixels = 0;
196       float zMin =  FLT_MAX;
197       float zMax = -FLT_MAX;
198 
199       for (int i = 0; i < height; i++)
200       {
201         for (int j = 0; j < width; j++)
202           if (cntZImg(i, j).cnt > 0)
203           {
204             numValidPixels++;
205             float z = cntZImg(i, j).z;
206             zMax = max(zMax, z);
207             zMin = min(zMin, z);
208           }
209       }
210 
211       lercInfo.numValidPixel = numValidPixels;
212       lercInfo.zMin = std::min(lercInfo.zMin, (double)zMin);
213       lercInfo.zMax = std::max(lercInfo.zMax, (double)zMax);
214       lercInfo.nMasks = numValidPixels < width * height ? 1 : 0;
215     }
216 
217     return ErrCode::Ok;
218   }
219 #endif
220 
221   return ErrCode::Failed;
222 }
223 
224 // -------------------------------------------------------------------------- ;
225 
Decode(const Byte * pLercBlob,unsigned int numBytesBlob,int nMasks,Byte * pValidBytes,int nDim,int nCols,int nRows,int nBands,DataType dt,void * pData)226 ErrCode Lerc::Decode(const Byte* pLercBlob, unsigned int numBytesBlob, int nMasks, Byte* pValidBytes,
227   int nDim, int nCols, int nRows, int nBands, DataType dt, void* pData)
228 {
229   switch (dt)
230   {
231   case DT_Char:    return DecodeTempl((signed char*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
232   case DT_Byte:    return DecodeTempl((Byte*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
233   case DT_Short:   return DecodeTempl((short*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
234   case DT_UShort:  return DecodeTempl((unsigned short*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
235   case DT_Int:     return DecodeTempl((int*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
236   case DT_UInt:    return DecodeTempl((unsigned int*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
237   case DT_Float:   return DecodeTempl((float*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
238   case DT_Double:  return DecodeTempl((double*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
239 
240   default:
241     return ErrCode::WrongParam;
242   }
243 }
244 
245 // -------------------------------------------------------------------------- ;
246 
ConvertToDouble(const void * pDataIn,DataType dt,size_t nDataValues,double * pDataOut)247 ErrCode Lerc::ConvertToDouble(const void* pDataIn, DataType dt, size_t nDataValues, double* pDataOut)
248 {
249   switch (dt)
250   {
251   case DT_Char:    return ConvertToDoubleTempl((const signed char*)pDataIn, nDataValues, pDataOut);
252   case DT_Byte:    return ConvertToDoubleTempl((const Byte*)pDataIn, nDataValues, pDataOut);
253   case DT_Short:   return ConvertToDoubleTempl((const short*)pDataIn, nDataValues, pDataOut);
254   case DT_UShort:  return ConvertToDoubleTempl((const unsigned short*)pDataIn, nDataValues, pDataOut);
255   case DT_Int:     return ConvertToDoubleTempl((const int*)pDataIn, nDataValues, pDataOut);
256   case DT_UInt:    return ConvertToDoubleTempl((const unsigned int*)pDataIn, nDataValues, pDataOut);
257   case DT_Float:   return ConvertToDoubleTempl((const float*)pDataIn, nDataValues, pDataOut);
258   //case DT_Double:  no convert double to double
259 
260   default:
261     return ErrCode::WrongParam;
262   }
263 }
264 
265 // -------------------------------------------------------------------------- ;
266 // -------------------------------------------------------------------------- ;
267 
268 template<class T>
ComputeCompressedSizeTempl(const T * pData,int version,int nDim,int nCols,int nRows,int nBands,int nMasks,const Byte * pValidBytes,double maxZErr,unsigned int & numBytesNeeded)269 ErrCode Lerc::ComputeCompressedSizeTempl(const T* pData, int version, int nDim, int nCols, int nRows, int nBands,
270   int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded)
271 {
272   numBytesNeeded = 0;
273 
274   if (!pData || nDim <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || maxZErr < 0)
275     return ErrCode::WrongParam;
276 
277   if (!(nMasks == 0 || nMasks == 1 || nMasks == nBands) || (nMasks > 0 && !pValidBytes))
278     return ErrCode::WrongParam;
279 
280   unsigned int numBytesWritten = 0;
281 
282   return EncodeInternal(pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr,
283     numBytesNeeded, nullptr, 0, numBytesWritten);
284 }
285 
286 // -------------------------------------------------------------------------- ;
287 
288 template<class T>
EncodeTempl(const T * pData,int version,int nDim,int nCols,int nRows,int nBands,int nMasks,const Byte * pValidBytes,double maxZErr,Byte * pBuffer,unsigned int numBytesBuffer,unsigned int & numBytesWritten)289 ErrCode Lerc::EncodeTempl(const T* pData, int version, int nDim, int nCols, int nRows, int nBands,
290   int nMasks, const Byte* pValidBytes, double maxZErr, Byte* pBuffer, unsigned int numBytesBuffer, unsigned int& numBytesWritten)
291 {
292   numBytesWritten = 0;
293 
294   if (!pData || nDim <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || maxZErr < 0 || !pBuffer || !numBytesBuffer)
295     return ErrCode::WrongParam;
296 
297   if (!(nMasks == 0 || nMasks == 1 || nMasks == nBands) || (nMasks > 0 && !pValidBytes))
298     return ErrCode::WrongParam;
299 
300   unsigned int numBytesNeeded = 0;
301 
302   return EncodeInternal(pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr,
303     numBytesNeeded, pBuffer, numBytesBuffer, numBytesWritten);
304 }
305 
306 // -------------------------------------------------------------------------- ;
307 
308 template<class T>
DecodeTempl(T * pData,const Byte * pLercBlob,unsigned int numBytesBlob,int nDim,int nCols,int nRows,int nBands,int nMasks,Byte * pValidBytes)309 ErrCode Lerc::DecodeTempl(T* pData, const Byte* pLercBlob, unsigned int numBytesBlob,
310   int nDim, int nCols, int nRows, int nBands, int nMasks, Byte* pValidBytes)
311 {
312   if (!pData || nDim <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || !pLercBlob || !numBytesBlob)
313     return ErrCode::WrongParam;
314 
315   if (!(nMasks == 0 || nMasks == 1 || nMasks == nBands) || (nMasks > 0 && !pValidBytes))
316     return ErrCode::WrongParam;
317 
318   const Byte* pByte = pLercBlob;
319   Lerc2::HeaderInfo hdInfo;
320   bool bHasMask = false;
321 
322   if (Lerc2::GetHeaderInfo(pByte, numBytesBlob, hdInfo, bHasMask) && hdInfo.version >= 1)    // if Lerc2
323   {
324     LercInfo lercInfo;
325     ErrCode errCode = GetLercInfo(pLercBlob, numBytesBlob, lercInfo);    // fast for Lerc2
326     if (errCode != ErrCode::Ok)
327       return errCode;
328 
329     const int nMasksEncoded = lercInfo.nMasks;    // 0, 1, or nBands
330 
331     if (nMasks < nMasksEncoded)
332       return ErrCode::WrongParam;
333 
334     size_t nBytesRemaining = numBytesBlob;
335     Lerc2 lerc2;
336     BitMask bitMask;
337 
338     for (int iBand = 0; iBand < nBands; iBand++)
339     {
340       if (((size_t)(pByte - pLercBlob) < numBytesBlob) && Lerc2::GetHeaderInfo(pByte, nBytesRemaining, hdInfo, bHasMask))
341       {
342         if (hdInfo.nDim != nDim || hdInfo.nCols != nCols || hdInfo.nRows != nRows)
343           return ErrCode::Failed;
344 
345         if ((pByte - pLercBlob) + (size_t)hdInfo.blobSize > numBytesBlob)
346           return ErrCode::BufferTooSmall;
347 
348         size_t nPix = (size_t)iBand * nRows * nCols;
349         T* arr = pData + nPix * nDim;
350 
351         bool bGetMask = iBand < nMasks;
352 
353         if (bGetMask && !bitMask.SetSize(nCols, nRows))
354           return ErrCode::Failed;
355 
356         if (!lerc2.Decode(&pByte, nBytesRemaining, arr, bGetMask ? bitMask.Bits() : nullptr))
357           return ErrCode::Failed;
358 
359         if (bGetMask && !Convert(bitMask, pValidBytes + nPix))
360           return ErrCode::Failed;
361       }
362     }  // iBand
363   }  // Lerc2
364 
365   else    // might be old Lerc1
366   {
367 #ifdef HAVE_LERC1_DECODE
368     unsigned int numBytesHeaderBand0 = CntZImage::computeNumBytesNeededToReadHeader(false);
369     unsigned int numBytesHeaderBand1 = CntZImage::computeNumBytesNeededToReadHeader(true);
370     Byte* pByte1 = const_cast<Byte*>(pLercBlob);
371     CntZImage zImg;
372 
373     for (int iBand = 0; iBand < nBands; iBand++)
374     {
375       unsigned int numBytesHeader = iBand == 0 ? numBytesHeaderBand0 : numBytesHeaderBand1;
376       if ((size_t)(pByte - pLercBlob) + numBytesHeader > numBytesBlob)
377         return ErrCode::BufferTooSmall;
378 
379       bool onlyZPart = iBand > 0;
380       if (!zImg.read(&pByte1, 1e12, false, onlyZPart))
381         return ErrCode::Failed;
382 
383       if (zImg.getWidth() != nCols || zImg.getHeight() != nRows)
384         return ErrCode::Failed;
385 
386       size_t nPix = (size_t)iBand * nRows * nCols;
387       T* arr = pData + nPix;
388       Byte* pDst = iBand < nMasks ? pValidBytes + nPix : nullptr;
389 
390       if (!Convert(zImg, arr, pDst, iBand == 0))
391         return ErrCode::Failed;
392     }
393 #else
394     return ErrCode::Failed;
395 #endif
396   }
397 
398   return ErrCode::Ok;
399 }
400 
401 // -------------------------------------------------------------------------- ;
402 // -------------------------------------------------------------------------- ;
403 
404 template<class T>
EncodeInternal(const T * pData,int version,int nDim,int nCols,int nRows,int nBands,int nMasks,const Byte * pValidBytes,double maxZErr,unsigned int & numBytesNeeded,Byte * pBuffer,unsigned int numBytesBuffer,unsigned int & numBytesWritten)405 ErrCode Lerc::EncodeInternal(const T* pData, int version, int nDim, int nCols, int nRows, int nBands,
406   int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded,
407   Byte* pBuffer, unsigned int numBytesBuffer, unsigned int& numBytesWritten)
408 {
409   numBytesNeeded = 0;
410   numBytesWritten = 0;
411 
412   Lerc2 lerc2;
413   if (version >= 0 && !lerc2.SetEncoderToOldVersion(version))
414     return ErrCode::WrongParam;
415 
416   Byte* pDst = pBuffer;
417 
418   const size_t nPix = (size_t)nCols * nRows;
419   const size_t nElem = nPix * nDim;
420 
421   const Byte* pPrevByteMask = nullptr;
422   vector<T> dataBuffer;
423   vector<Byte> maskBuffer, prevMaskBuffer;
424   BitMask bitMask;
425 
426   // loop over the bands
427   for (int iBand = 0; iBand < nBands; iBand++)
428   {
429     bool bEncMsk = (iBand == 0);
430 
431     // using the proper section of valid bytes, check this band for NaN
432     const T* arr = pData + nElem * iBand;
433     const Byte* pByteMask = (nMasks > 0) ? (pValidBytes + ((nMasks > 1) ? nPix * iBand : 0)) : nullptr;
434 
435     ErrCode errCode = CheckForNaN(arr, nDim, nCols, nRows, pByteMask);
436     if (errCode != ErrCode::Ok && errCode != ErrCode::NaN)
437       return errCode;
438 
439     if (errCode == ErrCode::NaN)    // found NaN values
440     {
441       if (!Resize(dataBuffer, nElem) || !Resize(maskBuffer, nPix))
442         return ErrCode::Failed;
443 
444       memcpy(&dataBuffer[0], arr, nElem * sizeof(T));
445       pByteMask ? memcpy(&maskBuffer[0], pByteMask, nPix) : memset(&maskBuffer[0], 1, nPix);
446 
447       if (!ReplaceNaNValues(dataBuffer, maskBuffer, nDim, nCols, nRows))
448         return ErrCode::Failed;
449 
450       if (iBand > 0 && MasksDiffer(&maskBuffer[0], pPrevByteMask, nPix))
451         bEncMsk = true;
452 
453       if (iBand < nBands - 1)
454       {
455         // keep current mask as new previous band mask
456         prevMaskBuffer = maskBuffer;
457         pPrevByteMask = &prevMaskBuffer[0];
458       }
459 
460       arr = &dataBuffer[0];
461       pByteMask = &maskBuffer[0];
462     }
463 
464     else    // no NaN in this band, the common case
465     {
466       if (iBand > 0 && MasksDiffer(pByteMask, pPrevByteMask, nPix))
467         bEncMsk = true;
468 
469       pPrevByteMask = pByteMask;
470     }
471 
472     if (bEncMsk)
473     {
474       if (pByteMask && !Convert(pByteMask, nCols, nRows, bitMask))
475         return ErrCode::Failed;
476 
477       if (!lerc2.Set(nDim, nCols, nRows, pByteMask ? bitMask.Bits() : nullptr))
478         return ErrCode::Failed;
479     }
480 
481     unsigned int nBytes = lerc2.ComputeNumBytesNeededToWrite(arr, maxZErr, bEncMsk);
482     if (nBytes <= 0)
483       return ErrCode::Failed;
484 
485     numBytesNeeded += nBytes;
486 
487     if (pBuffer)
488     {
489       if ((size_t)(pDst - pBuffer) + nBytes > numBytesBuffer)    // check we have enough space left
490         return ErrCode::BufferTooSmall;
491 
492       if (!lerc2.Encode(arr, &pDst))
493         return ErrCode::Failed;
494     }
495   }
496 
497   numBytesWritten = (unsigned int)(pDst - pBuffer);
498   return ErrCode::Ok;
499 }
500 
501 // -------------------------------------------------------------------------- ;
502 
503 #ifdef HAVE_LERC1_DECODE
504 template<class T>
Convert(const CntZImage & zImg,T * arr,Byte * pByteMask,bool bMustFillMask)505 bool Lerc::Convert(const CntZImage& zImg, T* arr, Byte* pByteMask, bool bMustFillMask)
506 {
507   if (!arr || !zImg.getSize())
508     return false;
509 
510   const bool fltPnt = (typeid(*arr) == typeid(double)) || (typeid(*arr) == typeid(float));
511 
512   int h = zImg.getHeight();
513   int w = zImg.getWidth();
514 
515   const CntZ* srcPtr = zImg.getData();
516   T* dstPtr = arr;
517   int num = w * h;
518 
519   if (pByteMask)
520   {
521     memset(pByteMask, 0, num);
522 
523     for (int k = 0; k < num; k++)
524     {
525       if (srcPtr->cnt > 0)
526       {
527         *dstPtr = fltPnt ? (T)srcPtr->z : (T)floor(srcPtr->z + 0.5);
528         pByteMask[k] = 1;
529       }
530 
531       srcPtr++;
532       dstPtr++;
533     }
534   }
535   else
536   {
537     for (int k = 0; k < num; k++)
538     {
539       if (srcPtr->cnt > 0)
540       {
541         *dstPtr = fltPnt ? (T)srcPtr->z : (T)floor(srcPtr->z + 0.5);
542       }
543       else if (bMustFillMask)
544         return false;
545 
546       srcPtr++;
547       dstPtr++;
548     }
549   }
550 
551   return true;
552 }
553 #endif
554 
555 // -------------------------------------------------------------------------- ;
556 
557 template<class T>
ConvertToDoubleTempl(const T * pDataIn,size_t nDataValues,double * pDataOut)558 ErrCode Lerc::ConvertToDoubleTempl(const T* pDataIn, size_t nDataValues, double* pDataOut)
559 {
560   if (!pDataIn || !nDataValues || !pDataOut)
561     return ErrCode::WrongParam;
562 
563   for (size_t k = 0; k < nDataValues; k++)
564     pDataOut[k] = pDataIn[k];
565 
566   return ErrCode::Ok;
567 }
568 
569 // -------------------------------------------------------------------------- ;
570 
CheckForNaN(const T * arr,int nDim,int nCols,int nRows,const Byte * pByteMask)571 template<class T> ErrCode Lerc::CheckForNaN(const T* arr, int nDim, int nCols, int nRows, const Byte* pByteMask)
572 {
573   if (!arr || nDim <= 0 || nCols <= 0 || nRows <= 0)
574     return ErrCode::WrongParam;
575 
576   if (typeid(T) != typeid(double) && typeid(T) != typeid(float))
577     return ErrCode::Ok;
578 
579   for (size_t k = 0, i = 0; i < (size_t)nRows; i++)
580   {
581     bool bFoundNaN = false;
582     const T* rowArr = &(arr[i * nCols * nDim]);
583 
584     if (!pByteMask)    // all valid
585     {
586       size_t num = (size_t)nCols * nDim;
587       for (size_t m = 0; m < num; m++)
588         if (std::isnan((double)rowArr[m]))
589           bFoundNaN = true;
590     }
591     else    // not all valid
592     {
593       for (size_t n = 0, j = 0; j < (size_t)nCols; j++, k++, n += nDim)
594         if (pByteMask[k])
595         {
596           for (int m = 0; m < nDim; m++)
597             if (std::isnan((double)rowArr[n + m]))
598               bFoundNaN = true;
599         }
600     }
601 
602     if (bFoundNaN)
603       return ErrCode::NaN;
604   }
605 
606   return ErrCode::Ok;
607 }
608 
609 // -------------------------------------------------------------------------- ;
610 
ReplaceNaNValues(std::vector<T> & dataBuffer,std::vector<Byte> & maskBuffer,int nDim,int nCols,int nRows)611 template<class T> bool Lerc::ReplaceNaNValues(std::vector<T>& dataBuffer, std::vector<Byte>& maskBuffer, int nDim, int nCols, int nRows)
612 {
613   if (nDim <= 0 || nCols <= 0 || nRows <= 0 || dataBuffer.size() != (size_t)nDim * nCols * nRows || maskBuffer.size() != (size_t)nCols * nRows)
614     return false;
615 
616   bool bIsFloat = (typeid(T) == typeid(float));
617   const T noDataValue = (T)(bIsFloat ? -FLT_MAX : -DBL_MAX);
618 
619   for (size_t k = 0, i = 0; i < (size_t)nRows; i++)
620   {
621     T* rowArr = &(dataBuffer[i * nCols * nDim]);
622 
623     for (size_t n = 0, j = 0; j < (size_t)nCols; j++, k++, n += nDim)
624     {
625       if (maskBuffer[k])
626       {
627         int cntNaN = 0;
628 
629         for (int m = 0; m < nDim; m++)
630           if (std::isnan((double)rowArr[n + m]))
631           {
632             cntNaN++;
633             rowArr[n + m] = noDataValue;
634           }
635 
636         if (cntNaN == nDim)
637           maskBuffer[k] = 0;
638       }
639     }
640   }
641 
642   return true;
643 }
644 
645 // -------------------------------------------------------------------------- ;
646 
Resize(std::vector<T> & buffer,size_t nElem)647 template<class T> bool Lerc::Resize(std::vector<T>& buffer, size_t nElem)
648 {
649   try
650   {
651     buffer.resize(nElem);
652   }
653   catch (...)
654   {
655     return false;
656   }
657 
658   return true;
659 }
660 
661 // -------------------------------------------------------------------------- ;
662 
Convert(const Byte * pByteMask,int nCols,int nRows,BitMask & bitMask)663 bool Lerc::Convert(const Byte* pByteMask, int nCols, int nRows, BitMask& bitMask)
664 {
665   if (!pByteMask || nCols <= 0 || nRows <= 0)
666     return false;
667 
668   if (!bitMask.SetSize(nCols, nRows))
669     return false;
670 
671   bitMask.SetAllValid();
672 
673   for (int k = 0, i = 0; i < nRows; i++)
674     for (int j = 0; j < nCols; j++, k++)
675       if (!pByteMask[k])
676         bitMask.SetInvalid(k);
677 
678   return true;
679 }
680 
681 // -------------------------------------------------------------------------- ;
682 
Convert(const BitMask & bitMask,Byte * pByteMask)683 bool Lerc::Convert(const BitMask& bitMask, Byte* pByteMask)
684 {
685   int nCols = bitMask.GetWidth();
686   int nRows = bitMask.GetHeight();
687 
688   if (nCols <= 0 || nRows <= 0 || !pByteMask)
689     return false;
690 
691   memset(pByteMask, 0, (size_t)nCols * nRows);
692 
693   for (int k = 0, i = 0; i < nRows; i++)
694     for (int j = 0; j < nCols; j++, k++)
695       if (bitMask.IsValid(k))
696         pByteMask[k] = 1;
697 
698   return true;
699 }
700 
701 // -------------------------------------------------------------------------- ;
702 
MasksDiffer(const Byte * p0,const Byte * p1,size_t n)703 bool Lerc::MasksDiffer(const Byte* p0, const Byte* p1, size_t n)
704 {
705   if (p0 == p1)
706     return false;
707 
708   if (!p0)    // means all valid
709     return memchr(p1, 0, n);    // any invalid?
710   else if (!p1)
711     return memchr(p0, 0, n);
712   else
713     return memcmp(p0, p1, n);
714 }
715 
716 // -------------------------------------------------------------------------- ;
717 
718