1 /*
2 Copyright 2015 Esri
3 
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8 http://www.apache.org/licenses/LICENSE-2.0
9 
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 
16 A local copy of the license and additional notices are located with the
17 source distribution at:
18 
19 http://github.com/Esri/lerc/
20 
21 Contributors:  Thomas Maurer
22 */
23 
24 #ifndef LERC2_H
25 #define LERC2_H
26 
27 #include <cfloat>
28 #include <cmath>
29 #include <algorithm>
30 #include <string>
31 #include "BitMask.h"
32 #include "BitStuffer2.h"
33 
34 NAMESPACE_LERC_START
35 
36 /**   Lerc2 v1
37  *
38  *    -- allow for lossless compression of all common data types
39  *    -- avoid data type conversions and copies
40  *    -- optimized compression for segmented rasters (10-15x lossless)
41  *    -- micro block is 8x8 fixed, only gets doubled to 16x16 if bit rate < 1 bpp
42  *    -- cnt is replaced by bit mask
43  *    -- Lerc blob header has data range [min, max]
44  *    -- harden consistency checks to detect if the byte blob has been tampered with
45  *    -- drop support for big endian, this is legacy now
46  *
47  *    Lerc2 v2
48  *
49  *    -- add Huffman coding for better lossless compression of 8 bit data types Char, Byte
50  *
51  *    Lerc2 v3
52  *
53  *    -- add checksum for the entire byte blob, for more rigorous detection of compressed data corruption
54  *    -- for the main bit stuffing routine, use an extra uint buffer for guaranteed memory alignment
55  *    -- this also allows to drop the NumExtraBytesToAllocate functions
56  *
57  *    Lerc2 v4
58  *
59  *    -- allow array per pixel, nDim values per pixel. Such as RGB, complex number, or larger arrays per pixel
60  *    -- extend Huffman coding for 8 bit data types from delta only to trying both delta and orig
61  *    -- for integer data types, allow to drop bit planes containing only random noise
62  *
63  *    Lerc2 v5
64  *    -- for float data (as it might be lower precision like %.2f), try raise maxZError if possible w/o extra loss
65  *    -- add delta encoding of a block iDim relative to previous block (iDim - 1)
66  *
67  */
68 
69 class Lerc2
70 {
71 public:
72   Lerc2();
73   Lerc2(int nDim, int nCols, int nRows, const Byte* pMaskBits = nullptr);    // valid / invalid bits as byte array
~Lerc2()74   virtual ~Lerc2()  {}
75 
CurrentVersion()76   static int CurrentVersion() { return 5; }
77 
78   bool SetEncoderToOldVersion(int version);    // call this to encode compatible to an old decoder
79 
80   bool Set(int nDim, int nCols, int nRows, const Byte* pMaskBits = nullptr);
81 
82   template<class T>
83   unsigned int ComputeNumBytesNeededToWrite(const T* arr, double maxZError, bool encodeMask);
84 
85   /// dst buffer already allocated;  byte ptr is moved like a file pointer
86   template<class T>
87   bool Encode(const T* arr, Byte** ppByte);
88 
89   // data types supported by Lerc2
90   enum DataType {DT_Char = 0, DT_Byte, DT_Short, DT_UShort, DT_Int, DT_UInt, DT_Float, DT_Double, DT_Undefined};
91 
92   struct HeaderInfo
93   {
94     int version;
95     unsigned int checksum;
96     int nRows,
97         nCols,
98         nDim,
99         numValidPixel,
100         microBlockSize,
101         blobSize;
102 
103     DataType dt;
104 
105     double  maxZError,
106             zMin,    // if nDim > 1, this is the overall range
107             zMax;
108 
RawInitHeaderInfo109     void RawInit()  { memset(this, 0, sizeof(struct HeaderInfo)); }
110 
TryHuffmanHeaderInfo111     bool TryHuffman() const  { return version > 1 && (dt == DT_Byte || dt == DT_Char) && maxZError == 0.5; }
112   };
113 
114   static bool GetHeaderInfo(const Byte* pByte, size_t nBytesRemaining, struct HeaderInfo& headerInfo, bool& bHasMask);
115 
116   /// dst buffer already allocated;  byte ptr is moved like a file pointer
117   template<class T>
118   bool Decode(const Byte** ppByte, size_t& nBytesRemaining, T* arr, Byte* pMaskBits = nullptr);    // if mask ptr is not 0, mask bits are returned (even if all valid or same as previous)
119 
120 private:
121 
122   enum ImageEncodeMode { IEM_Tiling = 0, IEM_DeltaHuffman, IEM_Huffman };
123   enum BlockEncodeMode { BEM_RawBinary = 0, BEM_BitStuffSimple, BEM_BitStuffLUT };
124 
125   int         m_microBlockSize,
126               m_maxValToQuantize;
127   BitMask     m_bitMask;
128   HeaderInfo  m_headerInfo;
129   BitStuffer2 m_bitStuffer2;
130   bool        m_encodeMask,
131               m_writeDataOneSweep;
132   ImageEncodeMode  m_imageEncodeMode;
133 
134   std::vector<double> m_zMinVec, m_zMaxVec;
135   std::vector<std::pair<unsigned short, unsigned int> > m_huffmanCodes;    // <= 256 codes, 1.5 kB
136 
137 private:
FileKey()138   static std::string FileKey()  { return "Lerc2 "; }
IsLittleEndianSystem()139   static bool IsLittleEndianSystem()  { int n = 1;  return (1 == *((Byte*)&n)) && (4 == sizeof(int)); }
140   void Init();
141 
142   static unsigned int ComputeNumBytesHeaderToWrite(const struct HeaderInfo& hd);
143   static bool WriteHeader(Byte** ppByte, const struct HeaderInfo& hd);
144   static bool ReadHeader(const Byte** ppByte, size_t& nBytesRemaining, struct HeaderInfo& hd);
145 
146   bool WriteMask(Byte** ppByte) const;
147   bool ReadMask(const Byte** ppByte, size_t& nBytesRemaining);
148 
149   bool DoChecksOnEncode(Byte* pBlobBegin, Byte* pBlobEnd) const;
150   static unsigned int ComputeChecksumFletcher32(const Byte* pByte, int len);
151 
152   static void AddUIntToCounts(int* pCounts, unsigned int val, int nBits);
153   static void AddIntToCounts(int* pCounts, int val, int nBits);
154 
155   template<class T>
156   bool TryBitPlaneCompression(const T* data, double eps, double& newMaxZError) const;
157 
158   template<class T>
159   bool TryRaiseMaxZError(const T* data, double& maxZError) const;
160 
161   static bool PruneCandidates(std::vector<double>& roundErr, std::vector<double>& zErr,
162     std::vector<int>& zFac, double maxZError);
163 
164   template<class T>
165   bool WriteDataOneSweep(const T* data, Byte** ppByte) const;
166 
167   template<class T>
168   bool ReadDataOneSweep(const Byte** ppByte, size_t& nBytesRemaining, T* data) const;
169 
170   template<class T>
171   bool ComputeMinMaxRanges(const T* data, std::vector<double>& zMinVec, std::vector<double>& zMaxVec) const;
172 
173   template<class T>
174   bool WriteTiles(const T* data, Byte** ppByte, int& numBytes) const;
175 
176   template<class T>
177   bool ReadTiles(const Byte** ppByte, size_t& nBytesRemaining, T* data) const;
178 
179   template<class T>
180   bool GetValidDataAndStats(const T* data, int i0, int i1, int j0, int j1, int iDim,
181     T* dataBuf, T& zMin, T& zMax, int& numValidPixel, bool& tryLut) const;
182 
183   template<class T>
184   static bool ComputeDiffSliceInt(const T* data, const T* prevData, int numValidPixel, bool bCheckForIntOverflow,
185     double maxZError, std::vector<int>& diffDataVec, int& zMin, int& zMax, bool& tryLut);
186 
187   template<class T>
188   static bool ComputeDiffSliceFlt(const T* data, const T* prevData, int numValidPixel, bool bCheckForFltRndErr,
189     double maxZError, std::vector<T>& diffDataVec, T& zMin, T& zMax, bool& tryLut);
190 
191   static bool NeedToCheckForIntOverflow(const HeaderInfo& hd);
192   static bool NeedToCheckForFltRndErr(const HeaderInfo& hd);
193 
194   static double ComputeMaxVal(double zMin, double zMax, double maxZError);
195 
196   template<class T>
197   bool NeedToQuantize(int numValidPixel, T zMin, T zMax) const;
198 
199   template<class T>
200   void Quantize(const T* dataBuf, int num, T zMin, std::vector<unsigned int>& quantVec) const;
201 
202   template<class T>
203   static void ScaleBack(T* dataBuf, const std::vector<unsigned int>& quantVec,
204     double zMin, bool bDiff, bool bClamp, double zMaxClamp, double maxZError);
205 
206   template<class T>
207   static void ScaleBackConstBlock(T* dataBuf, int num, double zMin, bool bClamp, double zMaxClamp);
208 
209   template<class T>
210   int NumBytesTile(int numValidPixel, T zMin, T zMax, DataType dtZ, bool tryLut, BlockEncodeMode& blockEncodeMode,
211                    const std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec) const;
212 
213   template<class T>
214   bool WriteTile(const T* dataBuf, int num, Byte** ppByte, int& numBytesWritten, int j0, T zMin, T zMax,
215     DataType dtZ, bool bDiffEnc, const std::vector<unsigned int>& quantVec, BlockEncodeMode blockEncodeMode,
216     const std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec) const;
217 
218   template<class T>
219   bool ReadTile(const Byte** ppByte, size_t& nBytesRemaining, T* data, int i0, int i1, int j0, int j1, int iDim,
220                 std::vector<unsigned int>& bufferVec) const;
221 
222   template<class T>
223   static int ReduceDataType(T z, DataType dt, DataType& dtReduced);
224 
225   static DataType GetDataTypeUsed(DataType dt, int reducedTypeCode);
226 
227   static DataType ValidateDataType(int dt);
228 
229   static bool WriteVariableDataType(Byte** ppByte, double z, DataType dtUsed);
230 
231   static double ReadVariableDataType(const Byte** ppByte, DataType dtUsed);
232 
233   template<class T>
234   static DataType GetDataType(T z);
235 
236   static unsigned int GetMaxValToQuantize(DataType dt);
237 
238   static unsigned int GetDataTypeSize(DataType dt);
239 
240   static void SortQuantArray(const std::vector<unsigned int>& quantVec,
241     std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec);
242 
243   template<class T>
244   void ComputeHuffmanCodes(const T* data, int& numBytes, ImageEncodeMode& imageEncodeMode,
245     std::vector<std::pair<unsigned short, unsigned int> >& codes) const;
246 
247   template<class T>
248   void ComputeHistoForHuffman(const T* data, std::vector<int>& histo, std::vector<int>& deltaHisto) const;
249 
250   template<class T>
251   bool EncodeHuffman(const T* data, Byte** ppByte) const;
252 
253   template<class T>
254   bool DecodeHuffman(const Byte** ppByte, size_t& nBytesRemaining, T* data) const;
255 
256   template<class T>
257   bool WriteMinMaxRanges(const T* data, Byte** ppByte) const;
258 
259   template<class T>
260   bool ReadMinMaxRanges(const Byte** ppByte, size_t& nBytesRemaining, const T* data);
261 
262   bool CheckMinMaxRanges(bool& minMaxEqual) const;
263 
264   template<class T>
265   bool FillConstImage(T* data) const;
266 };
267 
268 // -------------------------------------------------------------------------- ;
269 // -------------------------------------------------------------------------- ;
270 
271 inline
AddUIntToCounts(int * pCounts,unsigned int val,int nBits)272 void Lerc2::AddUIntToCounts(int* pCounts, unsigned int val, int nBits)
273 {
274   pCounts[0] += val & 1;
275   for (int i = 1; i < nBits; i++)
276     pCounts[i] += (val >>= 1) & 1;
277 }
278 
279 // -------------------------------------------------------------------------- ;
280 
281 inline
AddIntToCounts(int * pCounts,int val,int nBits)282 void Lerc2::AddIntToCounts(int* pCounts, int val, int nBits)
283 {
284   pCounts[0] += val & 1;
285   for (int i = 1; i < nBits; i++)
286     pCounts[i] += (val >>= 1) & 1;
287 }
288 
289 // -------------------------------------------------------------------------- ;
290 
NeedToCheckForIntOverflow(const HeaderInfo & hd)291 inline bool Lerc2::NeedToCheckForIntOverflow(const HeaderInfo& hd)
292 {
293   return (hd.dt == DT_Int || hd.dt == DT_UInt) && (hd.zMax - hd.zMin >= 0x7FFFFFFF);
294 }
295 
296 // -------------------------------------------------------------------------- ;
297 
NeedToCheckForFltRndErr(const HeaderInfo & hd)298 inline bool Lerc2::NeedToCheckForFltRndErr(const HeaderInfo& hd)
299 {
300   if (hd.dt != DT_Float)
301     return false;
302 
303   if (hd.zMax - hd.zMin > 100000)  // prevent the below test falls through with extreme numbers like 10^38
304     return true;
305 
306   float diff = (float)(hd.zMax - hd.zMin);
307   double testMax = (double)diff + hd.zMin;
308   double fltRndErr = fabs(testMax - hd.zMax);
309 
310   return (fltRndErr > hd.maxZError / 8);
311 }
312 
313 // -------------------------------------------------------------------------- ;
314 
ComputeMaxVal(double zMin,double zMax,double maxZError)315 inline double Lerc2::ComputeMaxVal(double zMin, double zMax, double maxZError)
316 {
317   double fac = 1 / (2 * maxZError);    // must match the code in Decode(), don't touch it
318   return (zMax - zMin) * fac;
319 }
320 
321 // -------------------------------------------------------------------------- ;
322 
323 template<class T>
NeedToQuantize(int numValidPixel,T zMin,T zMax)324 inline bool Lerc2::NeedToQuantize(int numValidPixel, T zMin, T zMax) const
325 {
326   if (numValidPixel == 0 || m_headerInfo.maxZError == 0)
327     return false;
328 
329   double maxVal = ComputeMaxVal(zMin, zMax, m_headerInfo.maxZError);
330   return !(maxVal > m_maxValToQuantize || (unsigned int)(maxVal + 0.5) == 0);
331 }
332 
333 // -------------------------------------------------------------------------- ;
334 
335 template<class T>
Quantize(const T * dataBuf,int num,T zMin,std::vector<unsigned int> & quantVec)336 inline void Lerc2::Quantize(const T* dataBuf, int num, T zMin, std::vector<unsigned int>& quantVec) const
337 {
338   quantVec.resize(num);
339 
340   if (m_headerInfo.dt < DT_Float && m_headerInfo.maxZError == 0.5)    // int lossless
341   {
342     for (int i = 0; i < num; i++)
343       quantVec[i] = (unsigned int)(dataBuf[i] - zMin);    // ok: char, short get promoted to int by C++ integral promotion rule
344   }
345   else    // float and/or lossy
346   {
347     double scale = 1 / (2 * m_headerInfo.maxZError);
348     double zMinDbl = (double)zMin;
349 
350     for (int i = 0; i < num; i++)
351       quantVec[i] = (unsigned int)(((double)dataBuf[i] - zMinDbl) * scale + 0.5);    // ok, consistent with ComputeMaxVal(...)
352       //quantVec[i] = (unsigned int)((dataBuf[i] - zMin) * scale + 0.5);    // bad, not consistent with ComputeMaxVal(...)
353   }
354 }
355 
356 // -------------------------------------------------------------------------- ;
357 
358 template<class T>
ScaleBack(T * dataBuf,const std::vector<unsigned int> & quantVec,double zMin,bool bDiff,bool bClamp,double zMaxClamp,double maxZError)359 inline void Lerc2::ScaleBack(T* dataBuf, const std::vector<unsigned int>& quantVec,
360   double zMin, bool bDiff, bool bClamp, double zMaxClamp, double maxZError)
361 {
362   double invScale = 2 * maxZError;    // for int types this is int
363   int num = (int)quantVec.size();
364 
365   if (!bClamp)
366     for (int i = 0; i < num; i++)
367     {
368       double z = zMin + quantVec[i] * invScale + (bDiff ? dataBuf[i] : 0);
369       dataBuf[i] = (T)z;
370     }
371   else
372     for (int i = 0; i < num; i++)
373     {
374       double z = zMin + quantVec[i] * invScale + (bDiff ? dataBuf[i] : 0);
375       dataBuf[i] = (T)std::min(z, zMaxClamp);
376     }
377 }
378 
379 // -------------------------------------------------------------------------- ;
380 
381 template<class T>
ScaleBackConstBlock(T * dataBuf,int num,double zMin,bool bClamp,double zMaxClamp)382 inline void Lerc2::ScaleBackConstBlock(T* dataBuf, int num, double zMin, bool bClamp, double zMaxClamp)
383 {
384   if (!bClamp)
385     for (int i = 0; i < num; i++)
386       dataBuf[i] = (T)(zMin + dataBuf[i]);
387   else
388     for (int i = 0; i < num; i++)
389       dataBuf[i] = (T)std::min(zMin + dataBuf[i], zMaxClamp);
390 }
391 
392 // -------------------------------------------------------------------------- ;
393 
394 template<class T>
NumBytesTile(int numValidPixel,T zMin,T zMax,DataType dtZ,bool tryLut,BlockEncodeMode & blockEncodeMode,const std::vector<std::pair<unsigned int,unsigned int>> & sortedQuantVec)395 inline int Lerc2::NumBytesTile(int numValidPixel, T zMin, T zMax, DataType dtZ, bool tryLut,
396   BlockEncodeMode& blockEncodeMode, const std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec) const
397 {
398   blockEncodeMode = BEM_RawBinary;
399 
400   if (numValidPixel == 0 || (zMin == 0 && zMax == 0))
401     return 1;
402 
403   double maxVal = 0, maxZError = m_headerInfo.maxZError;
404   int nBytesRaw = (int)(1 + numValidPixel * sizeof(T));
405 
406   if ((maxZError == 0 && zMax > zMin)
407     || (maxZError > 0 && (maxVal = ComputeMaxVal(zMin, zMax, maxZError)) > m_maxValToQuantize))
408   {
409     return nBytesRaw;
410   }
411   else
412   {
413     DataType dtReduced;
414     ReduceDataType(zMin, dtZ, dtReduced);
415     int nBytes = 1 + GetDataTypeSize(dtReduced);
416 
417     unsigned int maxElem = (unsigned int)(maxVal + 0.5);
418     if (maxElem > 0)
419     {
420       nBytes += (!tryLut) ? m_bitStuffer2.ComputeNumBytesNeededSimple(numValidPixel, maxElem)
421                           : m_bitStuffer2.ComputeNumBytesNeededLut(sortedQuantVec, tryLut);
422     }
423 
424     if (nBytes < nBytesRaw)
425       blockEncodeMode = (!tryLut || maxElem == 0) ? BEM_BitStuffSimple : BEM_BitStuffLUT;
426     else
427       nBytes = nBytesRaw;
428 
429     return nBytes;
430   }
431 }
432 
433 // -------------------------------------------------------------------------- ;
434 
435 template<class T>
ReduceDataType(T z,DataType dt,DataType & dtReduced)436 inline int Lerc2::ReduceDataType(T z, DataType dt, DataType& dtReduced)
437 {
438   Byte b = (Byte)z;
439   switch (dt)
440   {
441     case DT_Short:
442     {
443       signed char c = (signed char)z;
444       int tc = (T)c == z ? 2 : (T)b == z ? 1 : 0;
445       dtReduced = (DataType)(dt - tc);
446       return tc;
447     }
448     case DT_UShort:
449     {
450       int tc = (T)b == z ? 1 : 0;
451       dtReduced = (DataType)(dt - 2 * tc);
452       return tc;
453     }
454     case DT_Int:
455     {
456       short s = (short)z;
457       unsigned short us = (unsigned short)z;
458       int tc = (T)b == z ? 3 : (T)s == z ? 2 : (T)us == z ? 1 : 0;
459       dtReduced = (DataType)(dt - tc);
460       return tc;
461     }
462     case DT_UInt:
463     {
464       unsigned short us = (unsigned short)z;
465       int tc = (T)b == z ? 2 : (T)us == z ? 1 : 0;
466       dtReduced = (DataType)(dt - 2 * tc);
467       return tc;
468     }
469     case DT_Float:
470     {
471       short s = (short)z;
472       int tc = (T)b == z ? 2 : (T)s == z ? 1 : 0;
473       dtReduced = tc == 0 ? dt : (tc == 1 ? DT_Short : DT_Byte);
474       return tc;
475     }
476     case DT_Double:
477     {
478       short s = (short)z;
479       int l = (int)z;
480       float f = (float)z;
481       int tc = (T)s == z ? 3 : (T)l == z ? 2 : (T)f == z ? 1 : 0;
482       dtReduced = tc == 0 ? dt : (DataType)(dt - 2 * tc + 1);
483       return tc;
484     }
485     default:
486     {
487       dtReduced = dt;
488       return 0;
489     }
490   }
491 }
492 
493 // -------------------------------------------------------------------------- ;
494 
ValidateDataType(int dt)495 inline Lerc2::DataType Lerc2::ValidateDataType(int dt)
496 {
497   if( dt >= DT_Char && dt <= DT_Double )
498     return static_cast<DataType>(dt);
499   return DT_Undefined;
500 }
501 
502 // -------------------------------------------------------------------------- ;
503 
504 inline
GetDataTypeUsed(DataType dt,int tc)505 Lerc2::DataType Lerc2::GetDataTypeUsed(DataType dt, int tc)
506 {
507   switch (dt)
508   {
509     case DT_Short:
510     case DT_Int:     return ValidateDataType(dt - tc);
511     case DT_UShort:
512     case DT_UInt:    return ValidateDataType(dt - 2 * tc);
513     case DT_Float:   return tc == 0 ? dt : (tc == 1 ? DT_Short : DT_Byte);
514     case DT_Double:  return tc == 0 ? dt : ValidateDataType(dt - 2 * tc + 1);
515     default:
516       return dt;
517   }
518 }
519 
520 // -------------------------------------------------------------------------- ;
521 
522 inline
WriteVariableDataType(Byte ** ppByte,double z,DataType dtUsed)523 bool Lerc2::WriteVariableDataType(Byte** ppByte, double z, DataType dtUsed)
524 {
525   Byte* ptr = *ppByte;
526 
527   switch (dtUsed)
528   {
529     case DT_Char:
530     {
531       *((signed char*)ptr) = (signed char)z;
532       ptr++;
533       break;
534     }
535     case DT_Byte:
536     {
537       *((Byte*)ptr) = (Byte)z;
538       ptr++;
539       break;
540     }
541     case DT_Short:
542     {
543       short s = (short)z;
544       memcpy(ptr, &s, sizeof(short));
545       ptr += 2;
546       break;
547     }
548     case DT_UShort:
549     {
550       unsigned short us = (unsigned short)z;
551       memcpy(ptr, &us, sizeof(unsigned short));
552       ptr += 2;
553       break;
554     }
555     case DT_Int:
556     {
557       int i = (int)z;
558       memcpy(ptr, &i, sizeof(int));
559       ptr += 4;
560       break;
561     }
562     case DT_UInt:
563     {
564       unsigned int n = (unsigned int)z;
565       memcpy(ptr, &n, sizeof(unsigned int));
566       ptr += 4;
567       break;
568     }
569     case DT_Float:
570     {
571       float f = (float)z;
572       memcpy(ptr, &f, sizeof(float));
573       ptr += 4;
574       break;
575     }
576     case DT_Double:
577     {
578       memcpy(ptr, &z, sizeof(double));
579       ptr += 8;
580       break;
581     }
582 
583     default:
584       return false;
585   }
586 
587   *ppByte = ptr;
588   return true;
589 }
590 
591 // -------------------------------------------------------------------------- ;
592 
593 inline
ReadVariableDataType(const Byte ** ppByte,DataType dtUsed)594 double Lerc2::ReadVariableDataType(const Byte** ppByte, DataType dtUsed)
595 {
596   const Byte* ptr = *ppByte;
597 
598   switch (dtUsed)
599   {
600     case DT_Char:
601     {
602       signed char c = *((signed char*)ptr);
603       *ppByte = ptr + 1;
604       return c;
605     }
606     case DT_Byte:
607     {
608       Byte b = *((Byte*)ptr);
609       *ppByte = ptr + 1;
610       return b;
611     }
612     case DT_Short:
613     {
614       short s;
615       memcpy(&s, ptr, sizeof(short));
616       *ppByte = ptr + 2;
617       return s;
618     }
619     case DT_UShort:
620     {
621       unsigned short us;
622       memcpy(&us, ptr, sizeof(unsigned short));
623       *ppByte = ptr + 2;
624       return us;
625     }
626     case DT_Int:
627     {
628       int i;
629       memcpy(&i, ptr, sizeof(int));
630       *ppByte = ptr + 4;
631       return i;
632     }
633     case DT_UInt:
634     {
635       unsigned int n;
636       memcpy(&n, ptr, sizeof(unsigned int));
637       *ppByte = ptr + 4;
638       return n;
639     }
640     case DT_Float:
641     {
642       float f;
643       memcpy(&f, ptr, sizeof(float));
644       *ppByte = ptr + 4;
645       return f;
646     }
647     case DT_Double:
648     {
649       double d;
650       memcpy(&d, ptr, sizeof(double));
651       *ppByte = ptr + 8;
652       return d;
653     }
654     default:
655       return 0;
656   }
657 }
658 
659 // -------------------------------------------------------------------------- ;
660 
661 inline
GetMaxValToQuantize(DataType dt)662 unsigned int Lerc2::GetMaxValToQuantize(DataType dt)
663 {
664   switch (dt)
665   {
666     case DT_Char:
667     case DT_Byte:    //return (1 <<  7) - 1;    // disabled: allow LUT mode for 8 bit segmented
668     case DT_Short:
669     case DT_UShort:  return (1 << 15) - 1;
670 
671     case DT_Int:
672     case DT_UInt:
673     case DT_Float:
674     case DT_Double:  return (1 << 30) - 1;
675 
676     default:
677       return 0;
678   }
679 }
680 
681 // -------------------------------------------------------------------------- ;
682 
683 inline
GetDataTypeSize(DataType dt)684 unsigned int Lerc2::GetDataTypeSize(DataType dt)
685 {
686   switch (dt)
687   {
688     case DT_Char:
689     case DT_Byte:   return 1;
690     case DT_Short:
691     case DT_UShort: return 2;
692     case DT_Int:
693     case DT_UInt:
694     case DT_Float:  return 4;
695     case DT_Double: return 8;
696 
697     default:
698       return 0;
699   }
700 }
701 
702 // -------------------------------------------------------------------------- ;
703 
704 inline
CheckMinMaxRanges(bool & minMaxEqual)705 bool Lerc2::CheckMinMaxRanges(bool& minMaxEqual) const
706 {
707   int nDim = m_headerInfo.nDim;
708   if ((int)m_zMinVec.size() != nDim || (int)m_zMaxVec.size() != nDim)
709     return false;
710 
711   minMaxEqual = (0 == memcmp(&m_zMinVec[0], &m_zMaxVec[0], nDim * sizeof(m_zMinVec[0])));
712   return true;
713 }
714 
715 // -------------------------------------------------------------------------- ;
716 
717 NAMESPACE_LERC_END
718 #endif
719