LCOV - code coverage report
Current view: top level - third_party/LercLib - Lerc2.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 205 233 88.0 %
Date: 2026-07-24 18:27:47 Functions: 14 16 87.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             :                 Lucian Plesea (provided checksum code)
      23             : */
      24             : 
      25             : #include "Defines.h"
      26             : #include "Lerc2.h"
      27             : 
      28             : #include <climits>
      29             : #include <cstdint>
      30             : 
      31             : USING_NAMESPACE_LERC
      32             : using namespace std;
      33             : 
      34           0 : static void ignore_ret_val(bool) {}
      35             : 
      36             : // -------------------------------------------------------------------------- ;
      37             : 
      38        7816 : Lerc2::Lerc2()
      39             : {
      40        7811 :   Init();
      41        7814 : }
      42             : 
      43             : // -------------------------------------------------------------------------- ;
      44             : 
      45           0 : Lerc2::Lerc2(int nDim, int nCols, int nRows, const Byte* pMaskBits)
      46             : {
      47           0 :   Init();
      48           0 :   ignore_ret_val(Set(nDim, nCols, nRows, pMaskBits));
      49           0 : }
      50             : 
      51             : // -------------------------------------------------------------------------- ;
      52             : 
      53        5180 : bool Lerc2::SetEncoderToOldVersion(int version)
      54             : {
      55        5180 :   if (version < 2 || version > kCurrVersion)
      56           0 :     return false;
      57             : 
      58        5180 :   if (version < 4 && m_headerInfo.nDim > 1)
      59           0 :     return false;
      60             : 
      61        5180 :   m_headerInfo.version = version;
      62             : 
      63        5180 :   return true;
      64             : }
      65             : 
      66             : // -------------------------------------------------------------------------- ;
      67             : 
      68        7815 : void Lerc2::Init()
      69             : {
      70        7815 :   m_microBlockSize    = 8;
      71        7815 :   m_maxValToQuantize  = 0;
      72        7815 :   m_encodeMask        = true;
      73        7815 :   m_writeDataOneSweep = false;
      74        7815 :   m_imageEncodeMode   = IEM_Tiling;
      75             : 
      76        7815 :   m_headerInfo.RawInit();
      77        7814 :   m_headerInfo.version = kCurrVersion;
      78        7814 :   m_headerInfo.microBlockSize = m_microBlockSize;
      79        7814 : }
      80             : 
      81             : // -------------------------------------------------------------------------- ;
      82             : 
      83        5181 : bool Lerc2::Set(int nDim, int nCols, int nRows, const Byte* pMaskBits)
      84             : {
      85        5181 :   if (nDim > 1 && m_headerInfo.version < 4)
      86           0 :     return false;
      87             : 
      88        5181 :   if (!m_bitMask.SetSize(nCols, nRows))
      89           0 :     return false;
      90             : 
      91        5181 :   if (pMaskBits)
      92             :   {
      93          18 :     memcpy(m_bitMask.Bits(), pMaskBits, m_bitMask.Size());
      94          18 :     m_headerInfo.numValidPixel = m_bitMask.CountValidBits();
      95             :   }
      96             :   else
      97             :   {
      98        5163 :     m_headerInfo.numValidPixel = nCols * nRows;
      99        5163 :     m_bitMask.SetAllValid();
     100             :   }
     101             : 
     102        5181 :   m_headerInfo.nDim  = nDim;
     103        5181 :   m_headerInfo.nCols = nCols;
     104        5181 :   m_headerInfo.nRows = nRows;
     105             : 
     106        5181 :   return true;
     107             : }
     108             : 
     109             : // -------------------------------------------------------------------------- ;
     110             : 
     111             : //// if the Lerc2 header should ever shrink in size to less than below, then update it (very unlikely)
     112             : //
     113             : //unsigned int Lerc2::MinNumBytesNeededToReadHeader()
     114             : //{
     115             : //  unsigned int numBytes = (unsigned int)FileKey().length();
     116             : //  numBytes += 7 * sizeof(int);
     117             : //  numBytes += 3 * sizeof(double);
     118             : //  return numBytes;
     119             : //}
     120             : 
     121             : // -------------------------------------------------------------------------- ;
     122             : 
     123        7314 : bool Lerc2::GetHeaderInfo(const Byte* pByte, size_t nBytesRemaining, struct HeaderInfo& hd)
     124             : {
     125        7314 :   if (!pByte || !IsLittleEndianSystem())
     126           0 :     return false;
     127             : 
     128        7315 :   return ReadHeader(&pByte, nBytesRemaining, hd);
     129             : }
     130             : 
     131             : // -------------------------------------------------------------------------- ;
     132             : // -------------------------------------------------------------------------- ;
     133             : 
     134        5181 : unsigned int Lerc2::ComputeNumBytesHeaderToWrite(const struct HeaderInfo& hd)
     135             : {
     136        5181 :   unsigned int numBytes = (unsigned int)FileKey().length();
     137        5181 :   numBytes += 1 * sizeof(int);
     138        5181 :   numBytes += (hd.version >= 3 ? 1 : 0) * sizeof(unsigned int);
     139        5181 :   numBytes += (hd.version >= 4 ? 7 : 6) * sizeof(int);
     140        5181 :   numBytes += 3 * sizeof(double);
     141        5181 :   return numBytes;
     142             : }
     143             : 
     144             : // -------------------------------------------------------------------------- ;
     145             : 
     146        5181 : bool Lerc2::WriteHeader(Byte** ppByte, const struct HeaderInfo& hd)
     147             : {
     148        5181 :   if (!ppByte)
     149           0 :     return false;
     150             : 
     151        5181 :   Byte* ptr = *ppByte;
     152             : 
     153       10362 :   string fileKey = FileKey();
     154        5181 :   size_t len = fileKey.length();
     155        5181 :   memcpy(ptr, fileKey.c_str(), len);
     156        5181 :   ptr += len;
     157             : 
     158        5181 :   memcpy(ptr, &hd.version, sizeof(int));
     159        5181 :   ptr += sizeof(int);
     160             : 
     161        5181 :   if (hd.version >= 3)
     162             :   {
     163         370 :     unsigned int checksum = 0;
     164         370 :     memcpy(ptr, &checksum, sizeof(unsigned int));    // place holder to be filled by the real check sum later
     165         370 :     ptr += sizeof(unsigned int);
     166             :   }
     167             : 
     168       10362 :   vector<int> intVec;
     169        5181 :   intVec.push_back(hd.nRows);
     170        5181 :   intVec.push_back(hd.nCols);
     171             : 
     172        5181 :   if (hd.version >= 4)
     173             :   {
     174         370 :     intVec.push_back(hd.nDim);
     175             :   }
     176             : 
     177        5181 :   intVec.push_back(hd.numValidPixel);
     178        5181 :   intVec.push_back(hd.microBlockSize);
     179        5181 :   intVec.push_back(hd.blobSize);
     180        5181 :   intVec.push_back((int)hd.dt);
     181             : 
     182        5181 :   len = intVec.size() * sizeof(int);
     183        5181 :   memcpy(ptr, &intVec[0], len);
     184        5181 :   ptr += len;
     185             : 
     186        5181 :   vector<double> dblVec;
     187        5181 :   dblVec.push_back(hd.maxZError);
     188        5181 :   dblVec.push_back(hd.zMin);
     189        5181 :   dblVec.push_back(hd.zMax);
     190             : 
     191        5181 :   len = dblVec.size() * sizeof(double);
     192        5181 :   memcpy(ptr, &dblVec[0], len);
     193        5181 :   ptr += len;
     194             : 
     195        5181 :   *ppByte = ptr;
     196        5181 :   return true;
     197             : }
     198             : 
     199             : // -------------------------------------------------------------------------- ;
     200             : 
     201        9948 : bool Lerc2::ReadHeader(const Byte** ppByte, size_t& nBytesRemainingInOut, struct HeaderInfo& hd)
     202             : {
     203        9948 :   if (!ppByte || !*ppByte)
     204           9 :     return false;
     205             : 
     206        9939 :   const Byte* ptr = *ppByte;
     207        9939 :   size_t nBytesRemaining = nBytesRemainingInOut;
     208             : 
     209       19878 :   string fileKey = FileKey();
     210        9950 :   size_t keyLen = fileKey.length();
     211             : 
     212        9945 :   hd.RawInit();
     213             : 
     214        9944 :   if (nBytesRemaining < keyLen || memcmp(ptr, fileKey.c_str(), keyLen))
     215        1022 :     return false;
     216             : 
     217        8926 :   ptr += keyLen;
     218        8926 :   nBytesRemaining -= keyLen;
     219             : 
     220        8926 :   if (nBytesRemaining < sizeof(int) || !memcpy(&(hd.version), ptr, sizeof(int)))
     221           0 :     return false;
     222             : 
     223        8926 :   ptr += sizeof(int);
     224        8926 :   nBytesRemaining -= sizeof(int);
     225             : 
     226        8926 :   if (hd.version > kCurrVersion)    // this reader is outdated
     227           0 :     return false;
     228             : 
     229        8926 :   if (hd.version >= 3)
     230             :   {
     231        4084 :     if (nBytesRemaining < sizeof(unsigned int) || !memcpy(&(hd.checksum), ptr, sizeof(unsigned int)))
     232           0 :       return false;
     233             : 
     234        4084 :     ptr += sizeof(unsigned int);
     235        4084 :     nBytesRemaining -= sizeof(unsigned int);
     236             :   }
     237             : 
     238        8926 :   int nInts = (hd.version >= 4) ? 7 : 6;
     239       17843 :   vector<int> intVec(nInts, 0);
     240       17850 :   vector<double> dblVec(3, 0);
     241             : 
     242        8920 :   size_t len = sizeof(int) * intVec.size();
     243             : 
     244        8934 :   if (nBytesRemaining < len || !memcpy(&intVec[0], ptr, len))
     245           0 :     return false;
     246             : 
     247        8929 :   ptr += len;
     248        8929 :   nBytesRemaining -= len;
     249             : 
     250        8929 :   len = sizeof(double) * dblVec.size();
     251             : 
     252        8924 :   if (nBytesRemaining < len || !memcpy(&dblVec[0], ptr, len))
     253           0 :     return false;
     254             : 
     255        8922 :   ptr += len;
     256        8922 :   nBytesRemaining -= len;
     257             : 
     258        8922 :   int i = 0;
     259        8922 :   hd.nRows          = intVec[i++];
     260        8925 :   hd.nCols          = intVec[i++];
     261        8926 :   hd.nDim           = (hd.version >= 4) ? intVec[i++] : 1;
     262        8927 :   hd.numValidPixel  = intVec[i++];
     263        8929 :   hd.microBlockSize = intVec[i++];
     264        8926 :   hd.blobSize       = intVec[i++];
     265        8927 :   const int dt      = intVec[i++];
     266        8925 :   if (hd.nRows <= 0 || hd.nCols <= 0 || hd.nDim <= 0 || hd.numValidPixel < 0
     267        8927 :     || hd.microBlockSize <= 0 || hd.blobSize <= 0 || dt < DT_Char || dt > DT_Double)
     268           0 :     return false;
     269        8925 :   hd.dt             = static_cast<DataType>(dt);
     270             : 
     271        8925 :   hd.maxZError      = dblVec[0];
     272        8926 :   hd.zMin           = dblVec[1];
     273        8926 :   hd.zMax           = dblVec[2];
     274             : 
     275        8927 :   const uint64_t numPixel = (uint64_t)hd.nRows * hd.nCols;
     276        8927 :   if (numPixel > (uint64_t)INT_MAX || (uint64_t)hd.numValidPixel > numPixel)
     277           0 :     return false;
     278             : 
     279        8927 :   *ppByte = ptr;
     280        8927 :   nBytesRemainingInOut = nBytesRemaining;
     281             : 
     282        8927 :   return true;
     283             : }
     284             : 
     285             : // -------------------------------------------------------------------------- ;
     286             : 
     287        5181 : bool Lerc2::WriteMask(Byte** ppByte) const
     288             : {
     289        5181 :   if (!ppByte)
     290           0 :     return false;
     291             : 
     292        5181 :   int numValid = m_headerInfo.numValidPixel;
     293        5181 :   int numTotal = m_headerInfo.nCols * m_headerInfo.nRows;
     294             : 
     295        5181 :   bool needMask = numValid > 0 && numValid < numTotal;
     296             : 
     297        5181 :   Byte* ptr = *ppByte;
     298             : 
     299        5181 :   if (needMask && m_encodeMask)
     300             :   {
     301             :     Byte* pArrRLE;
     302             :     size_t numBytesRLE;
     303           9 :     RLE rle;
     304           9 :     if (!rle.compress((const Byte*)m_bitMask.Bits(), m_bitMask.Size(), &pArrRLE, numBytesRLE, false))
     305           0 :       return false;
     306             : 
     307           9 :     int numBytesMask = (int)numBytesRLE;
     308           9 :     memcpy(ptr, &numBytesMask, sizeof(int));    // num bytes for compressed mask
     309           9 :     ptr += sizeof(int);
     310           9 :     memcpy(ptr, pArrRLE, numBytesRLE);
     311           9 :     ptr += numBytesRLE;
     312             : 
     313          18 :     delete[] pArrRLE;
     314             :   }
     315             :   else
     316             :   {
     317        5172 :     memset(ptr, 0, sizeof(int));    // indicates no mask stored
     318        5172 :     ptr += sizeof(int);
     319             :   }
     320             : 
     321        5181 :   *ppByte = ptr;
     322        5181 :   return true;
     323             : }
     324             : 
     325             : // -------------------------------------------------------------------------- ;
     326             : 
     327        2636 : bool Lerc2::ReadMask(const Byte** ppByte, size_t& nBytesRemainingInOut)
     328             : {
     329        2636 :   if (!ppByte)
     330           0 :     return false;
     331             : 
     332        2636 :   int numValid = m_headerInfo.numValidPixel;
     333        2636 :   int w = m_headerInfo.nCols;
     334        2636 :   int h = m_headerInfo.nRows;
     335             : 
     336        2636 :   const Byte* ptr = *ppByte;
     337        2636 :   size_t nBytesRemaining = nBytesRemainingInOut;
     338             : 
     339             :   int numBytesMask;
     340        2636 :   if (nBytesRemaining < sizeof(int) || !memcpy(&numBytesMask, ptr, sizeof(int)))
     341           0 :     return false;
     342             : 
     343        2636 :   ptr += sizeof(int);
     344        2636 :   nBytesRemaining -= sizeof(int);
     345             : 
     346        2636 :   if (numValid == 0 || numValid == w * h)
     347             :   {
     348        2625 :     if (numBytesMask != 0)
     349           0 :       return false;
     350             :   }
     351             : 
     352        2636 :   if (!m_bitMask.SetSize(w, h))
     353           0 :     return false;
     354             : 
     355        2635 :   if (numValid == 0)
     356           9 :     m_bitMask.SetAllInvalid();
     357        2626 :   else if (numValid == w * h)
     358        2615 :     m_bitMask.SetAllValid();
     359          11 :   else if (numBytesMask > 0)    // read it in
     360             :   {
     361          12 :     if (nBytesRemaining < static_cast<size_t>(numBytesMask))
     362           0 :       return false;
     363             : 
     364          12 :     RLE rle;
     365          12 :     if (!rle.decompress(ptr, nBytesRemaining, m_bitMask.Bits(), m_bitMask.Size()))
     366           0 :       return false;
     367             : 
     368          12 :     ptr += numBytesMask;
     369          12 :     nBytesRemaining -= numBytesMask;
     370             :   }
     371             :   // else use previous mask
     372             : 
     373        2635 :   *ppByte = ptr;
     374        2635 :   nBytesRemainingInOut = nBytesRemaining;
     375             : 
     376        2635 :   return true;
     377             : }
     378             : 
     379             : // -------------------------------------------------------------------------- ;
     380             : 
     381        5181 : bool Lerc2::DoChecksOnEncode(Byte* pBlobBegin, Byte* pBlobEnd) const
     382             : {
     383        5181 :   if ((size_t)(pBlobEnd - pBlobBegin) != (size_t)m_headerInfo.blobSize)
     384           0 :     return false;
     385             : 
     386        5181 :   if (m_headerInfo.version >= 3)
     387             :   {
     388         370 :     int blobSize = (int)(pBlobEnd - pBlobBegin);
     389         370 :     int nBytes = (int)(FileKey().length() + sizeof(int) + sizeof(unsigned int));    // start right after the checksum entry
     390         370 :     if (blobSize < nBytes)
     391           0 :       return false;
     392         370 :     unsigned int checksum = ComputeChecksumFletcher32(pBlobBegin + nBytes, blobSize - nBytes);
     393             : 
     394         370 :     nBytes -= sizeof(unsigned int);
     395         370 :     memcpy(pBlobBegin + nBytes, &checksum, sizeof(unsigned int));
     396             :   }
     397             : 
     398        5181 :   return true;
     399             : }
     400             : 
     401             : // -------------------------------------------------------------------------- ;
     402             : 
     403             : // from  https://en.wikipedia.org/wiki/Fletcher's_checksum
     404             : // modified from ushorts to bytes (by Lucian Plesea)
     405             : 
     406        1393 : unsigned int Lerc2::ComputeChecksumFletcher32(const Byte* pByte, int len)
     407             : {
     408        1393 :   unsigned int sum1 = 0xffff, sum2 = 0xffff;
     409        1393 :   unsigned int words = len / 2;
     410             : 
     411        8830 :   while (words)
     412             :   {
     413        7437 :     unsigned int tlen = (words >= 359) ? 359 : words;
     414        7437 :     words -= tlen;
     415     2411450 :     do {
     416     2418890 :       sum1 += (*pByte++ << 8);
     417     2418890 :       sum2 += sum1 += *pByte++;
     418     2418890 :     } while (--tlen);
     419             : 
     420        7437 :     sum1 = (sum1 & 0xffff) + (sum1 >> 16);
     421        7437 :     sum2 = (sum2 & 0xffff) + (sum2 >> 16);
     422             :   }
     423             : 
     424             :   // add the straggler byte if it exists
     425        1393 :   if (len & 1)
     426         637 :     sum2 += sum1 += (*pByte << 8);
     427             : 
     428             :   // second reduction step to reduce sums to 16 bits
     429        1393 :   sum1 = (sum1 & 0xffff) + (sum1 >> 16);
     430        1393 :   sum2 = (sum2 & 0xffff) + (sum2 >> 16);
     431             : 
     432        1393 :   return sum2 << 16 | sum1;
     433             : }
     434             : 
     435             : // -------------------------------------------------------------------------- ;
     436             : 
     437             : //struct MyLessThanOp
     438             : //{
     439             : //  inline bool operator() (const pair<unsigned int, unsigned int>& p0,
     440             : //                          const pair<unsigned int, unsigned int>& p1)  { return p0.first < p1.first; }
     441             : //};
     442             : 
     443             : // -------------------------------------------------------------------------- ;
     444             : 
     445      709569 : void Lerc2::SortQuantArray(const vector<unsigned int>& quantVec, vector<pair<unsigned int, unsigned int> >& sortedQuantVec)
     446             : {
     447      709569 :   int numElem = (int)quantVec.size();
     448      709569 :   sortedQuantVec.resize(numElem);
     449             : 
     450    71881600 :   for (int i = 0; i < numElem; i++)
     451    71172000 :     sortedQuantVec[i] = pair<unsigned int, unsigned int>(quantVec[i], i);
     452             : 
     453             :   //std::sort(sortedQuantVec.begin(), sortedQuantVec.end(), MyLessThanOp());
     454             : 
     455      709569 :   std::sort(sortedQuantVec.begin(), sortedQuantVec.end(),
     456   371995000 :     [](const pair<unsigned int, unsigned int>& p0,
     457   371995000 :        const pair<unsigned int, unsigned int>& p1) { return p0.first < p1.first; });
     458      709569 : }
     459             : 
     460             : // -------------------------------------------------------------------------- ;
     461             : 

Generated by: LCOV version 1.14