LCOV - code coverage report
Current view: top level - third_party/LercLib - Lerc2.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 750 1049 71.5 %
Date: 2024-11-21 22:18:42 Functions: 143 200 71.5 %

          Line data    Source code
       1             : /*
       2             : Copyright 2015 Esri
       3             : 
       4             : Licensed under the Apache License, Version 2.0 (the "License");
       5             : you may not use this file except in compliance with the License.
       6             : You may obtain a copy of the License at
       7             : 
       8             : http://www.apache.org/licenses/LICENSE-2.0
       9             : 
      10             : Unless required by applicable law or agreed to in writing, software
      11             : distributed under the License is distributed on an "AS IS" BASIS,
      12             : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             : See the License for the specific language governing permissions and
      14             : limitations under the License.
      15             : 
      16             : A local copy of the license and additional notices are located with the
      17             : source distribution at:
      18             : 
      19             : http://github.com/Esri/lerc/
      20             : 
      21             : Contributors:  Thomas Maurer
      22             : */
      23             : 
      24             : #ifndef LERC2_H
      25             : #define LERC2_H
      26             : 
      27             : #include <algorithm>
      28             : #include <cfloat>
      29             : #include <cmath>
      30             : #include <limits>
      31             : #include <string>
      32             : #include <typeinfo>
      33             : #include "Defines.h"
      34             : #include "BitMask.h"
      35             : #include "BitStuffer2.h"
      36             : #include "Huffman.h"
      37             : #include "RLE.h"
      38             : 
      39             : NAMESPACE_LERC_START
      40             : 
      41             : /**   Lerc2 v1
      42             :  *
      43             :  *    -- allow for lossless compression of all common data types
      44             :  *    -- avoid data type conversions and copies
      45             :  *    -- optimized compression for segmented rasters (10-15x lossless)
      46             :  *    -- micro block is 8x8 fixed, only gets doubled to 16x16 if bit rate < 1 bpp
      47             :  *    -- cnt is replaced by bit mask
      48             :  *    -- Lerc blob header has data range [min, max]
      49             :  *    -- harden consistency checks to detect if the byte blob has been tampered with
      50             :  *    -- drop support for big endian, this is legacy now
      51             :  *
      52             :  *    Lerc2 v2
      53             :  *
      54             :  *    -- add Huffman coding for better lossless compression of 8 bit data types Char, Byte
      55             :  *
      56             :  *    Lerc2 v3
      57             :  *
      58             :  *    -- add checksum for the entire byte blob, for more rigorous detection of compressed data corruption
      59             :  *    -- for the main bit stuffing routine, use an extra uint buffer for guaranteed memory alignment
      60             :  *    -- this also allows dropping the NumExtraBytesToAllocate functions
      61             :  *
      62             :  *    Lerc2 v4
      63             :  *
      64             :  *    -- allow array per pixel, nDim values per pixel. Such as RGB, complex number, or larger arrays per pixel
      65             :  *    -- extend Huffman coding for 8 bit data types from delta only to trying both delta and orig
      66             :  *    -- for integer data types, allow to drop bit planes containing only random noise
      67             :  *
      68             :  */
      69             : 
      70             : class Lerc2
      71             : {
      72             : public:
      73             :   Lerc2();
      74             :   Lerc2(int nDim, int nCols, int nRows, const Byte* pMaskBits = nullptr);    // valid / invalid bits as byte array
      75        7323 :   virtual ~Lerc2()  {}
      76             : 
      77             :   bool SetEncoderToOldVersion(int version);    // call this to encode compatible to an old decoder
      78             : 
      79             :   bool Set(int nDim, int nCols, int nRows, const Byte* pMaskBits = nullptr);
      80             : 
      81             :   template<class T>
      82             :   unsigned int ComputeNumBytesNeededToWrite(const T* arr, double maxZError, bool encodeMask);
      83             : 
      84             :   //static unsigned int MinNumBytesNeededToReadHeader();
      85             : 
      86             :   /// dst buffer already allocated;  byte ptr is moved like a file pointer
      87             :   template<class T>
      88             :   bool Encode(const T* arr, Byte** ppByte);
      89             : 
      90             :   // data types supported by Lerc2
      91             :   enum DataType {DT_Char = 0, DT_Byte, DT_Short, DT_UShort, DT_Int, DT_UInt, DT_Float, DT_Double, DT_Undefined};
      92             : 
      93             :   struct HeaderInfo
      94             :   {
      95             :     int version;
      96             :     unsigned int checksum;
      97             :     int nRows,
      98             :         nCols,
      99             :         nDim,
     100             :         numValidPixel,
     101             :         microBlockSize,
     102             :         blobSize;
     103             : 
     104             :     DataType dt;
     105             : 
     106             :     double  maxZError,
     107             :             zMin,    // if nDim > 1, this is the overall range
     108             :             zMax;
     109             : 
     110       14811 :     void RawInit()  { memset(this, 0, sizeof(struct HeaderInfo)); }
     111             : 
     112       11928 :     bool TryHuffman() const  { return version > 1 && (dt == DT_Byte || dt == DT_Char) && maxZError == 0.5; }
     113             :   };
     114             : 
     115             :   static bool GetHeaderInfo(const Byte* pByte, size_t nBytesRemaining, struct HeaderInfo& headerInfo);
     116             : 
     117             :   /// dst buffer already allocated;  byte ptr is moved like a file pointer
     118             :   template<class T>
     119             :   bool Decode(const Byte** ppByte, size_t& nBytesRemaining, T* arr, Byte* pMaskBits = nullptr);    // if mask ptr is not 0, mask bits are returned (even if all valid or same as previous)
     120             : 
     121             : private:
     122             :   static const int kCurrVersion = 4;    // 2: added Huffman coding to 8 bit types DT_Char, DT_Byte;
     123             :                                         // 3: changed the bit stuffing to using a uint aligned buffer,
     124             :                                         //    added Fletcher32 checksum
     125             :                                         // 4: allow nDim values per pixel
     126             : 
     127             :   enum ImageEncodeMode { IEM_Tiling = 0, IEM_DeltaHuffman, IEM_Huffman };
     128             :   enum BlockEncodeMode { BEM_RawBinary = 0, BEM_BitStuffSimple, BEM_BitStuffLUT };
     129             : 
     130             :   int         m_microBlockSize,
     131             :               m_maxValToQuantize;
     132             :   BitMask     m_bitMask;
     133             :   HeaderInfo  m_headerInfo;
     134             :   BitStuffer2 m_bitStuffer2;
     135             :   bool        m_encodeMask,
     136             :               m_writeDataOneSweep;
     137             :   ImageEncodeMode  m_imageEncodeMode;
     138             : 
     139             :   std::vector<double> m_zMinVec, m_zMaxVec;
     140             :   std::vector<std::pair<unsigned short, unsigned int> > m_huffmanCodes;    // <= 256 codes, 1.5 kB
     141             : 
     142             : private:
     143       18750 :   static std::string FileKey()  { return "Lerc2 "; }
     144       17850 :   static bool IsLittleEndianSystem()  { int n = 1;  return (1 == *((Byte*)&n)) && (4 == sizeof(int)); }
     145             :   void Init();
     146             : 
     147             :   static unsigned int ComputeNumBytesHeaderToWrite(const struct HeaderInfo& hd);
     148             :   static bool WriteHeader(Byte** ppByte, const struct HeaderInfo& hd);
     149             :   static bool ReadHeader(const Byte** ppByte, size_t& nBytesRemaining, struct HeaderInfo& hd);
     150             : 
     151             :   bool WriteMask(Byte** ppByte) const;
     152             :   bool ReadMask(const Byte** ppByte, size_t& nBytesRemaining);
     153             : 
     154             :   bool DoChecksOnEncode(Byte* pBlobBegin, Byte* pBlobEnd) const;
     155             :   static unsigned int ComputeChecksumFletcher32(const Byte* pByte, int len);
     156             : 
     157             :   static void AddUIntToCounts(int* pCounts, unsigned int val, int nBits);
     158             :   static void AddIntToCounts(int* pCounts, int val, int nBits);
     159             : 
     160             :   template<class T>
     161             :   bool TryBitPlaneCompression(const T* data, double eps, double& newMaxZError) const;
     162             : 
     163             :   template<class T>
     164             :   bool WriteDataOneSweep(const T* data, Byte** ppByte) const;
     165             : 
     166             :   template<class T>
     167             :   bool ReadDataOneSweep(const Byte** ppByte, size_t& nBytesRemaining, T* data) const;
     168             : 
     169             :   template<class T>
     170             :   bool WriteTiles(const T* data, Byte** ppByte, int& numBytes, std::vector<double>& zMinVec, std::vector<double>& zMaxVec) const;
     171             : 
     172             :   template<class T>
     173             :   bool ReadTiles(const Byte** ppByte, size_t& nBytesRemaining, T* data) const;
     174             : 
     175             :   template<class T>
     176             :   bool GetValidDataAndStats(const T* data, int i0, int i1, int j0, int j1, int iDim,
     177             :     T* dataBuf, T& zMinA, T& zMaxA, int& numValidPixel, bool& tryLutA) const;
     178             : 
     179             :   static double ComputeMaxVal(double zMin, double zMax, double maxZError);
     180             : 
     181             :   template<class T>
     182             :   bool NeedToQuantize(int numValidPixel, T zMin, T zMax) const;
     183             : 
     184             :   template<class T>
     185             :   bool Quantize(const T* dataBuf, int num, T zMin, std::vector<unsigned int>& quantVec) const;
     186             : 
     187             :   template<class T>
     188             :   int NumBytesTile(int numValidPixel, T zMin, T zMax, bool tryLut, BlockEncodeMode& blockEncodeMode,
     189             :                    const std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec) const;
     190             : 
     191             :   template<class T>
     192             :   bool WriteTile(const T* dataBuf, int num, Byte** ppByte, int& numBytesWritten, int j0, T zMin, T zMax,
     193             :     const std::vector<unsigned int>& quantVec, BlockEncodeMode blockEncodeMode,
     194             :     const std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec) const;
     195             : 
     196             :   template<class T>
     197             :   bool ReadTile(const Byte** ppByte, size_t& nBytesRemaining, T* data, int i0, int i1, int j0, int j1, int iDim,
     198             :                 std::vector<unsigned int>& bufferVec) const;
     199             : 
     200             :   template<class T>
     201             :   int TypeCode(T z, DataType& dtUsed) const;
     202             : 
     203             :   DataType GetDataTypeUsed(int typeCode) const;
     204             : 
     205             :   static DataType ValidateDataType(int dt);
     206             : 
     207             :   static bool WriteVariableDataType(Byte** ppByte, double z, DataType dtUsed);
     208             : 
     209             :   static double ReadVariableDataType(const Byte** ppByte, DataType dtUsed);
     210             : 
     211             :   template<class T> DataType GetDataType(T z) const;
     212             : 
     213             :   static unsigned int GetMaxValToQuantize(DataType dt);
     214             : 
     215             :   static unsigned int GetDataTypeSize(DataType dt);
     216             : 
     217             :   static void SortQuantArray(const std::vector<unsigned int>& quantVec,
     218             :     std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec);
     219             : 
     220             :   template<class T>
     221             :   void ComputeHuffmanCodes(const T* data, int& numBytes, ImageEncodeMode& imageEncodeMode,
     222             :     std::vector<std::pair<unsigned short, unsigned int> >& codes) const;
     223             : 
     224             :   template<class T>
     225             :   void ComputeHistoForHuffman(const T* data, std::vector<int>& histo, std::vector<int>& deltaHisto) const;
     226             : 
     227             :   template<class T>
     228             :   bool EncodeHuffman(const T* data, Byte** ppByte) const;
     229             : 
     230             :   template<class T>
     231             :   bool DecodeHuffman(const Byte** ppByte, size_t& nBytesRemaining, T* data) const;
     232             : 
     233             :   template<class T>
     234             :   bool WriteMinMaxRanges(const T* data, Byte** ppByte) const;
     235             : 
     236             :   template<class T>
     237             :   bool ReadMinMaxRanges(const Byte** ppByte, size_t& nBytesRemaining, const T* data);
     238             : 
     239             :   bool CheckMinMaxRanges(bool& minMaxEqual) const;
     240             : 
     241             :   template<class T>
     242             :   bool FillConstImage(T* data) const;
     243             : };
     244             : 
     245             : // -------------------------------------------------------------------------- ;
     246             : // -------------------------------------------------------------------------- ;
     247             : 
     248             : template<class T>
     249        5181 : unsigned int Lerc2::ComputeNumBytesNeededToWrite(const T* arr, double maxZError, bool encodeMask)
     250             : {
     251        5181 :   if (!arr || !IsLittleEndianSystem())
     252           0 :     return 0;
     253             : 
     254             :   // header
     255        5181 :   unsigned int nBytesHeaderMask = ComputeNumBytesHeaderToWrite(m_headerInfo);
     256             : 
     257             :   // valid / invalid mask
     258        5181 :   int numValid = m_headerInfo.numValidPixel;
     259        5181 :   int numTotal = m_headerInfo.nCols * m_headerInfo.nRows;
     260             : 
     261        5181 :   bool needMask = numValid > 0 && numValid < numTotal;
     262             : 
     263        5181 :   m_encodeMask = encodeMask;
     264             : 
     265        5181 :   nBytesHeaderMask += 1 * sizeof(int);    // the mask encode numBytes
     266             : 
     267        5181 :   if (needMask && encodeMask)
     268             :   {
     269           9 :     RLE rle;
     270           9 :     size_t n = rle.computeNumBytesRLE((const Byte*)m_bitMask.Bits(), m_bitMask.Size());
     271           9 :     nBytesHeaderMask += (unsigned int)n;
     272             :   }
     273             : 
     274        5181 :   m_headerInfo.dt = GetDataType(arr[0]);
     275             : 
     276        5181 :   if (m_headerInfo.dt == DT_Undefined)
     277           0 :     return 0;
     278             : 
     279        5181 :   if (maxZError == 777)    // cheat code
     280           0 :     maxZError = -0.01;
     281             : 
     282        5181 :   if (m_headerInfo.dt < DT_Float)    // integer types
     283             :   {
     284             :     // interpret a negative maxZError as bit plane epsilon; dflt = 0.01;
     285        5128 :     if (maxZError < 0 && (!TryBitPlaneCompression(arr, -maxZError, maxZError)))
     286           0 :       maxZError = 0;
     287             : 
     288        5128 :     maxZError = std::max(0.5, floor(maxZError));
     289             :   }
     290          53 :   else if (maxZError < 0)    // don't allow bit plane compression for float or double yet
     291           0 :     return 0;
     292             : 
     293        5181 :   m_headerInfo.maxZError = maxZError;
     294        5181 :   m_headerInfo.zMin = 0;
     295        5181 :   m_headerInfo.zMax = 0;
     296        5181 :   m_headerInfo.microBlockSize = m_microBlockSize;
     297        5181 :   m_headerInfo.blobSize = nBytesHeaderMask;
     298             : 
     299        5181 :   if (numValid == 0)
     300           9 :     return nBytesHeaderMask;
     301             : 
     302        5172 :   m_maxValToQuantize = GetMaxValToQuantize(m_headerInfo.dt);
     303             : 
     304        5172 :   Byte* ptr = nullptr;    // only emulate the writing and just count the bytes needed
     305        5172 :   int nBytesTiling = 0;
     306             : 
     307        5172 :   if (!WriteTiles(arr, &ptr, nBytesTiling, m_zMinVec, m_zMaxVec))    // also fills the min max ranges
     308           0 :     return 0;
     309             : 
     310        5172 :   m_headerInfo.zMin = *std::min_element(m_zMinVec.begin(), m_zMinVec.end());
     311        5172 :   m_headerInfo.zMax = *std::max_element(m_zMaxVec.begin(), m_zMaxVec.end());
     312             : 
     313        5172 :   if (m_headerInfo.zMin == m_headerInfo.zMax)    // image is const
     314        1699 :     return nBytesHeaderMask;
     315             : 
     316        3473 :   int nDim = m_headerInfo.nDim;
     317             : 
     318        3473 :   if (m_headerInfo.version >= 4)
     319             :   {
     320             :     // add the min max ranges behind the mask and before the main data;
     321             :     // so we do not write it if no valid pixel or all same value const
     322         342 :     m_headerInfo.blobSize += 2 * nDim * sizeof(T);
     323             : 
     324         342 :     bool minMaxEqual = false;
     325         342 :     if (!CheckMinMaxRanges(minMaxEqual))
     326           0 :       return 0;
     327             : 
     328         342 :     if (minMaxEqual)
     329           0 :       return m_headerInfo.blobSize;    // all nDim bands are const
     330             :   }
     331             : 
     332             :   // data
     333        3473 :   m_imageEncodeMode = IEM_Tiling;
     334        3473 :   int nBytesData = nBytesTiling;
     335        3473 :   int nBytesHuffman = 0;
     336             : 
     337        3473 :   if (m_headerInfo.TryHuffman())
     338             :   {
     339             :     ImageEncodeMode huffmanEncMode;
     340        3327 :     ComputeHuffmanCodes(arr, nBytesHuffman, huffmanEncMode, m_huffmanCodes);    // save Huffman codes for later use
     341             : 
     342        3327 :     if (!m_huffmanCodes.empty() && nBytesHuffman < nBytesTiling)
     343             :     {
     344         639 :       m_imageEncodeMode = huffmanEncMode;
     345         639 :       nBytesData = nBytesHuffman;
     346             :     }
     347             :     else
     348        2687 :       m_huffmanCodes.resize(0);
     349             :   }
     350             : 
     351        3472 :   m_writeDataOneSweep = false;
     352        3472 :   int nBytesDataOneSweep = (int)(numValid * nDim * sizeof(T));
     353             : 
     354             :   {
     355             :     // try with double block size to reduce block header overhead, if
     356        3472 :     if ( (nBytesTiling * 8 < numTotal * nDim * 2)    // resulting bit rate < x (2 bpp)
     357        3154 :       && (nBytesTiling < 4 * nBytesDataOneSweep)     // bit stuffing is effective
     358        3154 :       && (nBytesHuffman == 0 || nBytesTiling < 2 * nBytesHuffman) )    // not much worse than huffman (otherwise huffman wins anyway)
     359             :     {
     360        3154 :       m_headerInfo.microBlockSize = m_microBlockSize * 2;
     361             : 
     362        3154 :       std::vector<double> zMinVec, zMaxVec;
     363        3154 :       int nBytes2 = 0;
     364        3154 :       if (!WriteTiles(arr, &ptr, nBytes2, zMinVec, zMaxVec))    // no huffman in here anymore
     365           0 :         return 0;
     366             : 
     367        3154 :       if (nBytes2 <= nBytesData)
     368             :       {
     369         627 :         nBytesData = nBytes2;
     370         627 :         m_imageEncodeMode = IEM_Tiling;
     371         627 :         m_huffmanCodes.resize(0);
     372             :       }
     373             :       else
     374             :       {
     375        2527 :         m_headerInfo.microBlockSize = m_microBlockSize;    // reset to orig
     376             :       }
     377             :     }
     378             :   }
     379             : 
     380        3472 :   if (m_headerInfo.TryHuffman())
     381        3327 :     nBytesData += 1;    // flag for image encode mode
     382             : 
     383        3473 :   if (nBytesDataOneSweep <= nBytesData)
     384             :   {
     385          24 :     m_writeDataOneSweep = true;    // fallback: write data binary uncompressed in one sweep
     386          24 :     m_headerInfo.blobSize += 1 + nBytesDataOneSweep;    // header, mask, min max ranges, flag, data one sweep
     387             :   }
     388             :   else
     389             :   {
     390        3449 :     m_writeDataOneSweep = false;
     391        3449 :     m_headerInfo.blobSize += 1 + nBytesData;    // header, mask, min max ranges, flag(s), data
     392             :   }
     393             : 
     394        3473 :   return m_headerInfo.blobSize;
     395             : }
     396             : 
     397             : // -------------------------------------------------------------------------- ;
     398             : 
     399             : template<class T>
     400        5180 : bool Lerc2::Encode(const T* arr, Byte** ppByte)
     401             : {
     402        5180 :   if (!arr || !ppByte || !IsLittleEndianSystem())
     403           0 :     return false;
     404             : 
     405        5180 :   Byte* ptrBlob = *ppByte;    // keep a ptr to the start of the blob
     406             : 
     407        5180 :   if (!WriteHeader(ppByte, m_headerInfo))
     408           0 :     return false;
     409             : 
     410        5180 :   if (!WriteMask(ppByte))
     411           0 :     return false;
     412             : 
     413        5180 :   if (m_headerInfo.numValidPixel == 0 || m_headerInfo.zMin == m_headerInfo.zMax)
     414             :   {
     415        1708 :     return DoChecksOnEncode(ptrBlob, *ppByte);
     416             :   }
     417             : 
     418        3472 :   if (m_headerInfo.version >= 4)
     419             :   {
     420         342 :     if (!WriteMinMaxRanges(arr, ppByte))
     421           0 :       return false;
     422             : 
     423         342 :     bool minMaxEqual = false;
     424         342 :     if (!CheckMinMaxRanges(minMaxEqual))
     425           0 :       return false;
     426             : 
     427         341 :     if (minMaxEqual)
     428           0 :       return DoChecksOnEncode(ptrBlob, *ppByte);
     429             :   }
     430             : 
     431        3471 :   **ppByte = m_writeDataOneSweep ? 1 : 0;    // write flag
     432        3471 :   (*ppByte)++;
     433             : 
     434        3471 :   if (!m_writeDataOneSweep)
     435             :   {
     436        3448 :     if (m_headerInfo.TryHuffman())
     437             :     {
     438        3326 :       **ppByte = (Byte)m_imageEncodeMode;    // Huffman or tiling encode mode
     439        3326 :       (*ppByte)++;
     440             : 
     441        3326 :       if (!m_huffmanCodes.empty())   // Huffman, no tiling
     442             :       {
     443         640 :         if (m_imageEncodeMode != IEM_DeltaHuffman && m_imageEncodeMode != IEM_Huffman)
     444         640 :           return false;
     445             : 
     446         640 :         if (!EncodeHuffman(arr, ppByte))    // data bit stuffed
     447           0 :           return false;
     448             : 
     449         640 :         return DoChecksOnEncode(ptrBlob, *ppByte);
     450             :       }
     451             :     }
     452             : 
     453        2809 :     int numBytes = 0;
     454        2809 :     std::vector<double> zMinVec, zMaxVec;
     455        2809 :     if (!WriteTiles(arr, ppByte, numBytes, zMinVec, zMaxVec))
     456           0 :       return false;
     457             :   }
     458             :   else
     459             :   {
     460          24 :     if (!WriteDataOneSweep(arr, ppByte))
     461           0 :       return false;
     462             :   }
     463             : 
     464        2833 :   return DoChecksOnEncode(ptrBlob, *ppByte);
     465             : }
     466             : 
     467             : // -------------------------------------------------------------------------- ;
     468             : 
     469             : template<class T>
     470        2142 : bool Lerc2::Decode(const Byte** ppByte, size_t& nBytesRemaining, T* arr, Byte* pMaskBits)
     471             : {
     472        2142 :   if (!arr || !ppByte || !IsLittleEndianSystem())
     473           0 :     return false;
     474             : 
     475        2142 :   const Byte* ptrBlob = *ppByte;    // keep a ptr to the start of the blob
     476        2142 :   size_t nBytesRemaining00 = nBytesRemaining;
     477             : 
     478        2142 :   if (!ReadHeader(ppByte, nBytesRemaining, m_headerInfo))
     479           0 :     return false;
     480             : 
     481        2142 :   if (nBytesRemaining00 < (size_t)m_headerInfo.blobSize)
     482           0 :     return false;
     483             : 
     484        2142 :   if (m_headerInfo.version >= 3)
     485             :   {
     486         531 :     int nBytes = (int)(FileKey().length() + sizeof(int) + sizeof(unsigned int));    // start right after the checksum entry
     487         531 :     if (m_headerInfo.blobSize < nBytes)
     488           0 :       return false;
     489         531 :     unsigned int checksum = ComputeChecksumFletcher32(ptrBlob + nBytes, m_headerInfo.blobSize - nBytes);
     490             : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
     491             :     // For fuzzing, ignore checksum verification
     492             :     (void)checksum;
     493             : #else
     494         531 :     if (checksum != m_headerInfo.checksum)
     495           0 :       return false;
     496             : #endif
     497             :   }
     498             : 
     499        2142 :   if (!ReadMask(ppByte, nBytesRemaining))
     500           0 :     return false;
     501             : 
     502        2142 :   if (pMaskBits)    // return proper mask bits even if they were not stored
     503          51 :     memcpy(pMaskBits, m_bitMask.Bits(), m_bitMask.Size());
     504             : 
     505        2142 :   memset(arr, 0, m_headerInfo.nCols * m_headerInfo.nRows * m_headerInfo.nDim * sizeof(T));
     506             : 
     507        2142 :   if (m_headerInfo.numValidPixel == 0)
     508           9 :     return true;
     509             : 
     510        2133 :   if (m_headerInfo.zMin == m_headerInfo.zMax)    // image is const
     511             :   {
     512         576 :     if (!FillConstImage(arr))
     513           0 :       return false;
     514             : 
     515         576 :     return true;
     516             :   }
     517             : 
     518        1557 :   if (m_headerInfo.version >= 4)
     519             :   {
     520         505 :     if (!ReadMinMaxRanges(ppByte, nBytesRemaining, arr))
     521           0 :       return false;
     522             : 
     523         505 :     bool minMaxEqual = false;
     524         505 :     if (!CheckMinMaxRanges(minMaxEqual))
     525           0 :       return false;
     526             : 
     527         505 :     if (minMaxEqual)    // if all bands are const, fill outgoing and done
     528             :     {
     529           0 :       if (!FillConstImage(arr))
     530           0 :         return false;
     531             : 
     532           0 :       return true;    // done
     533             :     }
     534             :   }
     535             : 
     536        1557 :   if (nBytesRemaining < 1)
     537           0 :     return false;
     538             : 
     539        1557 :   Byte readDataOneSweep = **ppByte;    // read flag
     540        1557 :   (*ppByte)++;
     541        1557 :   nBytesRemaining--;
     542             : 
     543        1557 :   if (!readDataOneSweep)
     544             :   {
     545        1533 :     if (m_headerInfo.TryHuffman())
     546             :     {
     547        1328 :       if (nBytesRemaining < 1)
     548           0 :         return false;
     549             : 
     550        1328 :       Byte flag = **ppByte;    // read flag Huffman / Lerc2
     551        1328 :       (*ppByte)++;
     552        1328 :       nBytesRemaining--;
     553             : 
     554        1328 :       if (flag > 2 || (m_headerInfo.version < 4 && flag > 1))
     555           0 :         return false;
     556             : 
     557        1328 :       m_imageEncodeMode = (ImageEncodeMode)flag;
     558             : 
     559        1328 :       if (m_imageEncodeMode == IEM_DeltaHuffman || m_imageEncodeMode == IEM_Huffman)
     560             :       {
     561         409 :         if (!DecodeHuffman(ppByte, nBytesRemaining, arr))
     562           0 :           return false;
     563             : 
     564         409 :         return true;    // done.
     565             :       }
     566             :     }
     567             : 
     568        1124 :     if (!ReadTiles(ppByte, nBytesRemaining, arr))
     569           0 :       return false;
     570             :   }
     571             :   else
     572             :   {
     573          24 :     if (!ReadDataOneSweep(ppByte, nBytesRemaining, arr))
     574           0 :       return false;
     575             :   }
     576             : 
     577        1148 :   return true;
     578             : }
     579             : 
     580             : // -------------------------------------------------------------------------- ;
     581             : // -------------------------------------------------------------------------- ;
     582             : 
     583             : inline
     584           0 : void Lerc2::AddUIntToCounts(int* pCounts, unsigned int val, int nBits)
     585             : {
     586           0 :   pCounts[0] += val & 1;
     587           0 :   for (int i = 1; i < nBits; i++)
     588           0 :     pCounts[i] += (val >>= 1) & 1;
     589           0 : }
     590             : 
     591             : // -------------------------------------------------------------------------- ;
     592             : 
     593             : inline
     594           0 : void Lerc2::AddIntToCounts(int* pCounts, int val, int nBits)
     595             : {
     596           0 :   pCounts[0] += val & 1;
     597           0 :   for (int i = 1; i < nBits; i++)
     598           0 :     pCounts[i] += (val >>= 1) & 1;
     599           0 : }
     600             : 
     601             : // -------------------------------------------------------------------------- ;
     602             : 
     603             : // for the theory and math, see
     604             : // https://pdfs.semanticscholar.org/d064/2e2ad1a4c3b445b0d795770f604a5d9e269c.pdf
     605             : 
     606             : template<class T>
     607           0 : bool Lerc2::TryBitPlaneCompression(const T* data, double eps, double& newMaxZError) const
     608             : {
     609           0 :   newMaxZError = 0;    // lossless is the obvious fallback
     610             : 
     611           0 :   if (!data || eps <= 0)
     612           0 :     return false;
     613             : 
     614           0 :   const HeaderInfo& hd = m_headerInfo;
     615           0 :   const int nDim = hd.nDim;
     616           0 :   const int maxShift = 8 * GetDataTypeSize(hd.dt);
     617           0 :   const int minCnt = 5000;
     618             : 
     619           0 :   if (hd.numValidPixel < minCnt)    // not enough data for good stats
     620           0 :     return false;
     621             : 
     622           0 :   std::vector<int> cntDiffVec(nDim * maxShift, 0);
     623           0 :   int cnt = 0;
     624             : 
     625           0 :   if (nDim == 1 && hd.numValidPixel == hd.nCols * hd.nRows)    // special but common case
     626             :   {
     627           0 :     if (hd.dt == DT_Byte || hd.dt == DT_UShort || hd.dt == DT_UInt)    // unsigned int
     628             :     {
     629           0 :       for (int i = 0; i < hd.nRows - 1; i++)
     630           0 :         for (int k = i * hd.nCols, j = 0; j < hd.nCols - 1; j++, k++)
     631             :         {
     632           0 :           unsigned int c = ((unsigned int)data[k]) ^ ((unsigned int)data[k + 1]);
     633           0 :           AddUIntToCounts(&cntDiffVec[0], c, maxShift);
     634           0 :           cnt++;
     635           0 :           c = ((unsigned int)data[k]) ^ ((unsigned int)data[k + hd.nCols]);
     636           0 :           AddUIntToCounts(&cntDiffVec[0], c, maxShift);
     637           0 :           cnt++;
     638           0 :         }
     639             :     }
     640           0 :     else if (hd.dt == DT_Char || hd.dt == DT_Short || hd.dt == DT_Int)    // signed int
     641             :     {
     642           0 :       for (int i = 0; i < hd.nRows - 1; i++)
     643           0 :         for (int k = i * hd.nCols, j = 0; j < hd.nCols - 1; j++, k++)
     644             :         {
     645           0 :           int c = ((int)data[k]) ^ ((int)data[k + 1]);
     646           0 :           AddIntToCounts(&cntDiffVec[0], c, maxShift);
     647           0 :           cnt++;
     648           0 :           c = ((int)data[k]) ^ ((int)data[k + hd.nCols]);
     649           0 :           AddIntToCounts(&cntDiffVec[0], c, maxShift);
     650           0 :           cnt++;
     651           0 :         }
     652             :     }
     653             :     else
     654           0 :       return false;    // unsupported data type
     655             :   }
     656             : 
     657             :   else    // general case:  nDim > 1 or not all pixel valid
     658             :   {
     659           0 :     if (hd.dt == DT_Byte || hd.dt == DT_UShort || hd.dt == DT_UInt)    // unsigned int
     660             :     {
     661           0 :       for (int k = 0, m0 = 0, i = 0; i < hd.nRows; i++)
     662           0 :         for (int j = 0; j < hd.nCols; j++, k++, m0 += nDim)
     663           0 :           if (m_bitMask.IsValid(k))
     664             :           {
     665           0 :             if (j < hd.nCols - 1 && m_bitMask.IsValid(k + 1))    // hori
     666             :             {
     667           0 :               for (int s0 = 0, iDim = 0; iDim < nDim; iDim++, s0 += maxShift)
     668             :               {
     669           0 :                 unsigned int c = ((unsigned int)data[m0 + iDim]) ^ ((unsigned int)data[m0 + iDim + nDim]);
     670           0 :                 AddUIntToCounts(&cntDiffVec[s0], c, maxShift);
     671             :               }
     672           0 :               cnt++;
     673             :             }
     674           0 :             if (i < hd.nRows - 1 && m_bitMask.IsValid(k + hd.nCols))    // vert
     675             :             {
     676           0 :               for (int s0 = 0, iDim = 0; iDim < nDim; iDim++, s0 += maxShift)
     677             :               {
     678           0 :                 unsigned int c = ((unsigned int)data[m0 + iDim]) ^ ((unsigned int)data[m0 + iDim + nDim * hd.nCols]);
     679           0 :                 AddUIntToCounts(&cntDiffVec[s0], c, maxShift);
     680             :               }
     681           0 :               cnt++;
     682             :             }
     683           0 :           }
     684             :     }
     685           0 :     else if (hd.dt == DT_Char || hd.dt == DT_Short || hd.dt == DT_Int)    // signed int
     686             :     {
     687           0 :       for (int k = 0, m0 = 0, i = 0; i < hd.nRows; i++)
     688           0 :         for (int j = 0; j < hd.nCols; j++, k++, m0 += nDim)
     689           0 :           if (m_bitMask.IsValid(k))
     690             :           {
     691           0 :             if (j < hd.nCols - 1 && m_bitMask.IsValid(k + 1))    // hori
     692             :             {
     693           0 :               for (int s0 = 0, iDim = 0; iDim < nDim; iDim++, s0 += maxShift)
     694             :               {
     695           0 :                 int c = ((int)data[m0 + iDim]) ^ ((int)data[m0 + iDim + nDim]);
     696           0 :                 AddIntToCounts(&cntDiffVec[s0], c, maxShift);
     697             :               }
     698           0 :               cnt++;
     699             :             }
     700           0 :             if (i < hd.nRows - 1 && m_bitMask.IsValid(k + hd.nCols))    // vert
     701             :             {
     702           0 :               for (int s0 = 0, iDim = 0; iDim < nDim; iDim++, s0 += maxShift)
     703             :               {
     704           0 :                 int c = ((int)data[m0 + iDim]) ^ ((int)data[m0 + iDim + nDim * hd.nCols]);
     705           0 :                 AddIntToCounts(&cntDiffVec[s0], c, maxShift);
     706             :               }
     707           0 :               cnt++;
     708             :             }
     709           0 :           }
     710             :     }
     711             :     else
     712           0 :       return false;    // unsupported data type
     713             :   }
     714             : 
     715           0 :   if (cnt < minCnt)    // not enough data for good stats
     716           0 :     return false;
     717             : 
     718           0 :   int nCutFound = 0, lastPlaneKept = 0;
     719           0 :   const bool printAll = false;
     720             : 
     721           0 :   for (int s = maxShift - 1; s >= 0; s--)
     722             :   {
     723             :     if (printAll) printf("bit plane %2d: ", s);
     724           0 :     bool bCrit = true;
     725             : 
     726           0 :     for (int iDim = 0; iDim < nDim; iDim++)
     727             :     {
     728           0 :       double x = cntDiffVec[iDim * maxShift + s];
     729           0 :       double n = cnt;
     730           0 :       double m = x / n;
     731             :       //double stdDev = sqrt(x * x / n - m * m) / n;
     732             : 
     733             :       //printf("  %.4f +- %.4f  ", (float)(2 * m), (float)(2 * stdDev));
     734             :       if (printAll) printf("  %.4f ", (float)(2 * m));
     735             : 
     736           0 :       if (fabs(1 - 2 * m) >= eps)
     737           0 :         bCrit = false;
     738             :     }
     739             :     if (printAll) printf("\n");
     740             : 
     741           0 :     if (bCrit && nCutFound < 2)
     742             :     {
     743           0 :       if (nCutFound == 0)
     744           0 :         lastPlaneKept = s;
     745             : 
     746           0 :       if (nCutFound == 1 && s < lastPlaneKept - 1)
     747             :       {
     748           0 :         lastPlaneKept = s;
     749           0 :         nCutFound = 0;
     750             :         if (printAll) printf(" reset ");
     751             :       }
     752             : 
     753           0 :       nCutFound++;
     754             :       if (printAll && nCutFound == 1) printf("\n");
     755             :     }
     756             :   }
     757             : 
     758           0 :   lastPlaneKept = std::max(0, lastPlaneKept);
     759             :   if (printAll) printf("%d \n", lastPlaneKept);
     760             : 
     761           0 :   newMaxZError = (1 << lastPlaneKept) >> 1;    // turn lastPlaneKept into new maxZError
     762             : 
     763           0 :   return true;
     764             : }
     765             : 
     766             : // -------------------------------------------------------------------------- ;
     767             : 
     768             : template<class T>
     769          24 : bool Lerc2::WriteDataOneSweep(const T* data, Byte** ppByte) const
     770             : {
     771          24 :   if (!data || !ppByte)
     772           0 :     return false;
     773             : 
     774          24 :   Byte* ptr = (*ppByte);
     775          24 :   const HeaderInfo& hd = m_headerInfo;
     776          24 :   int nDim = hd.nDim;
     777          24 :   int len = nDim * sizeof(T);
     778             : 
     779          86 :   for (int k = 0, m0 = 0, i = 0; i < hd.nRows; i++)
     780        3492 :     for (int j = 0; j < hd.nCols; j++, k++, m0 += nDim)
     781        3430 :       if (m_bitMask.IsValid(k))
     782             :       {
     783        3430 :         memcpy(ptr, &data[m0], len);
     784        3430 :         ptr += len;
     785             :       }
     786             : 
     787          24 :   (*ppByte) = ptr;
     788          24 :   return true;
     789             : }
     790             : 
     791             : // -------------------------------------------------------------------------- ;
     792             : 
     793             : template<class T>
     794          24 : bool Lerc2::ReadDataOneSweep(const Byte** ppByte, size_t& nBytesRemaining, T* data) const
     795             : {
     796          24 :   if (!data || !ppByte || !(*ppByte))
     797           0 :     return false;
     798             : 
     799          24 :   const Byte* ptr = (*ppByte);
     800          24 :   const HeaderInfo& hd = m_headerInfo;
     801          24 :   int nDim = hd.nDim;
     802          24 :   int len = nDim * sizeof(T);
     803             : 
     804          24 :   size_t nValidPix = (size_t)m_bitMask.CountValidBits();
     805             : 
     806          24 :   if (nBytesRemaining < nValidPix * len)
     807           0 :     return false;
     808             : 
     809          86 :   for (int k = 0, m0 = 0, i = 0; i < hd.nRows; i++)
     810        3492 :     for (int j = 0; j < hd.nCols; j++, k++, m0 += nDim)
     811        3430 :       if (m_bitMask.IsValid(k))
     812             :       {
     813        3430 :         memcpy(&data[m0], ptr, len);
     814        3430 :         ptr += len;
     815             :       }
     816             : 
     817          24 :   (*ppByte) = ptr;
     818          24 :   nBytesRemaining -= nValidPix * len;
     819             : 
     820          24 :   return true;
     821             : }
     822             : 
     823             : // -------------------------------------------------------------------------- ;
     824             : 
     825             : template<class T>
     826       11135 : bool Lerc2::WriteTiles(const T* data, Byte** ppByte, int& numBytes, std::vector<double>& zMinVec, std::vector<double>& zMaxVec) const
     827             : {
     828       11135 :   if (!data || !ppByte)
     829           0 :     return false;
     830             : 
     831       11135 :   numBytes = 0;
     832       11135 :   int numBytesLerc = 0;
     833             : 
     834       22270 :   std::vector<unsigned int> quantVec;
     835       22270 :   std::vector<std::pair<unsigned int, unsigned int> > sortedQuantVec;
     836             : 
     837       11135 :   const HeaderInfo& hd = m_headerInfo;
     838       11135 :   int mbSize = hd.microBlockSize;
     839       11135 :   int nDim = hd.nDim;
     840             : 
     841       22271 :   std::vector<T> dataVec(mbSize * mbSize, 0);
     842       11135 :   T* dataBuf = &dataVec[0];
     843             : 
     844       11135 :   zMinVec.assign(nDim, DBL_MAX);
     845       11135 :   zMaxVec.assign(nDim, -DBL_MAX);
     846             : 
     847       11135 :   int numTilesVert = (hd.nRows + mbSize - 1) / mbSize;
     848       11135 :   int numTilesHori = (hd.nCols + mbSize - 1) / mbSize;
     849             : 
     850      155882 :   for (int iTile = 0; iTile < numTilesVert; iTile++)
     851             :   {
     852      144747 :     int tileH = mbSize;
     853      144747 :     int i0 = iTile * tileH;
     854      144747 :     if (iTile == numTilesVert - 1)
     855       11135 :       tileH = hd.nRows - i0;
     856             : 
     857     2319464 :     for (int jTile = 0; jTile < numTilesHori; jTile++)
     858             :     {
     859     2174719 :       int tileW = mbSize;
     860     2174719 :       int j0 = jTile * tileW;
     861     2174719 :       if (jTile == numTilesHori - 1)
     862      144747 :         tileW = hd.nCols - j0;
     863             : 
     864     4489554 :       for (int iDim = 0; iDim < nDim; iDim++)
     865             :       {
     866     2314845 :         T zMin = 0, zMax = 0;
     867     2314845 :         int numValidPixel = 0;
     868     2314845 :         bool tryLut = false;
     869             : 
     870     2314845 :         if (!GetValidDataAndStats(data, i0, i0 + tileH, j0, j0 + tileW, iDim, dataBuf, zMin, zMax, numValidPixel, tryLut))
     871           1 :           return false;
     872             : 
     873     2314835 :         if (numValidPixel > 0)
     874             :         {
     875     2314835 :           zMinVec[iDim] = (std::min)(zMinVec[iDim], (double)zMin);
     876     2314835 :           zMaxVec[iDim] = (std::max)(zMaxVec[iDim], (double)zMax);
     877             :         }
     878             : 
     879             :         //tryLut = false;
     880             : 
     881             :         // if needed, quantize the data here once
     882     2314835 :         if ((*ppByte || tryLut) && NeedToQuantize(numValidPixel, zMin, zMax))
     883             :         {
     884      728526 :           if (!Quantize(dataBuf, numValidPixel, zMin, quantVec))
     885           0 :             return false;
     886             : 
     887      728526 :           if (tryLut)
     888      709569 :             SortQuantArray(quantVec, sortedQuantVec);
     889             :         }
     890             : 
     891             :         BlockEncodeMode blockEncodeMode;
     892     2314835 :         int numBytesNeeded = NumBytesTile(numValidPixel, zMin, zMax, tryLut, blockEncodeMode, sortedQuantVec);
     893     2314845 :         numBytesLerc += numBytesNeeded;
     894             : 
     895     2314845 :         if (*ppByte)
     896             :         {
     897      629449 :           int numBytesWritten = 0;
     898             : 
     899      629449 :           if (!WriteTile(dataBuf, numValidPixel, ppByte, numBytesWritten, j0, zMin, zMax, quantVec, blockEncodeMode, sortedQuantVec))
     900           1 :             return false;
     901             : 
     902      629449 :           if (numBytesWritten != numBytesNeeded)
     903           1 :             return false;
     904             :         }
     905             :       }
     906             :     }
     907             :   }
     908             : 
     909       11135 :   numBytes += numBytesLerc;
     910       11135 :   return true;
     911             : }
     912             : 
     913             : // -------------------------------------------------------------------------- ;
     914             : 
     915             : template<class T>
     916        1124 : bool Lerc2::ReadTiles(const Byte** ppByte, size_t& nBytesRemaining, T* data) const
     917             : {
     918        1124 :   if (!data || !ppByte || !(*ppByte))
     919           0 :     return false;
     920             : 
     921        2248 :   std::vector<unsigned int> bufferVec;
     922             : 
     923        1124 :   const HeaderInfo& hd = m_headerInfo;
     924        1124 :   int mbSize = hd.microBlockSize;
     925        1124 :   int nDim = hd.nDim;
     926             : 
     927        1124 :   if (mbSize > 32)  // fail gracefully in case of corrupted blob for old version <= 2 which had no checksum
     928           0 :     return false;
     929             : 
     930        1124 :   if( mbSize <= 0 || hd.nRows < 0 || hd.nCols < 0 ||
     931        3372 :       hd.nRows > std::numeric_limits<int>::max() - (mbSize - 1) ||
     932        1124 :       hd.nCols > std::numeric_limits<int>::max() - (mbSize - 1) )
     933             :   {
     934           0 :     return false;
     935             :   }
     936        1124 :   int numTilesVert = (hd.nRows + mbSize - 1) / mbSize;
     937        1124 :   int numTilesHori = (hd.nCols + mbSize - 1) / mbSize;
     938             : 
     939       15523 :   for (int iTile = 0; iTile < numTilesVert; iTile++)
     940             :   {
     941       14399 :     int tileH = mbSize;
     942       14399 :     int i0 = iTile * tileH;
     943       14399 :     if (iTile == numTilesVert - 1)
     944        1124 :       tileH = hd.nRows - i0;
     945             : 
     946      251414 :     for (int jTile = 0; jTile < numTilesHori; jTile++)
     947             :     {
     948      237015 :       int tileW = mbSize;
     949      237015 :       int j0 = jTile * tileW;
     950      237015 :       if (jTile == numTilesHori - 1)
     951       14399 :         tileW = hd.nCols - j0;
     952             : 
     953      485152 :       for (int iDim = 0; iDim < nDim; iDim++)
     954             :       {
     955      248137 :         if (!ReadTile(ppByte, nBytesRemaining, data, i0, i0 + tileH, j0, j0 + tileW, iDim, bufferVec))
     956           0 :           return false;
     957             :       }
     958             :     }
     959             :   }
     960             : 
     961        1124 :   return true;
     962             : }
     963             : 
     964             : // -------------------------------------------------------------------------- ;
     965             : 
     966             : template<class T>
     967     2314845 : bool Lerc2::GetValidDataAndStats(const T* data, int i0, int i1, int j0, int j1, int iDim,
     968             :   T* dataBuf, T& zMin, T& zMax, int& numValidPixel, bool& tryLut) const
     969             : {
     970     2314845 :   const HeaderInfo& hd = m_headerInfo;
     971             : 
     972     2314845 :   if (!data || i0 < 0 || j0 < 0 || i1 > hd.nRows || j1 > hd.nCols || iDim < 0 || iDim > hd.nDim || !dataBuf)
     973           1 :     return false;
     974             : 
     975     2314835 :   zMin = 0;
     976     2314835 :   zMax = 0;
     977     2314835 :   tryLut = false;
     978             : 
     979     2314835 :   T prevVal = 0;
     980     2314835 :   int cnt = 0, cntSameVal = 0;
     981     2314835 :   int nDim = hd.nDim;
     982             : 
     983     2314835 :   if (hd.numValidPixel == hd.nCols * hd.nRows)    // all valid, no mask
     984             :   {
     985    23229467 :     for (int i = i0; i < i1; i++)
     986             :     {
     987    20914686 :       int k = i * hd.nCols + j0;
     988    20914686 :       int m = k * nDim + iDim;
     989             : 
     990   226878342 :       for (int j = j0; j < j1; j++, k++, m += nDim)
     991             :       {
     992   205962858 :         T val = data[m];
     993   205962858 :         dataBuf[cnt] = val;
     994             : 
     995   205962858 :         if (cnt > 0)
     996             :         {
     997   203649081 :           if (val < zMin)
     998      696827 :             zMin = val;
     999   202952350 :           else if (val > zMax)
    1000      714172 :             zMax = val;
    1001             : 
    1002   203649081 :           if (val == prevVal)
    1003   188847021 :             cntSameVal++;
    1004             :         }
    1005             :         else
    1006     2314651 :           zMin = zMax = val;    // init
    1007             : 
    1008   205962858 :         prevVal = val;
    1009   205962858 :         cnt++;
    1010             :       }
    1011             :     }
    1012             :   }
    1013             :   else    // not all valid, use mask
    1014             :   {
    1015         219 :     for (int i = i0; i < i1; i++)
    1016             :     {
    1017         110 :       int k = i * hd.nCols + j0;
    1018         110 :       int m = k * nDim + iDim;
    1019             : 
    1020         930 :       for (int j = j0; j < j1; j++, k++, m += nDim)
    1021         820 :         if (m_bitMask.IsValid(k))
    1022             :         {
    1023         413 :           T val = data[m];
    1024         413 :           dataBuf[cnt] = val;
    1025             : 
    1026         413 :           if (cnt > 0)
    1027             :           {
    1028         306 :             if (val < zMin)
    1029           0 :               zMin = val;
    1030         306 :             else if (val > zMax)
    1031           0 :               zMax = val;
    1032             : 
    1033         306 :             if (val == prevVal)
    1034         306 :               cntSameVal++;
    1035             :           }
    1036             :           else
    1037         107 :             zMin = zMax = val;    // init
    1038             : 
    1039         413 :           prevVal = val;
    1040         413 :           cnt++;
    1041             :         }
    1042             :     }
    1043             :   }
    1044             : 
    1045     2314835 :   if (cnt > 4)
    1046     2314701 :     tryLut = (zMax > zMin + hd.maxZError) && (2 * cntSameVal > cnt);
    1047             : 
    1048     2314835 :   numValidPixel = cnt;
    1049     2314835 :   return true;
    1050             : }
    1051             : 
    1052             : // -------------------------------------------------------------------------- ;
    1053             : 
    1054     3559960 : inline double Lerc2::ComputeMaxVal(double zMin, double zMax, double maxZError)
    1055             : {
    1056     3559960 :   double fac = 1 / (2 * maxZError);    // must match the code in Decode(), don't touch it
    1057     3559960 :   return (zMax - zMin) * fac;
    1058             : }
    1059             : 
    1060             : // -------------------------------------------------------------------------- ;
    1061             : 
    1062             : template<class T>
    1063     1093786 : bool Lerc2::NeedToQuantize(int numValidPixel, T zMin, T zMax) const
    1064             : {
    1065     1093786 :   if (numValidPixel == 0 || m_headerInfo.maxZError == 0)
    1066           0 :     return false;
    1067             : 
    1068     1093786 :   double maxVal = ComputeMaxVal(zMin, zMax, m_headerInfo.maxZError);
    1069     1093786 :   return !(maxVal > m_maxValToQuantize || (unsigned int)(maxVal + 0.5) == 0);
    1070             : }
    1071             : 
    1072             : // -------------------------------------------------------------------------- ;
    1073             : 
    1074             : template<class T>
    1075      728526 : bool Lerc2::Quantize(const T* dataBuf, int num, T zMin, std::vector<unsigned int>& quantVec) const
    1076             : {
    1077      728526 :   quantVec.resize(num);
    1078             : 
    1079      728526 :   if (m_headerInfo.dt < DT_Float && m_headerInfo.maxZError == 0.5)    // int lossless
    1080             :   {
    1081    72097312 :     for (int i = 0; i < num; i++)
    1082    72097312 :       quantVec[i] = (unsigned int)(dataBuf[i] - zMin);    // ok, as char, short get promoted to int by C++ integral promotion rule
    1083             :   }
    1084             :   else    // float and/or lossy
    1085             :   {
    1086       15661 :     double scale = 1 / (2 * m_headerInfo.maxZError);
    1087       15661 :     double zMinDbl = (double)zMin;
    1088             : 
    1089     1062142 :     for (int i = 0; i < num; i++)
    1090     1046482 :       quantVec[i] = (unsigned int)(((double)dataBuf[i] - zMinDbl) * scale + 0.5);    // ok, consistent with ComputeMaxVal(...)
    1091             :       //quantVec[i] = (unsigned int)((dataBuf[i] - zMin) * scale + 0.5);    // bad, not consistent with ComputeMaxVal(...)
    1092             :   }
    1093             : 
    1094      728526 :   return true;
    1095             : }
    1096             : 
    1097             : // -------------------------------------------------------------------------- ;
    1098             : 
    1099             : template<class T>
    1100     2314835 : int Lerc2::NumBytesTile(int numValidPixel, T zMin, T zMax, bool tryLut, BlockEncodeMode& blockEncodeMode,
    1101             :                          const std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec) const
    1102             : {
    1103     2314835 :   blockEncodeMode = BEM_RawBinary;
    1104             : 
    1105     2314835 :   if (numValidPixel == 0 || (zMin == 0 && zMax == 0))
    1106      376137 :     return 1;
    1107             : 
    1108     1938696 :   double maxVal = 0, maxZError = m_headerInfo.maxZError;
    1109     1938696 :   int nBytesRaw = (int)(1 + numValidPixel * sizeof(T));
    1110             : 
    1111         596 :   if ((maxZError == 0 && zMax > zMin)
    1112     1939292 :     || (maxZError > 0 && (maxVal = ComputeMaxVal(zMin, zMax, maxZError)) > m_maxValToQuantize))
    1113             :   {
    1114         436 :     return nBytesRaw;
    1115             :   }
    1116             :   else
    1117             :   {
    1118             :     DataType dtUsed;
    1119     1938260 :     TypeCode(zMin, dtUsed);
    1120     1938270 :     int nBytes = 1 + GetDataTypeSize(dtUsed);
    1121             : 
    1122     1938270 :     unsigned int maxElem = (unsigned int)(maxVal + 0.5);
    1123     1938270 :     if (maxElem > 0)
    1124             :     {
    1125     1480163 :       nBytes += (!tryLut) ? m_bitStuffer2.ComputeNumBytesNeededSimple(numValidPixel, maxElem)
    1126      709569 :                           : m_bitStuffer2.ComputeNumBytesNeededLut(sortedQuantVec, tryLut);
    1127             :     }
    1128             : 
    1129     1938270 :     if (nBytes < nBytesRaw)
    1130     1918287 :       blockEncodeMode = (!tryLut || maxElem == 0) ? BEM_BitStuffSimple : BEM_BitStuffLUT;
    1131             :     else
    1132       19980 :       nBytes = nBytesRaw;
    1133             : 
    1134     1938270 :     return nBytes;
    1135             :   }
    1136             : }
    1137             : 
    1138             : // -------------------------------------------------------------------------- ;
    1139             : 
    1140             : template<class T>
    1141      629449 : bool Lerc2::WriteTile(const T* dataBuf, int num, Byte** ppByte, int& numBytesWritten, int j0, T zMin, T zMax,
    1142             :   const std::vector<unsigned int>& quantVec, BlockEncodeMode blockEncodeMode,
    1143             :   const std::vector<std::pair<unsigned int, unsigned int> >& sortedQuantVec) const
    1144             : {
    1145      629449 :   Byte* ptr = *ppByte;
    1146      629449 :   Byte comprFlag = ((j0 >> 3) & 15) << 2;    // use bits 2345 for integrity check
    1147             : 
    1148      629449 :   if (num == 0 || (zMin == 0 && zMax == 0))    // special cases
    1149             :   {
    1150      100003 :     *ptr++ = comprFlag | 2;    // set compression flag to 2 to mark tile as constant 0
    1151      100003 :     numBytesWritten = 1;
    1152      100003 :     *ppByte = ptr;
    1153      100003 :     return true;
    1154             :   }
    1155             : 
    1156      529446 :   if (blockEncodeMode == BEM_RawBinary)
    1157             :   {
    1158        1369 :     *ptr++ = comprFlag | 0;    // write z's binary uncompressed
    1159             : 
    1160        1369 :     memcpy(ptr, dataBuf, num * sizeof(T));
    1161        1369 :     ptr += num * sizeof(T);
    1162             :   }
    1163             :   else
    1164             :   {
    1165      528077 :     double maxVal = (m_headerInfo.maxZError > 0) ? ComputeMaxVal(zMin, zMax, m_headerInfo.maxZError) : 0;
    1166             : 
    1167             :     // write z's as int arr bit stuffed
    1168      528077 :     unsigned int maxElem = (unsigned int)(maxVal + 0.5);
    1169      528077 :     if (maxElem == 0)
    1170      265252 :       comprFlag |= 3;    // set compression flag to 3 to mark tile as constant zMin
    1171             :     else
    1172      262825 :       comprFlag |= 1;    // use bit stuffing
    1173             : 
    1174             :     DataType dtUsed;
    1175      528077 :     int bits67 = TypeCode(zMin, dtUsed);
    1176      528077 :     comprFlag |= bits67 << 6;
    1177             : 
    1178      528077 :     *ptr++ = comprFlag;
    1179             : 
    1180      528077 :     if (!WriteVariableDataType(&ptr, (double)zMin, dtUsed))
    1181           0 :       return false;
    1182             : 
    1183      528077 :     if (maxElem > 0)
    1184             :     {
    1185      262825 :       if ((int)quantVec.size() != num)
    1186           0 :         return false;
    1187             : 
    1188      262825 :       if (blockEncodeMode == BEM_BitStuffSimple)
    1189             :       {
    1190       41909 :         if (!m_bitStuffer2.EncodeSimple(&ptr, quantVec, m_headerInfo.version))
    1191           0 :           return false;
    1192             :       }
    1193      220916 :       else if (blockEncodeMode == BEM_BitStuffLUT)
    1194             :       {
    1195      220916 :         if (!m_bitStuffer2.EncodeLut(&ptr, sortedQuantVec, m_headerInfo.version))
    1196           0 :           return false;
    1197             :       }
    1198             :       else
    1199           0 :         return false;
    1200             :     }
    1201             :   }
    1202             : 
    1203      529446 :   numBytesWritten = (int)(ptr - *ppByte);
    1204      529446 :   *ppByte = ptr;
    1205      529446 :   return true;
    1206             : }
    1207             : 
    1208             : // -------------------------------------------------------------------------- ;
    1209             : 
    1210             : template<class T>
    1211      248137 : bool Lerc2::ReadTile(const Byte** ppByte, size_t& nBytesRemainingInOut, T* data, int i0, int i1, int j0, int j1, int iDim,
    1212             :                      std::vector<unsigned int>& bufferVec) const
    1213             : {
    1214      248137 :   const Byte* ptr = *ppByte;
    1215      248137 :   size_t nBytesRemaining = nBytesRemainingInOut;
    1216             : 
    1217      248137 :   if (nBytesRemaining < 1)
    1218           0 :     return false;
    1219             : 
    1220      248137 :   Byte comprFlag = *ptr++;
    1221      248137 :   nBytesRemaining--;
    1222             : 
    1223      248137 :   int bits67 = comprFlag >> 6;
    1224      248137 :   int testCode = (comprFlag >> 2) & 15;    // use bits 2345 for integrity check
    1225      248137 :   if (testCode != ((j0 >> 3) & 15))
    1226           0 :     return false;
    1227             : 
    1228      248137 :   const HeaderInfo& hd = m_headerInfo;
    1229      248137 :   int nCols = hd.nCols;
    1230      248137 :   int nDim = hd.nDim;
    1231             : 
    1232      248137 :   comprFlag &= 3;
    1233             : 
    1234      248137 :   if (comprFlag == 2)    // entire tile is constant 0 (all the valid pixels)
    1235             :   {
    1236      479349 :     for (int i = i0; i < i1; i++)
    1237             :     {
    1238      436220 :       int k = i * nCols + j0;
    1239      436220 :       int m = k * nDim + iDim;
    1240             : 
    1241     5408890 :       for (int j = j0; j < j1; j++, k++, m += nDim)
    1242     4972670 :         if (m_bitMask.IsValid(k))
    1243     4972670 :           data[m] = 0;
    1244             :     }
    1245             : 
    1246       43129 :     *ppByte = ptr;
    1247       43129 :     nBytesRemainingInOut = nBytesRemaining;
    1248       43129 :     return true;
    1249             :   }
    1250             : 
    1251      205008 :   else if (comprFlag == 0)    // read z's binary uncompressed
    1252             :   {
    1253        1209 :     const T* srcPtr = (const T*)ptr;
    1254        1209 :     int cnt = 0;
    1255             : 
    1256       10713 :     for (int i = i0; i < i1; i++)
    1257             :     {
    1258        9504 :       int k = i * nCols + j0;
    1259        9504 :       int m = k * nDim + iDim;
    1260             : 
    1261       85536 :       for (int j = j0; j < j1; j++, k++, m += nDim)
    1262       76032 :         if (m_bitMask.IsValid(k))
    1263             :         {
    1264       76032 :           if (nBytesRemaining < sizeof(T))
    1265           0 :             return false;
    1266             : 
    1267       76032 :           data[m] = *srcPtr++;
    1268       76032 :           nBytesRemaining -= sizeof(T);
    1269             : 
    1270       76032 :           cnt++;
    1271             :         }
    1272             :     }
    1273             : 
    1274        1209 :     ptr += cnt * sizeof(T);
    1275             :   }
    1276             :   else
    1277             :   {
    1278             :     // read z's as int arr bit stuffed
    1279      203799 :     DataType dtUsed = GetDataTypeUsed(bits67);
    1280      203799 :     if( dtUsed == DT_Undefined )
    1281           0 :       return false;
    1282      203799 :     size_t n = GetDataTypeSize(dtUsed);
    1283      203799 :     if (nBytesRemaining < n)
    1284           0 :       return false;
    1285             : 
    1286      203799 :     double offset = ReadVariableDataType(&ptr, dtUsed);
    1287      203799 :     nBytesRemaining -= n;
    1288             : 
    1289      203799 :     if (comprFlag == 3)    // entire tile is constant zMin (all the valid pixels)
    1290             :     {
    1291      905018 :       for (int i = i0; i < i1; i++)
    1292             :       {
    1293      814328 :         int k = i * nCols + j0;
    1294      814328 :         int m = k * nDim + iDim;
    1295             : 
    1296     8764730 :         for (int j = j0; j < j1; j++, k++, m += nDim)
    1297     7950400 :           if (m_bitMask.IsValid(k))
    1298     7950400 :             data[m] = (T)offset;
    1299             :       }
    1300             :     }
    1301             :     else
    1302             :     {
    1303      113109 :       size_t maxElementCount = (i1 - i0) * (j1 - j0);
    1304      113109 :       if (!m_bitStuffer2.Decode(&ptr, nBytesRemaining, bufferVec, maxElementCount, hd.version))
    1305           0 :         return false;
    1306             : 
    1307      113109 :       double invScale = 2 * hd.maxZError;    // for int types this is int
    1308      113109 :       double zMax = (hd.version >= 4 && nDim > 1) ? m_zMaxVec[iDim] : hd.zMax;
    1309      113109 :       const unsigned int* srcPtr = bufferVec.data();
    1310             : 
    1311      113109 :       if (bufferVec.size() == maxElementCount)    // all valid
    1312             :       {
    1313     1031152 :         for (int i = i0; i < i1; i++)
    1314             :         {
    1315      918040 :           int k = i * nCols + j0;
    1316      918040 :           int m = k * nDim + iDim;
    1317             : 
    1318     8486986 :           for (int j = j0; j < j1; j++, k++, m += nDim)
    1319             :           {
    1320     7568948 :             double z = offset + *srcPtr++ * invScale;
    1321     7568948 :             data[m] = (T)std::min(z, zMax);    // make sure we stay in the orig range
    1322             :           }
    1323             :         }
    1324             :       }
    1325             :       else    // not all valid
    1326             :       {
    1327             : #ifndef GDAL_COMPILATION
    1328             :         if (hd.version > 2)
    1329             :         {
    1330             :           for (int i = i0; i < i1; i++)
    1331             :           {
    1332             :             int k = i * nCols + j0;
    1333             :             int m = k * nDim + iDim;
    1334             : 
    1335             :             for (int j = j0; j < j1; j++, k++, m += nDim)
    1336             :               if (m_bitMask.IsValid(k))
    1337             :               {
    1338             :                 double z = offset + *srcPtr++ * invScale;
    1339             :                 data[m] = (T)std::min(z, zMax);    // make sure we stay in the orig range
    1340             :               }
    1341             :           }
    1342             :         }
    1343             :         else  // fail gracefully in case of corrupted blob for old version <= 2 which had no checksum
    1344             : #endif
    1345             :         {
    1346           0 :           size_t bufferVecIdx = 0;
    1347             : 
    1348           0 :           for (int i = i0; i < i1; i++)
    1349             :           {
    1350           0 :             int k = i * nCols + j0;
    1351           0 :             int m = k * nDim + iDim;
    1352             : 
    1353           0 :             for (int j = j0; j < j1; j++, k++, m += nDim)
    1354           0 :               if (m_bitMask.IsValid(k))
    1355             :               {
    1356           0 :                 if (bufferVecIdx == bufferVec.size())  // fail gracefully in case of corrupted blob for old version <= 2 which had no checksum
    1357           0 :                   return false;
    1358             : 
    1359           0 :                 double z = offset + bufferVec[bufferVecIdx] * invScale;
    1360           0 :                 bufferVecIdx++;
    1361           0 :                 data[m] = (T)std::min(z, zMax);    // make sure we stay in the orig range
    1362             :               }
    1363             :           }
    1364             :         }
    1365             :       }
    1366             :     }
    1367             :   }
    1368             : 
    1369      205008 :   *ppByte = ptr;
    1370      205008 :   nBytesRemainingInOut = nBytesRemaining;
    1371      205008 :   return true;
    1372             : }
    1373             : 
    1374             : // -------------------------------------------------------------------------- ;
    1375             : 
    1376             : template<class T>
    1377     2466344 : int Lerc2::TypeCode(T z, DataType& dtUsed) const
    1378             : {
    1379     2466344 :   Byte b = (Byte)z;
    1380     2466344 :   DataType dt = m_headerInfo.dt;
    1381     2466344 :   switch (dt)
    1382             :   {
    1383          48 :     case DT_Short:
    1384             :     {
    1385          48 :       signed char c = (signed char)z;
    1386          48 :       int tc = (T)c == z ? 2 : (T)b == z ? 1 : 0;
    1387          48 :       dtUsed = (DataType)(dt - tc);
    1388          48 :       return tc;
    1389             :     }
    1390          48 :     case DT_UShort:
    1391             :     {
    1392          48 :       int tc = (T)b == z ? 1 : 0;
    1393          48 :       dtUsed = (DataType)(dt - 2 * tc);
    1394          48 :       return tc;
    1395             :     }
    1396          48 :     case DT_Int:
    1397             :     {
    1398          48 :       short s = (short)z;
    1399          48 :       unsigned short us = (unsigned short)z;
    1400          48 :       int tc = (T)b == z ? 3 : (T)s == z ? 2 : (T)us == z ? 1 : 0;
    1401          48 :       dtUsed = (DataType)(dt - tc);
    1402          48 :       return tc;
    1403             :     }
    1404          48 :     case DT_UInt:
    1405             :     {
    1406          48 :       unsigned short us = (unsigned short)z;
    1407          48 :       int tc = (T)b == z ? 2 : (T)us == z ? 1 : 0;
    1408          48 :       dtUsed = (DataType)(dt - 2 * tc);
    1409          48 :       return tc;
    1410             :     }
    1411         101 :     case DT_Float:
    1412             :     {
    1413         101 :       short s = (short)z;
    1414         101 :       int tc = (T)b == z ? 2 : (T)s == z ? 1 : 0;
    1415         101 :       dtUsed = tc == 0 ? dt : (tc == 1 ? DT_Short : DT_Byte);
    1416         101 :       return tc;
    1417             :     }
    1418         122 :     case DT_Double:
    1419             :     {
    1420         122 :       short s = (short)z;
    1421         122 :       int l = (int)z;
    1422         122 :       float f = (float)z;
    1423         122 :       int tc = (T)s == z ? 3 : (T)l == z ? 2 : (T)f == z ? 1 : 0;
    1424         122 :       dtUsed = tc == 0 ? dt : (DataType)(dt - 2 * tc + 1);
    1425         122 :       return tc;
    1426             :     }
    1427     2465929 :     default:
    1428             :     {
    1429     2465929 :       dtUsed = dt;
    1430     2465929 :       return 0;
    1431             :     }
    1432             :   }
    1433             : }
    1434             : 
    1435             : // -------------------------------------------------------------------------- ;
    1436             : 
    1437          60 : inline Lerc2::DataType Lerc2::ValidateDataType(int dt)
    1438             : {
    1439          60 :   if( dt >= DT_Char && dt <= DT_Double )
    1440          60 :     return static_cast<DataType>(dt);
    1441           0 :   return DT_Undefined;
    1442             : }
    1443             : 
    1444             : // -------------------------------------------------------------------------- ;
    1445             : 
    1446             : inline
    1447      203799 : Lerc2::DataType Lerc2::GetDataTypeUsed(int tc) const
    1448             : {
    1449      203799 :   DataType dt = m_headerInfo.dt;
    1450      203799 :   switch (dt)
    1451             :   {
    1452          26 :     case DT_Short:
    1453          26 :     case DT_Int:     return ValidateDataType(dt - tc);
    1454          26 :     case DT_UShort:
    1455          26 :     case DT_UInt:    return ValidateDataType(dt - 2 * tc);
    1456           4 :     case DT_Float:   return tc == 0 ? dt : (tc == 1 ? DT_Short : DT_Byte);
    1457           8 :     case DT_Double:  return tc == 0 ? dt : ValidateDataType(dt - 2 * tc + 1);
    1458      203735 :     default:
    1459      203735 :       return dt;
    1460             :   }
    1461             : }
    1462             : 
    1463             : // -------------------------------------------------------------------------- ;
    1464             : 
    1465             : inline
    1466      528077 : bool Lerc2::WriteVariableDataType(Byte** ppByte, double z, DataType dtUsed)
    1467             : {
    1468      528077 :   Byte* ptr = *ppByte;
    1469             : 
    1470      528077 :   switch (dtUsed)
    1471             :   {
    1472          13 :     case DT_Char:
    1473             :     {
    1474          13 :       *((signed char*)ptr) = (signed char)z;
    1475          13 :       ptr++;
    1476          13 :       break;
    1477             :     }
    1478      528056 :     case DT_Byte:
    1479             :     {
    1480      528056 :       *((Byte*)ptr) = (Byte)z;
    1481      528056 :       ptr++;
    1482      528056 :       break;
    1483             :     }
    1484           8 :     case DT_Short:
    1485             :     {
    1486           8 :       short s = (short)z;
    1487           8 :       memcpy(ptr, &s, sizeof(short));
    1488           8 :       ptr += 2;
    1489           8 :       break;
    1490             :     }
    1491           0 :     case DT_UShort:
    1492             :     {
    1493           0 :       unsigned short us = (unsigned short)z;
    1494           0 :       memcpy(ptr, &us, sizeof(unsigned short));
    1495           0 :       ptr += 2;
    1496           0 :       break;
    1497             :     }
    1498           0 :     case DT_Int:
    1499             :     {
    1500           0 :       int i = (int)z;
    1501           0 :       memcpy(ptr, &i, sizeof(int));
    1502           0 :       ptr += 4;
    1503           0 :       break;
    1504             :     }
    1505           0 :     case DT_UInt:
    1506             :     {
    1507           0 :       unsigned int n = (unsigned int)z;
    1508           0 :       memcpy(ptr, &n, sizeof(unsigned int));
    1509           0 :       ptr += 4;
    1510           0 :       break;
    1511             :     }
    1512           0 :     case DT_Float:
    1513             :     {
    1514           0 :       float f = (float)z;
    1515           0 :       memcpy(ptr, &f, sizeof(float));
    1516           0 :       ptr += 4;
    1517           0 :       break;
    1518             :     }
    1519           0 :     case DT_Double:
    1520             :     {
    1521           0 :       memcpy(ptr, &z, sizeof(double));
    1522           0 :       ptr += 8;
    1523           0 :       break;
    1524             :     }
    1525             : 
    1526           0 :     default:
    1527           0 :       return false;
    1528             :   }
    1529             : 
    1530      528077 :   *ppByte = ptr;
    1531      528077 :   return true;
    1532             : }
    1533             : 
    1534             : // -------------------------------------------------------------------------- ;
    1535             : 
    1536             : inline
    1537      203799 : double Lerc2::ReadVariableDataType(const Byte** ppByte, DataType dtUsed)
    1538             : {
    1539      203799 :   const Byte* ptr = *ppByte;
    1540             : 
    1541      203799 :   switch (dtUsed)
    1542             :   {
    1543          13 :     case DT_Char:
    1544             :     {
    1545          13 :       signed char c = *((signed char*)ptr);
    1546          13 :       *ppByte = ptr + 1;
    1547          13 :       return c;
    1548             :     }
    1549      203778 :     case DT_Byte:
    1550             :     {
    1551      203778 :       Byte b = *((Byte*)ptr);
    1552      203778 :       *ppByte = ptr + 1;
    1553      203778 :       return b;
    1554             :     }
    1555           8 :     case DT_Short:
    1556             :     {
    1557             :       short s;
    1558           8 :       memcpy(&s, ptr, sizeof(short));
    1559           8 :       *ppByte = ptr + 2;
    1560           8 :       return s;
    1561             :     }
    1562           0 :     case DT_UShort:
    1563             :     {
    1564             :       unsigned short us;
    1565           0 :       memcpy(&us, ptr, sizeof(unsigned short));
    1566           0 :       *ppByte = ptr + 2;
    1567           0 :       return us;
    1568             :     }
    1569           0 :     case DT_Int:
    1570             :     {
    1571             :       int i;
    1572           0 :       memcpy(&i, ptr, sizeof(int));
    1573           0 :       *ppByte = ptr + 4;
    1574           0 :       return i;
    1575             :     }
    1576           0 :     case DT_UInt:
    1577             :     {
    1578             :       unsigned int n;
    1579           0 :       memcpy(&n, ptr, sizeof(unsigned int));
    1580           0 :       *ppByte = ptr + 4;
    1581           0 :       return n;
    1582             :     }
    1583           0 :     case DT_Float:
    1584             :     {
    1585             :       float f;
    1586           0 :       memcpy(&f, ptr, sizeof(float));
    1587           0 :       *ppByte = ptr + 4;
    1588           0 :       return f;
    1589             :     }
    1590           0 :     case DT_Double:
    1591             :     {
    1592             :       double d;
    1593           0 :       memcpy(&d, ptr, sizeof(double));
    1594           0 :       *ppByte = ptr + 8;
    1595           0 :       return d;
    1596             :     }
    1597           0 :     default:
    1598           0 :       return 0;
    1599             :   }
    1600             : }
    1601             : 
    1602             : // -------------------------------------------------------------------------- ;
    1603             : 
    1604             : template<class T>
    1605        5181 : Lerc2::DataType Lerc2::GetDataType(T z) const
    1606             : {
    1607        5181 :   const std::type_info& ti = typeid(z);
    1608             : 
    1609        5181 :        if (ti == typeid(signed char))     return DT_Char;
    1610        5180 :   else if (ti == typeid(Byte))            return DT_Byte;
    1611          61 :   else if (ti == typeid(short))           return DT_Short;
    1612          59 :   else if (ti == typeid(unsigned short))  return DT_UShort;
    1613          57 :   else if (ti == typeid(int ) && sizeof(int ) == 4)   return DT_Int;
    1614          55 :   else if (ti == typeid(long) && sizeof(long) == 4)   return DT_Int;
    1615          55 :   else if (ti == typeid(unsigned int ) && sizeof(unsigned int ) == 4)   return DT_UInt;
    1616          53 :   else if (ti == typeid(unsigned long) && sizeof(unsigned long) == 4)   return DT_UInt;
    1617          53 :   else if (ti == typeid(float))           return DT_Float;
    1618          26 :   else if (ti == typeid(double))          return DT_Double;
    1619             :   else
    1620           0 :     return DT_Undefined;
    1621             : }
    1622             : 
    1623             : // -------------------------------------------------------------------------- ;
    1624             : 
    1625             : inline
    1626        5172 : unsigned int Lerc2::GetMaxValToQuantize(DataType dt)
    1627             : {
    1628        5172 :   switch (dt)
    1629             :   {
    1630        5123 :     case DT_Char:
    1631             :     case DT_Byte:    //return (1 <<  7) - 1;    // disabled: allow LUT mode for 8 bit segmented
    1632             :     case DT_Short:
    1633        5123 :     case DT_UShort:  return (1 << 15) - 1;
    1634             : 
    1635          49 :     case DT_Int:
    1636             :     case DT_UInt:
    1637             :     case DT_Float:
    1638          49 :     case DT_Double:  return (1 << 30) - 1;
    1639             : 
    1640           0 :     default:
    1641           0 :       return 0;
    1642             :   }
    1643             : }
    1644             : 
    1645             : // -------------------------------------------------------------------------- ;
    1646             : 
    1647             : inline
    1648     2142070 : unsigned int Lerc2::GetDataTypeSize(DataType dt)
    1649             : {
    1650     2142070 :   switch (dt)
    1651             :   {
    1652     2141860 :     case DT_Char:
    1653     2141860 :     case DT_Byte:   return 1;
    1654          42 :     case DT_Short:
    1655          42 :     case DT_UShort: return 2;
    1656         160 :     case DT_Int:
    1657             :     case DT_UInt:
    1658         160 :     case DT_Float:  return 4;
    1659           0 :     case DT_Double: return 8;
    1660             : 
    1661           0 :     default:
    1662           0 :       return 0;
    1663             :   }
    1664             : }
    1665             : 
    1666             : // -------------------------------------------------------------------------- ;
    1667             : 
    1668             : template<class T>
    1669        3327 : void Lerc2::ComputeHuffmanCodes(const T* data, int& numBytes, ImageEncodeMode& imageEncodeMode, std::vector<std::pair<unsigned short, unsigned int> >& codes) const
    1670             : {
    1671        6654 :   std::vector<int> histo, deltaHisto;
    1672        3327 :   ComputeHistoForHuffman(data, histo, deltaHisto);
    1673             : 
    1674        3327 :   int nBytes0 = 0, nBytes1 = 0;
    1675        3327 :   double avgBpp0 = 0, avgBpp1 = 0;
    1676        6654 :   Huffman huffman0, huffman1;
    1677             : 
    1678        3327 :   if (m_headerInfo.version >= 4)
    1679             :   {
    1680         204 :     if (!huffman0.ComputeCodes(histo) || !huffman0.ComputeCompressedSize(histo, nBytes0, avgBpp0))
    1681           0 :       nBytes0 = 0;
    1682             :   }
    1683             : 
    1684        3327 :   if (!huffman1.ComputeCodes(deltaHisto) || !huffman1.ComputeCompressedSize(deltaHisto, nBytes1, avgBpp1))
    1685           0 :     nBytes1 = 0;
    1686             : 
    1687        3327 :   if (nBytes0 > 0 && nBytes1 > 0)    // regular case, pick the better of the two
    1688             :   {
    1689         204 :     imageEncodeMode = (nBytes0 <= nBytes1) ? IEM_Huffman : IEM_DeltaHuffman;
    1690         204 :     codes = (nBytes0 <= nBytes1) ? huffman0.GetCodes() : huffman1.GetCodes();
    1691         204 :     numBytes = (std::min)(nBytes0, nBytes1);
    1692             :   }
    1693        3123 :   else if (nBytes0 == 0 && nBytes1 == 0)    // rare case huffman cannot handle, fall back to tiling
    1694             :   {
    1695           0 :     imageEncodeMode = IEM_Tiling;
    1696           0 :     codes.resize(0);
    1697           0 :     numBytes = 0;
    1698             :   }
    1699             :   else    // rare also, pick the valid one, the other is 0
    1700             :   {
    1701        3123 :     imageEncodeMode = (nBytes0 > nBytes1) ? IEM_Huffman : IEM_DeltaHuffman;
    1702        3123 :     codes = (nBytes0 > nBytes1) ? huffman0.GetCodes() : huffman1.GetCodes();
    1703        3123 :     numBytes = (std::max)(nBytes0, nBytes1);
    1704             :   }
    1705        3327 : }
    1706             : 
    1707             : // -------------------------------------------------------------------------- ;
    1708             : 
    1709             : template<class T>
    1710        3327 : void Lerc2::ComputeHistoForHuffman(const T* data, std::vector<int>& histo, std::vector<int>& deltaHisto) const
    1711             : {
    1712        3327 :   histo.resize(256);
    1713        3327 :   deltaHisto.resize(256);
    1714             : 
    1715        3327 :   memset(&histo[0], 0, histo.size() * sizeof(int));
    1716        3327 :   memset(&deltaHisto[0], 0, deltaHisto.size() * sizeof(int));
    1717             : 
    1718        3327 :   int offset = (m_headerInfo.dt == DT_Char) ? 128 : 0;
    1719        3327 :   int height = m_headerInfo.nRows;
    1720        3327 :   int width = m_headerInfo.nCols;
    1721        3327 :   int nDim = m_headerInfo.nDim;
    1722             : 
    1723        3327 :   if (m_headerInfo.numValidPixel == width * height)    // all valid
    1724             :   {
    1725        6718 :     for (int iDim = 0; iDim < nDim; iDim++)
    1726             :     {
    1727        3391 :       T prevVal = 0;
    1728      423843 :       for (int m = iDim, i = 0; i < height; i++)
    1729    59177320 :         for (int j = 0; j < width; j++, m += nDim)
    1730             :         {
    1731    58756900 :           T val = data[m];
    1732    58756900 :           T delta = val;
    1733             : 
    1734    58756900 :           if (j > 0)
    1735    58336680 :             delta -= prevVal;    // use overflow
    1736      420261 :           else if (i > 0)
    1737      417061 :             delta -= data[m - width * nDim];
    1738             :           else
    1739        3200 :             delta -= prevVal;
    1740             : 
    1741    58756900 :           prevVal = val;
    1742             : 
    1743    58756900 :           histo[offset + (int)val]++;
    1744    58755700 :           deltaHisto[offset + (int)delta]++;
    1745             :         }
    1746             :     }
    1747             :   }
    1748             :   else    // not all valid
    1749             :   {
    1750           0 :     for (int iDim = 0; iDim < nDim; iDim++)
    1751             :     {
    1752           0 :       T prevVal = 0;
    1753           0 :       for (int k = 0, m = iDim, i = 0; i < height; i++)
    1754           0 :         for (int j = 0; j < width; j++, k++, m += nDim)
    1755           0 :           if (m_bitMask.IsValid(k))
    1756             :           {
    1757           0 :             T val = data[m];
    1758           0 :             T delta = val;
    1759             : 
    1760           0 :             if (j > 0 && m_bitMask.IsValid(k - 1))
    1761             :             {
    1762           0 :               delta -= prevVal;    // use overflow
    1763             :             }
    1764           0 :             else if (i > 0 && m_bitMask.IsValid(k - width))
    1765             :             {
    1766           0 :               delta -= data[m - width * nDim];
    1767             :             }
    1768             :             else
    1769           0 :               delta -= prevVal;
    1770             : 
    1771           0 :             prevVal = val;
    1772             : 
    1773           0 :             histo[offset + (int)val]++;
    1774           0 :             deltaHisto[offset + (int)delta]++;
    1775             :           }
    1776             :     }
    1777             :   }
    1778        3327 : }
    1779             : 
    1780             : // -------------------------------------------------------------------------- ;
    1781             : 
    1782             : template<class T>
    1783         640 : bool Lerc2::EncodeHuffman(const T* data, Byte** ppByte) const
    1784             : {
    1785         640 :   if (!data || !ppByte)
    1786           0 :     return false;
    1787             : 
    1788        1280 :   Huffman huffman;
    1789         640 :   if (!huffman.SetCodes(m_huffmanCodes) || !huffman.WriteCodeTable(ppByte, m_headerInfo.version))    // header and code table
    1790           0 :     return false;
    1791             : 
    1792         640 :   int offset = (m_headerInfo.dt == DT_Char) ? 128 : 0;
    1793         640 :   int height = m_headerInfo.nRows;
    1794         640 :   int width = m_headerInfo.nCols;
    1795         640 :   int nDim = m_headerInfo.nDim;
    1796             : 
    1797         640 :   unsigned int* arr = (unsigned int*)(*ppByte);
    1798         640 :   unsigned int* dstPtr = arr;
    1799         640 :   int bitPos = 0;
    1800             : 
    1801         640 :   if (m_imageEncodeMode == IEM_DeltaHuffman)
    1802             :   {
    1803        1039 :     for (int iDim = 0; iDim < nDim; iDim++)
    1804             :     {
    1805         534 :       T prevVal = 0;
    1806       62570 :       for (int k = 0, m = iDim, i = 0; i < height; i++)
    1807     8220130 :         for (int j = 0; j < width; j++, k++, m += nDim)
    1808     8158090 :           if (m_bitMask.IsValid(k))
    1809             :           {
    1810     8157910 :             T val = data[m];
    1811     8157910 :             T delta = val;
    1812             : 
    1813     8157910 :             if (j > 0 && m_bitMask.IsValid(k - 1))
    1814             :             {
    1815     8095680 :               delta -= prevVal;    // use overflow
    1816             :             }
    1817       62052 :             else if (i > 0 && m_bitMask.IsValid(k - width))
    1818             :             {
    1819       61501 :               delta -= data[m - width * nDim];
    1820             :             }
    1821             :             else
    1822         551 :               delta -= prevVal;
    1823             : 
    1824     8157730 :             prevVal = val;
    1825             : 
    1826             :             // bit stuff the huffman code for this delta
    1827     8157730 :             int kBin = offset + (int)delta;
    1828     8157730 :             int len = m_huffmanCodes[kBin].first;
    1829     8157550 :             if (len <= 0)
    1830           0 :               return false;
    1831             : 
    1832     8157550 :             unsigned int code = m_huffmanCodes[kBin].second;
    1833             : 
    1834     8158100 :             if (32 - bitPos >= len)
    1835             :             {
    1836     8040170 :               if (bitPos == 0)
    1837      254850 :                 *dstPtr = 0;
    1838             : 
    1839     8040170 :               *dstPtr |= code << (32 - bitPos - len);
    1840     8040170 :               bitPos += len;
    1841     8040170 :               if (bitPos == 32)
    1842             :               {
    1843      254357 :                 bitPos = 0;
    1844      254357 :                 dstPtr++;
    1845             :               }
    1846             :             }
    1847             :             else
    1848             :             {
    1849      117934 :               bitPos += len - 32;
    1850      117934 :               *dstPtr++ |= code >> bitPos;
    1851      117934 :               *dstPtr = code << (32 - bitPos);
    1852             :             }
    1853             :           }
    1854             :     }
    1855             :   }
    1856             : 
    1857         135 :   else if (m_imageEncodeMode == IEM_Huffman)
    1858             :   {
    1859        5583 :     for (int k = 0, m0 = 0, i = 0; i < height; i++)
    1860     1155140 :       for (int j = 0; j < width; j++, k++, m0 += nDim)
    1861     1149700 :         if (m_bitMask.IsValid(k))
    1862     2299390 :           for (int m = 0; m < nDim; m++)
    1863             :           {
    1864     1149700 :             T val = data[m0 + m];
    1865             : 
    1866             :             // bit stuff the huffman code for this val
    1867     1149700 :             int kBin = offset + (int)val;
    1868     1149700 :             int len = m_huffmanCodes[kBin].first;
    1869     1149700 :             if (len <= 0)
    1870           0 :               return false;
    1871             : 
    1872     1149700 :             unsigned int code = m_huffmanCodes[kBin].second;
    1873             : 
    1874     1149700 :             if (32 - bitPos >= len)
    1875             :             {
    1876     1013540 :               if (bitPos == 0)
    1877       36755 :                 *dstPtr = 0;
    1878             : 
    1879     1013540 :               *dstPtr |= code << (32 - bitPos - len);
    1880     1013540 :               bitPos += len;
    1881     1013540 :               if (bitPos == 32)
    1882             :               {
    1883       36620 :                 bitPos = 0;
    1884       36620 :                 dstPtr++;
    1885             :               }
    1886             :             }
    1887             :             else
    1888             :             {
    1889      136154 :               bitPos += len - 32;
    1890      136154 :               *dstPtr++ |= code >> bitPos;
    1891      136154 :               *dstPtr = code << (32 - bitPos);
    1892             :             }
    1893             :           }
    1894             :   }
    1895             : 
    1896             :   else
    1897           0 :     return false;
    1898             : 
    1899         640 :   size_t numUInts = dstPtr - arr + (bitPos > 0 ? 1 : 0) + 1;    // add one more as the decode LUT can read ahead
    1900         640 :   *ppByte += numUInts * sizeof(unsigned int);
    1901         640 :   return true;
    1902             : }
    1903             : 
    1904             : // -------------------------------------------------------------------------- ;
    1905             : 
    1906             : template<class T>
    1907         409 : bool Lerc2::DecodeHuffman(const Byte** ppByte, size_t& nBytesRemainingInOut, T* data) const
    1908             : {
    1909         409 :   if (!data || !ppByte || !(*ppByte))
    1910           0 :     return false;
    1911             : 
    1912        1765 :   Huffman huffman;
    1913         409 :   if (!huffman.ReadCodeTable(ppByte, nBytesRemainingInOut, m_headerInfo.version))    // header and code table
    1914           0 :     return false;
    1915             : 
    1916         409 :   int numBitsLUT = 0;
    1917         409 :   if (!huffman.BuildTreeFromCodes(numBitsLUT))
    1918           0 :     return false;
    1919             : 
    1920         409 :   int offset = (m_headerInfo.dt == DT_Char) ? 128 : 0;
    1921         409 :   int height = m_headerInfo.nRows;
    1922         409 :   int width = m_headerInfo.nCols;
    1923         409 :   int nDim = m_headerInfo.nDim;
    1924             : 
    1925         409 :   const unsigned int* arr = (const unsigned int*)(*ppByte);
    1926         409 :   const unsigned int* srcPtr = arr;
    1927         409 :   int bitPos = 0;
    1928         409 :   size_t nBytesRemaining = nBytesRemainingInOut;
    1929             : 
    1930         409 :   if (m_headerInfo.numValidPixel == width * height)    // all valid
    1931             :   {
    1932         409 :     if (m_imageEncodeMode == IEM_DeltaHuffman)
    1933             :     {
    1934         519 :       for (int iDim = 0; iDim < nDim; iDim++)
    1935             :       {
    1936         304 :         T prevVal = 0;
    1937       22880 :         for (int m = iDim, i = 0; i < height; i++)
    1938     3082030 :           for (int j = 0; j < width; j++, m += nDim)
    1939             :           {
    1940     3059450 :             int val = 0;
    1941     3059450 :             if (nBytesRemaining >= 4 * sizeof(unsigned int))
    1942             :             {
    1943     3051130 :               if (!huffman.DecodeOneValue_NoOverrunCheck(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
    1944         947 :                 return false;
    1945             :             }
    1946             :             else
    1947             :             {
    1948        8324 :               if (!huffman.DecodeOneValue(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
    1949         947 :                 return false;
    1950             :             }
    1951             : 
    1952     3059450 :             T delta = (T)(val - offset);
    1953             : 
    1954     3059450 :             if (j > 0)
    1955     3037860 :               delta += prevVal;    // use overflow
    1956       21590 :             else if (i > 0)
    1957       22272 :               delta += data[m - width * nDim];
    1958             :             else
    1959           0 :               delta += prevVal;
    1960             : 
    1961     3059450 :             data[m] = delta;
    1962     3059450 :             prevVal = delta;
    1963             :           }
    1964             :       }
    1965             :     }
    1966             : 
    1967         194 :     else if (m_imageEncodeMode == IEM_Huffman)
    1968             :     {
    1969        7830 :       for (int k = 0, m0 = 0, i = 0; i < height; i++)
    1970     1618880 :         for (int j = 0; j < width; j++, k++, m0 += nDim)
    1971     3222500 :           for (int m = 0; m < nDim; m++)
    1972             :           {
    1973     1611250 :             int val = 0;
    1974     1611250 :             if (nBytesRemaining >= 4 * sizeof(unsigned int))
    1975             :             {
    1976     1609205 :               if (!huffman.DecodeOneValue_NoOverrunCheck(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
    1977           0 :                 return false;
    1978             :             }
    1979             :             else
    1980             :             {
    1981        2042 :               if (!huffman.DecodeOneValue(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
    1982           0 :                 return false;
    1983             :             }
    1984             : 
    1985     1611250 :             data[m0 + m] = (T)(val - offset);
    1986             :           }
    1987             :     }
    1988             : 
    1989             :     else
    1990           0 :       return false;
    1991             :   }
    1992             : 
    1993             :   else    // not all valid
    1994             :   {
    1995           0 :     if (m_imageEncodeMode == IEM_DeltaHuffman)
    1996             :     {
    1997           0 :       for (int iDim = 0; iDim < nDim; iDim++)
    1998             :       {
    1999           0 :         T prevVal = 0;
    2000           0 :         for (int k = 0, m = iDim, i = 0; i < height; i++)
    2001           0 :           for (int j = 0; j < width; j++, k++, m += nDim)
    2002           0 :             if (m_bitMask.IsValid(k))
    2003             :             {
    2004           0 :               int val = 0;
    2005           0 :               if (nBytesRemaining >= 4 * sizeof(unsigned int))
    2006             :               {
    2007           0 :                 if (!huffman.DecodeOneValue_NoOverrunCheck(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
    2008           0 :                   return false;
    2009             :               }
    2010             :               else
    2011             :               {
    2012           0 :                 if (!huffman.DecodeOneValue(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
    2013           0 :                   return false;
    2014             :               }
    2015             : 
    2016           0 :               T delta = (T)(val - offset);
    2017             : 
    2018           0 :               if (j > 0 && m_bitMask.IsValid(k - 1))
    2019             :               {
    2020           0 :                 delta += prevVal;    // use overflow
    2021             :               }
    2022           0 :               else if (i > 0 && m_bitMask.IsValid(k - width))
    2023             :               {
    2024           0 :                 delta += data[m - width * nDim];
    2025             :               }
    2026             :               else
    2027           0 :                 delta += prevVal;
    2028             : 
    2029           0 :               data[m] = delta;
    2030           0 :               prevVal = delta;
    2031             :             }
    2032             :       }
    2033             :     }
    2034             : 
    2035           0 :     else if (m_imageEncodeMode == IEM_Huffman)
    2036             :     {
    2037           0 :       for (int k = 0, m0 = 0, i = 0; i < height; i++)
    2038           0 :         for (int j = 0; j < width; j++, k++, m0 += nDim)
    2039           0 :           if (m_bitMask.IsValid(k))
    2040           0 :             for (int m = 0; m < nDim; m++)
    2041             :             {
    2042           0 :               int val = 0;
    2043           0 :               if (nBytesRemaining >= 4 * sizeof(unsigned int))
    2044             :               {
    2045           0 :                 if (!huffman.DecodeOneValue_NoOverrunCheck(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
    2046           0 :                   return false;
    2047             :               }
    2048             :               else
    2049             :               {
    2050           0 :                 if (!huffman.DecodeOneValue(&srcPtr, nBytesRemaining, bitPos, numBitsLUT, val))
    2051           0 :                   return false;
    2052             :               }
    2053             : 
    2054           0 :               data[m0 + m] = (T)(val - offset);
    2055             :             }
    2056             :     }
    2057             : 
    2058             :     else
    2059           0 :       return false;
    2060             :   }
    2061             : 
    2062         409 :   size_t numUInts = srcPtr - arr + (bitPos > 0 ? 1 : 0) + 1;    // add one more as the decode LUT can read ahead
    2063         409 :   size_t len = numUInts * sizeof(unsigned int);
    2064             : 
    2065         409 :   if (nBytesRemainingInOut < len)
    2066           0 :     return false;
    2067             : 
    2068         409 :   *ppByte += len;
    2069         409 :   nBytesRemainingInOut -= len;
    2070         409 :   return true;
    2071             : }
    2072             : 
    2073             : // -------------------------------------------------------------------------- ;
    2074             : 
    2075             : template<class T>
    2076         341 : bool Lerc2::WriteMinMaxRanges(const T* /*data*/, Byte** ppByte) const
    2077             : {
    2078         341 :   if (!ppByte || !(*ppByte))
    2079           0 :     return false;
    2080             : 
    2081             :   //printf("write min / max = %f  %f\n", m_zMinVec[0], m_zMaxVec[0]);
    2082             : 
    2083         341 :   int nDim = m_headerInfo.nDim;
    2084         341 :   if (/* nDim < 2 || */ (int)m_zMinVec.size() != nDim || (int)m_zMaxVec.size() != nDim)
    2085           0 :     return false;
    2086             : 
    2087         341 :   std::vector<T> zVec(nDim);
    2088         342 :   size_t len = nDim * sizeof(T);
    2089             : 
    2090         752 :   for (int i = 0; i < nDim; i++)
    2091         410 :     zVec[i] = (T)m_zMinVec[i];
    2092             : 
    2093         342 :   memcpy(*ppByte, &zVec[0], len);
    2094         341 :   (*ppByte) += len;
    2095             : 
    2096         752 :   for (int i = 0; i < nDim; i++)
    2097         410 :     zVec[i] = (T)m_zMaxVec[i];
    2098             : 
    2099         342 :   memcpy(*ppByte, &zVec[0], len);
    2100         341 :   (*ppByte) += len;
    2101             : 
    2102         341 :   return true;
    2103             : }
    2104             : 
    2105             : // -------------------------------------------------------------------------- ;
    2106             : 
    2107             : template<class T>
    2108         505 : bool Lerc2::ReadMinMaxRanges(const Byte** ppByte, size_t& nBytesRemaining, const T* /*data*/)
    2109             : {
    2110         505 :   if (!ppByte || !(*ppByte))
    2111           0 :     return false;
    2112             : 
    2113         505 :   int nDim = m_headerInfo.nDim;
    2114             : 
    2115         505 :   m_zMinVec.resize(nDim);
    2116         505 :   m_zMaxVec.resize(nDim);
    2117             : 
    2118        1010 :   std::vector<T> zVec(nDim);
    2119         505 :   size_t len = nDim * sizeof(T);
    2120             : 
    2121         505 :   if (nBytesRemaining < len || !memcpy(&zVec[0], *ppByte, len))
    2122           0 :     return false;
    2123             : 
    2124         505 :   (*ppByte) += len;
    2125         505 :   nBytesRemaining -= len;
    2126             : 
    2127        1128 :   for (int i = 0; i < nDim; i++)
    2128         623 :     m_zMinVec[i] = zVec[i];
    2129             : 
    2130         505 :   if (nBytesRemaining < len || !memcpy(&zVec[0], *ppByte, len))
    2131           0 :     return false;
    2132             : 
    2133         505 :   (*ppByte) += len;
    2134         505 :   nBytesRemaining -= len;
    2135             : 
    2136        1128 :   for (int i = 0; i < nDim; i++)
    2137         623 :     m_zMaxVec[i] = zVec[i];
    2138             : 
    2139             :   //printf("read min / max = %f  %f\n", m_zMinVec[0], m_zMaxVec[0]);
    2140             : 
    2141         505 :   return true;
    2142             : }
    2143             : 
    2144             : // -------------------------------------------------------------------------- ;
    2145             : 
    2146             : inline
    2147        1189 : bool Lerc2::CheckMinMaxRanges(bool& minMaxEqual) const
    2148             : {
    2149        1189 :   int nDim = m_headerInfo.nDim;
    2150        1189 :   if ((int)m_zMinVec.size() != nDim || (int)m_zMaxVec.size() != nDim)
    2151           0 :     return false;
    2152             : 
    2153        1188 :   minMaxEqual = (0 == memcmp(&m_zMinVec[0], &m_zMaxVec[0], nDim * sizeof(m_zMinVec[0])));
    2154        1188 :   return true;
    2155             : }
    2156             : 
    2157             : // -------------------------------------------------------------------------- ;
    2158             : 
    2159             : template<class T>
    2160         576 : bool Lerc2::FillConstImage(T* data) const
    2161             : {
    2162         576 :   if (!data)
    2163           0 :     return false;
    2164             : 
    2165         576 :   const HeaderInfo& hd = m_headerInfo;
    2166         576 :   int nCols = hd.nCols;
    2167         576 :   int nRows = hd.nRows;
    2168         576 :   int nDim = hd.nDim;
    2169         576 :   T z0 = (T)hd.zMin;
    2170             : 
    2171         576 :   if (nDim == 1)
    2172             :   {
    2173       72143 :     for (int k = 0, i = 0; i < nRows; i++)
    2174     9231438 :       for (int j = 0; j < nCols; j++, k++)
    2175     9159872 :         if (m_bitMask.IsValid(k))
    2176     9159468 :           data[k] = z0;
    2177             :   }
    2178             :   else
    2179             :   {
    2180           1 :     std::vector<T> zBufVec(nDim, z0);
    2181             : 
    2182           1 :     if (hd.zMin != hd.zMax)
    2183             :     {
    2184           0 :       if ((int)m_zMinVec.size() != nDim)
    2185           0 :         return false;
    2186             : 
    2187           0 :       for (int m = 0; m < nDim; m++)
    2188           0 :         zBufVec[m] = (T)m_zMinVec[m];
    2189             :     }
    2190             : 
    2191           1 :     int len = nDim * sizeof(T);
    2192           3 :     for (int k = 0, m = 0, i = 0; i < nRows; i++)
    2193           6 :       for (int j = 0; j < nCols; j++, k++, m += nDim)
    2194           4 :         if (m_bitMask.IsValid(k))
    2195           3 :           memcpy(&data[m], &zBufVec[0], len);
    2196             :   }
    2197             : 
    2198         576 :   return true;
    2199             : }
    2200             : 
    2201             : // -------------------------------------------------------------------------- ;
    2202             : 
    2203             : NAMESPACE_LERC_END
    2204             : #endif

Generated by: LCOV version 1.14