LCOV - code coverage report
Current view: top level - frmts/mrf/LERCV1 - Lerc1Image.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 477 540 88.3 %
Date: 2024-11-21 22:18:42 Functions: 23 23 100.0 %

          Line data    Source code
       1             : /*
       2             : Copyright 2015 - 2024 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             : A local copy of the license and additional notices are located with the
      16             : source distribution at:
      17             : 
      18             : http://github.com/Esri/lerc/
      19             : 
      20             : Contributors:  Thomas Maurer
      21             :                Lucian Plesea
      22             : */
      23             : 
      24             : #include "Lerc1Image.h"
      25             : #include <cstdint>
      26             : #include <cmath>
      27             : #include <cfloat>
      28             : #include <climits>
      29             : #include <string>
      30             : #include <algorithm>
      31             : 
      32             : NAMESPACE_LERC1_START
      33             : 
      34             : // max quantized value, 28 bits
      35             : // It is wasting a few bits, because a float has only 24bits of precision
      36             : static const double MAXQ = 0x1000000;
      37             : 
      38             : // RLE constants
      39             : static const int MAX_RUN = 32767;
      40             : static const int MIN_RUN = 5;
      41             : // End of Transmission
      42             : static const int EOT = -(MAX_RUN + 1);
      43             : 
      44             : // Decode a RLE bitmask, size should be already set
      45             : // Returns false if input seems wrong
      46             : // Zero size mask is fine, only checks the end marker
      47          16 : bool BitMaskV1::RLEdecompress(const Byte *src, size_t n)
      48             : {
      49          16 :     Byte *dst = bits.data();
      50          16 :     int sz = size();
      51             :     short int count;
      52             : 
      53             : // Read a low endian short int
      54             : #define READ_COUNT                                                             \
      55             :     if (true)                                                                  \
      56             :     {                                                                          \
      57             :         if (n < 2)                                                             \
      58             :             return false;                                                      \
      59             :         count = *src++;                                                        \
      60             :         count += (*src++ << 8);                                                \
      61             :     }
      62             : 
      63        5021 :     while (sz > 0)
      64             :     {  // One sequence per loop
      65        5005 :         READ_COUNT;
      66        5005 :         n -= 2;
      67        5005 :         if (count < 0)
      68             :         {  // negative count for repeats
      69        3222 :             if (0 == n)
      70           0 :                 return false;
      71        3222 :             --n;  // only decrement after checking for 0 to avoid a (harmless)
      72             :                   // unsigned integer overflow warning with ossfuzz
      73        3222 :             Byte b = *src++;
      74        3222 :             sz += count;
      75        3222 :             if (sz < 0)
      76           0 :                 return false;
      77      523624 :             while (0 != count++)
      78      520402 :                 *dst++ = b;
      79             :         }
      80             :         else
      81             :         {  // No repeats, count is positive
      82        1783 :             if (sz < count || n < static_cast<size_t>(count))
      83           0 :                 return false;
      84        1783 :             sz -= count;
      85        1783 :             n -= count;
      86        6056 :             while (0 != count--)
      87        4273 :                 *dst++ = *src++;
      88             :         }
      89             :     }
      90          16 :     READ_COUNT;
      91          16 :     return (count == EOT);
      92             : }
      93             : 
      94             : // Encode helper function
      95             : // It returns how many times the byte at *s is repeated
      96             : // a value between 1 and min(max_count, MAX_RUN)
      97        5296 : inline static int run_length(const Byte *s, int max_count)
      98             : {
      99        5296 :     if (max_count > MAX_RUN)
     100          24 :         max_count = MAX_RUN;
     101      786894 :     for (int i = 1; i < max_count; i++)
     102      786870 :         if (s[0] != s[i])
     103        5272 :             return i;
     104          24 :     return max_count;
     105             : }
     106             : 
     107             : // RLE compressed size is bound by n + 4 + 2 * (n - 1) / 32767
     108          12 : int BitMaskV1::RLEcompress(Byte *dst) const
     109             : {
     110          12 :     const Byte *src = bits.data();  // Next input byte
     111          12 :     Byte *start = dst;
     112          12 :     int sz = size();   // left to process
     113          12 :     Byte *pCnt = dst;  // Pointer to current sequence count
     114          12 :     int oddrun = 0;    // non-repeated byte count
     115             : 
     116             : // Store val as short low endian integer
     117             : #define WRITE_COUNT(val)                                                       \
     118             :     if (true)                                                                  \
     119             :     {                                                                          \
     120             :         *pCnt++ = Byte(val & 0xff);                                            \
     121             :         *pCnt++ = Byte(val >> 8);                                              \
     122             :     }
     123             : // Flush an existing odd run
     124             : #define FLUSH                                                                  \
     125             :     if (oddrun)                                                                \
     126             :     {                                                                          \
     127             :         WRITE_COUNT(oddrun);                                                   \
     128             :         pCnt += oddrun;                                                        \
     129             :         dst = pCnt + 2;                                                        \
     130             :         oddrun = 0;                                                            \
     131             :     }
     132             : 
     133          12 :     dst += 2;  // Skip the space for the first count
     134        2660 :     while (sz > 0)
     135             :     {
     136        2648 :         int run = run_length(src, sz);
     137        2648 :         if (run < MIN_RUN)
     138             :         {  // Use one byte
     139         817 :             *dst++ = *src++;
     140         817 :             sz--;
     141         817 :             if (MAX_RUN == ++oddrun)
     142           0 :                 FLUSH;
     143             :         }
     144             :         else
     145             :         {  // Found a run
     146        1831 :             FLUSH;
     147        1831 :             WRITE_COUNT(-run);
     148        1831 :             *pCnt++ = *src;
     149        1831 :             src += run;
     150        1831 :             sz -= run;
     151             :             // cppcheck-suppress redundantAssignment
     152        1831 :             dst = pCnt + 2;  // after the next marker
     153             :         }
     154             :     }
     155             :     // cppcheck-suppress uselessAssignmentPtrArg
     156          12 :     FLUSH;
     157             :     (void)oddrun;
     158             :     (void)dst;
     159          12 :     WRITE_COUNT(EOT);  // End marker
     160             :     // return compressed output size
     161          12 :     return int(pCnt - start);
     162             : }
     163             : 
     164             : // calculate encoded size
     165          12 : int BitMaskV1::RLEsize() const
     166             : {
     167          12 :     const Byte *src = bits.data();  // Next input byte
     168          12 :     int sz = size();                // left to process
     169          12 :     int oddrun = 0;                 // current non-repeated byte count
     170             :     // Simulate an odd run flush
     171             : #define SIMFLUSH                                                               \
     172             :     if (oddrun)                                                                \
     173             :     {                                                                          \
     174             :         osz += oddrun + 2;                                                     \
     175             :         oddrun = 0;                                                            \
     176             :     }
     177          12 :     int osz = 2;  // output size, start with size of end marker
     178        2660 :     while (sz)
     179             :     {
     180        2648 :         int run = run_length(src, sz);
     181        2648 :         if (run < MIN_RUN)
     182             :         {
     183         817 :             src++;
     184         817 :             sz--;
     185         817 :             if (MAX_RUN == ++oddrun)
     186           0 :                 SIMFLUSH;
     187             :         }
     188             :         else
     189             :         {
     190        1831 :             SIMFLUSH;
     191        1831 :             src += run;
     192        1831 :             sz -= run;
     193        1831 :             osz += 3;  // Any run is 3 bytes
     194             :         }
     195             :     }
     196          12 :     return oddrun ? (osz + oddrun + 2) : osz;
     197             : }
     198             : 
     199             : // Lookup tables for number of bytes in float and int, forward and reverse
     200             : static const Byte bits67[4] = {0x80, 0x40, 0xc0, 0};  // shifted left 6 bits
     201             : static const Byte stib67[4] = {4, 2, 1, 0};           // Last one is not used
     202             : 
     203       15766 : static int numBytesUInt(unsigned int k)
     204             : {
     205       15766 :     return (k <= 0xff) ? 1 : (k <= 0xffff) ? 2 : 4;
     206             : }
     207             : 
     208             : // Index of top set bit, counting from 1
     209       15766 : static int nBits(unsigned int v)
     210             : {
     211       15766 :     int r = int(0 != (v >> 16)) << 4;
     212       15766 :     v >>= r;
     213       15766 :     int t = int(0 != (v >> 8)) << 3;
     214       15766 :     v >>= t;
     215       15766 :     r += t;
     216       15766 :     t = int(0 != (v >> 4)) << 2;
     217       15766 :     v = (v >> t) << 1;
     218       15766 :     return 1 + r + t + int((0xffffaa50ul >> v) & 0x3);
     219             : }
     220             : 
     221        2459 : static bool blockread(Byte **ppByte, size_t &size, std::vector<unsigned int> &d)
     222             : {
     223        2459 :     if (!ppByte || !size)
     224           0 :         return false;
     225             : 
     226        2459 :     Byte numBits = **ppByte;
     227        2459 :     Byte n = stib67[numBits >> 6];
     228        2459 :     numBits &= 63;  // bits 0-5;
     229             :     // cppcheck-suppress knownConditionTrueFalse
     230        2459 :     if (numBits >= 32 || n == 0 || size < 1 + static_cast<size_t>(n))
     231           0 :         return false;
     232        2459 :     *ppByte += 1;
     233        2459 :     size -= 1;
     234             : 
     235        2459 :     unsigned int numElements = 0;
     236        2459 :     memcpy(&numElements, *ppByte, n);
     237        2459 :     *ppByte += n;
     238        2459 :     size -= n;
     239        2459 :     if (static_cast<size_t>(numElements) > d.size())
     240           0 :         return false;
     241        2459 :     if (numBits == 0)
     242             :     {  // Nothing to read, all zeros
     243           0 :         d.resize(0);
     244           0 :         d.resize(numElements, 0);
     245           0 :         return true;
     246             :     }
     247             : 
     248        2459 :     d.resize(numElements);
     249        2459 :     unsigned int numBytes = (numElements * numBits + 7) / 8;
     250        2459 :     if (size < numBytes)
     251           0 :         return false;
     252        2459 :     size -= numBytes;
     253             : 
     254        2459 :     int bits = 0;  // Available in accumulator, at the high end
     255        2459 :     unsigned int acc = 0;
     256      172685 :     for (unsigned int &val : d)
     257             :     {
     258      170226 :         if (bits >= numBits)
     259             :         {  // Enough bits in accumulator
     260      132540 :             val = acc >> (32 - numBits);
     261      132540 :             acc <<= numBits;
     262      132540 :             bits -= numBits;
     263      132540 :             continue;
     264             :         }
     265             : 
     266             :         // Need to reload the accumulator
     267       37686 :         val = 0;
     268       37686 :         if (bits)
     269             :         {
     270       18883 :             val = acc >> (32 - bits);
     271       18883 :             val <<= (numBits - bits);
     272             :         }
     273       37686 :         unsigned int nb = std::min(numBytes, 4u);
     274       37686 :         if (4u == nb)
     275       37489 :             memcpy(&acc, *ppByte, 4);
     276             :         else  // Read only a few bytes at the high end of acc
     277         197 :             memcpy(reinterpret_cast<Byte *>(&acc) + (4 - nb), *ppByte, nb);
     278       37686 :         *ppByte += nb;
     279       37686 :         numBytes -= nb;
     280             : 
     281       37686 :         bits += 32 - numBits;
     282       37686 :         val |= acc >> bits;
     283       37686 :         acc <<= 32 - bits;
     284             :     }
     285        2459 :     return numBytes == 0;
     286             : }
     287             : 
     288             : static const int CNT_Z = 8;
     289             : static const int CNT_Z_VER = 11;
     290             : static const std::string sCntZImage("CntZImage ");  // Includes a space
     291             : 
     292             : // computes the size of a CntZImage of any width and height, but all void /
     293             : // invalid, and then compressed
     294        1647 : unsigned int Lerc1Image::computeNumBytesNeededToWriteVoidImage()
     295             : {
     296             :     unsigned int sz =
     297        1647 :         (unsigned int)sCntZImage.size() + 4 * sizeof(int) + sizeof(double);
     298             :     // cnt part
     299        1647 :     sz += 3 * sizeof(int) + sizeof(float);
     300             :     // z part, 1 is the empty Tile if all invalid
     301        1647 :     sz += 3 * sizeof(int) + sizeof(float) + 1;
     302        1647 :     return sz;  // 67
     303             : }
     304             : 
     305             : unsigned int
     306          12 : Lerc1Image::computeNumBytesNeededToWrite(double maxZError, bool onlyZPart,
     307             :                                          InfoFromComputeNumBytes *info) const
     308             : {
     309             :     unsigned int sz =
     310          12 :         (unsigned int)(sCntZImage.size() + 4 * sizeof(int) + sizeof(double));
     311          12 :     if (!onlyZPart)
     312             :     {
     313          12 :         auto m = mask.IsValid(0);
     314          12 :         info->numTilesVertCnt = 0;
     315          12 :         info->numTilesHoriCnt = 0;
     316          12 :         info->maxCntInImg = m;
     317          12 :         info->numBytesCnt = 0;
     318        1500 :         for (int i = 0; i < getSize(); i++)
     319        1500 :             if (m != mask.IsValid(i))
     320             :             {
     321          12 :                 info->numBytesCnt = mask.RLEsize();
     322          12 :                 info->maxCntInImg = 1;
     323          12 :                 break;
     324             :             }
     325          12 :         sz += 3 * sizeof(int) + sizeof(float) + info->numBytesCnt;
     326             :     }
     327             : 
     328             :     // z part
     329             :     int numTilesVert, numTilesHori, numBytesOpt;
     330             :     float maxValInImg;
     331          12 :     if (!findTiling(maxZError, numTilesVert, numTilesHori, numBytesOpt,
     332             :                     maxValInImg))
     333           0 :         return 0;
     334             : 
     335          12 :     info->maxZError = maxZError;
     336          12 :     info->numTilesVertZ = numTilesVert;
     337          12 :     info->numTilesHoriZ = numTilesHori;
     338          12 :     info->numBytesZ = numBytesOpt;
     339          12 :     info->maxZInImg = maxValInImg;
     340             : 
     341          12 :     sz += 3 * sizeof(int) + sizeof(float) + numBytesOpt;
     342          12 :     return sz;
     343             : }
     344             : 
     345             : // if you change the file format, don't forget to update not only write and
     346             : // read functions, and the file version number, but also the computeNumBytes...
     347             : // and numBytes... functions
     348          12 : bool Lerc1Image::write(Byte **ppByte, double maxZError, bool zPart) const
     349             : {
     350             : // Local macro, write an unaligned variable, adjust pointer
     351             : #define WRVAR(VAR, PTR)                                                        \
     352             :     memcpy((PTR), &(VAR), sizeof(VAR));                                        \
     353             :     (PTR) += sizeof(VAR)
     354          12 :     if (getSize() == 0)
     355           0 :         return false;
     356             : 
     357             :     // signature
     358          12 :     memcpy(*ppByte, sCntZImage.c_str(), sCntZImage.size());
     359          12 :     *ppByte += sCntZImage.size();
     360             : 
     361          12 :     int height = getHeight();
     362          12 :     int width = getWidth();
     363          12 :     WRVAR(CNT_Z_VER, *ppByte);
     364          12 :     WRVAR(CNT_Z, *ppByte);
     365          12 :     WRVAR(height, *ppByte);
     366          12 :     WRVAR(width, *ppByte);
     367          12 :     WRVAR(maxZError, *ppByte);
     368             : 
     369          12 :     InfoFromComputeNumBytes info;
     370          12 :     if (0 == computeNumBytesNeededToWrite(maxZError, zPart, &info))
     371           0 :         return false;
     372             : 
     373          24 :     do
     374             :     {
     375          24 :         int numTilesVert, numTilesHori, numBytesOpt, numBytesWritten = 0;
     376             :         float maxValInImg;
     377             : 
     378          24 :         if (!zPart)
     379             :         {
     380          12 :             numTilesVert = info.numTilesVertCnt;
     381          12 :             numTilesHori = info.numTilesHoriCnt;
     382          12 :             numBytesOpt = info.numBytesCnt;
     383          12 :             maxValInImg = info.maxCntInImg;
     384             :         }
     385             :         else
     386             :         {
     387          12 :             numTilesVert = info.numTilesVertZ;
     388          12 :             numTilesHori = info.numTilesHoriZ;
     389          12 :             numBytesOpt = info.numBytesZ;
     390          12 :             maxValInImg = info.maxZInImg;
     391             :         }
     392             : 
     393          24 :         WRVAR(numTilesVert, *ppByte);
     394          24 :         WRVAR(numTilesHori, *ppByte);
     395          24 :         WRVAR(numBytesOpt, *ppByte);
     396          24 :         WRVAR(maxValInImg, *ppByte);
     397             : 
     398          24 :         if (!zPart && numTilesVert == 0 && numTilesHori == 0)
     399             :         {                         // no tiling for cnt part
     400          12 :             if (numBytesOpt > 0)  // cnt part is binary mask, use fast RLE class
     401          12 :                 numBytesWritten = mask.RLEcompress(*ppByte);
     402             :         }
     403             :         else
     404             :         {  // encode tiles to buffer, always z part
     405             :             float maxVal;
     406          12 :             if (!writeTiles(maxZError, numTilesVert, numTilesHori, *ppByte,
     407             :                             numBytesWritten, maxVal))
     408           0 :                 return false;
     409             :         }
     410             : 
     411          24 :         if (numBytesWritten != numBytesOpt)
     412           0 :             return false;
     413             : 
     414          24 :         *ppByte += numBytesWritten;
     415          24 :         zPart = !zPart;
     416             :     } while (zPart);
     417          12 :     return true;
     418             : #undef WRVAR
     419             : }
     420             : 
     421             : // To avoid excessive memory allocation attempts, this is still 1.8GB!!
     422             : static size_t TOO_LARGE = 1800 * 1000 * 1000 / static_cast<int>(sizeof(float));
     423             : 
     424          16 : bool Lerc1Image::read(Byte **ppByte, size_t &nRemainingBytes, double maxZError,
     425             :                       bool ZPart)
     426             : {
     427             : // Local macro, read an unaligned variable, adjust pointer
     428             : #define RDVAR(PTR, VAR)                                                        \
     429             :     memcpy(&(VAR), (PTR), sizeof(VAR));                                        \
     430             :     (PTR) += sizeof(VAR)
     431             : 
     432          16 :     size_t len = sCntZImage.length();
     433          16 :     if (nRemainingBytes < len)
     434           0 :         return false;
     435             : 
     436          32 :     std::string typeStr(reinterpret_cast<char *>(*ppByte), len);
     437          16 :     if (typeStr != sCntZImage)
     438           0 :         return false;
     439          16 :     *ppByte += len;
     440          16 :     nRemainingBytes -= len;
     441             : 
     442          16 :     int version = 0, type = 0;
     443          16 :     int width = 0, height = 0;
     444          16 :     double maxZErrorInFile = 0;
     445             : 
     446          16 :     if (nRemainingBytes < (4 * sizeof(int) + sizeof(double)))
     447           0 :         return false;
     448          16 :     RDVAR(*ppByte, version);
     449          16 :     RDVAR(*ppByte, type);
     450          16 :     RDVAR(*ppByte, height);
     451          16 :     RDVAR(*ppByte, width);
     452          16 :     RDVAR(*ppByte, maxZErrorInFile);
     453          16 :     nRemainingBytes -= 4 * sizeof(int) + sizeof(double);
     454             : 
     455          16 :     if (version != CNT_Z_VER || type != CNT_Z)
     456           0 :         return false;
     457          16 :     if (width <= 0 || width > 20000 || height <= 0 || height > 20000 ||
     458          16 :         maxZErrorInFile > maxZError)
     459           0 :         return false;
     460          16 :     if (static_cast<size_t>(width) * height > TOO_LARGE)
     461           0 :         return false;
     462             : 
     463          16 :     if (ZPart)
     464             :     {
     465           0 :         if (width != getWidth() || height != getHeight())
     466           0 :             return false;
     467             :     }
     468             :     else
     469             :     {  // Resize clears the buffer
     470          16 :         resize(width, height);
     471             :     }
     472             : 
     473          32 :     do
     474             :     {
     475          32 :         int numTilesVert = 0, numTilesHori = 0, numBytes = 0;
     476          32 :         float maxValInImg = 0;
     477          32 :         if (nRemainingBytes < 3 * sizeof(int) + sizeof(float))
     478           0 :             return false;
     479          32 :         RDVAR(*ppByte, numTilesVert);
     480          32 :         RDVAR(*ppByte, numTilesHori);
     481          32 :         RDVAR(*ppByte, numBytes);
     482          32 :         RDVAR(*ppByte, maxValInImg);
     483          32 :         nRemainingBytes -= 3 * sizeof(int) + sizeof(float);
     484             : 
     485          32 :         if (numBytes < 0 || nRemainingBytes < static_cast<size_t>(numBytes))
     486           0 :             return false;
     487          32 :         if (ZPart)
     488             :         {
     489          16 :             if (!readTiles(maxZErrorInFile, numTilesVert, numTilesHori,
     490             :                            maxValInImg, *ppByte, numBytes))
     491           0 :                 return false;
     492             :         }
     493             :         else
     494             :         {  // no tiling allowed for the cnt part
     495          16 :             if (numTilesVert != 0 && numTilesHori != 0)
     496           0 :                 return false;
     497          16 :             if (numBytes == 0)
     498             :             {  // cnt part is const
     499           0 :                 if (maxValInImg != 0.0 && maxValInImg != 1.0)
     500           0 :                     return false;  // Only 0 and 1 are valid
     501           0 :                 bool v = (maxValInImg != 0.0);
     502           0 :                 for (int k = 0; k < getSize(); k++)
     503           0 :                     mask.Set(k, v);
     504             :             }
     505             :             else
     506             :             {  // cnt part is binary mask, RLE compressed
     507          16 :                 if (!mask.RLEdecompress(*ppByte, static_cast<size_t>(numBytes)))
     508           0 :                     return false;
     509             :             }
     510             :         }
     511          32 :         *ppByte += numBytes;
     512          32 :         nRemainingBytes -= numBytes;
     513          32 :         ZPart = !ZPart;
     514             :     } while (ZPart);  // Stop after writing Z
     515          16 :     return true;
     516             : }
     517             : 
     518             : // Initialize from the given header, return true if it worked
     519             : // It could read more info from the header, if needed
     520           5 : bool Lerc1Image::getwh(const Byte *pByte, size_t nBytes, int &width,
     521             :                        int &height)
     522             : {
     523           5 :     size_t len = sCntZImage.length();
     524           5 :     if (nBytes < len)
     525           0 :         return false;
     526             : 
     527          10 :     std::string typeStr(reinterpret_cast<const char *>(pByte), len);
     528           5 :     if (typeStr != sCntZImage)
     529           0 :         return false;
     530           5 :     pByte += len;
     531           5 :     nBytes -= len;
     532             : 
     533           5 :     int version = 0, type = 0;
     534           5 :     double maxZErrorInFile = 0;
     535             : 
     536           5 :     if (nBytes < (4 * sizeof(int) + sizeof(double)))
     537           0 :         return false;
     538           5 :     RDVAR(pByte, version);
     539           5 :     RDVAR(pByte, type);
     540           5 :     RDVAR(pByte, height);
     541           5 :     RDVAR(pByte, width);
     542           5 :     RDVAR(pByte, maxZErrorInFile);
     543             :     (void)pByte;
     544             : 
     545           5 :     if (version != CNT_Z_VER || type != CNT_Z)
     546           0 :         return false;
     547           5 :     if (width <= 0 || width > 20000 || height <= 0 || height > 20000)
     548           0 :         return false;
     549           5 :     if (static_cast<size_t>(width) * height > TOO_LARGE)
     550           0 :         return false;
     551             : 
     552           5 :     return true;
     553             : #undef RDVAR
     554             : }
     555             : 
     556          12 : bool Lerc1Image::findTiling(double maxZError, int &numTilesVertA,
     557             :                             int &numTilesHoriA, int &numBytesOptA,
     558             :                             float &maxValInImgA) const
     559             : {
     560             :     // entire image as 1 block, this is usually the worst case
     561          12 :     numTilesVertA = numTilesHoriA = 1;
     562          12 :     if (!writeTiles(maxZError, 1, 1, nullptr, numBytesOptA, maxValInImgA))
     563           0 :         return false;
     564             :     // The actual figure may be different due to round-down
     565          12 :     static const std::vector<int> tileWidthArr = {8, 11, 15, 20, 32, 64};
     566          17 :     for (auto tileWidth : tileWidthArr)
     567             :     {
     568          17 :         int numTilesVert = static_cast<int>(getHeight() / tileWidth);
     569          17 :         int numTilesHori = static_cast<int>(getWidth() / tileWidth);
     570             : 
     571          17 :         if (numTilesVert * numTilesHori < 2)
     572           0 :             return true;
     573             : 
     574          17 :         int numBytes = 0;
     575             :         float maxVal;
     576          17 :         if (!writeTiles(maxZError, numTilesVert, numTilesHori, nullptr,
     577             :                         numBytes, maxVal))
     578           0 :             return false;
     579          17 :         if (numBytes > numBytesOptA)
     580          12 :             break;  // Stop when size start to increase
     581           5 :         if (numBytes < numBytesOptA)
     582             :         {
     583           5 :             numTilesVertA = numTilesVert;
     584           5 :             numTilesHoriA = numTilesHori;
     585           5 :             numBytesOptA = numBytes;
     586             :         }
     587             :     }
     588          12 :     return true;
     589             : }
     590             : 
     591             : // n is 1, 2 or 4
     592        3883 : static Byte *writeFlt(Byte *ptr, float z, int n)
     593             : {
     594        3883 :     if (4 == n)
     595         125 :         memcpy(ptr, &z, 4);
     596        3758 :     else if (1 == n)
     597        3589 :         *ptr = static_cast<Byte>(static_cast<signed char>(z));
     598             :     else
     599             :     {
     600         169 :         signed short s = static_cast<signed short>(z);
     601         169 :         memcpy(ptr, &s, 2);
     602             :     }
     603        3883 :     return ptr + n;
     604             : }
     605             : 
     606             : // Only small, exact integer values return 1 or 2, otherwise 4
     607       20434 : static int numBytesFlt(float z)
     608             : {
     609       20434 :     if (!std::isfinite(z) || z > SHRT_MAX || z < SHRT_MIN || z != int16_t(z))
     610        6974 :         return 4;
     611       13460 :     if (z > SCHAR_MAX || z < SCHAR_MIN)
     612         668 :         return 2;
     613       12792 :     return 1;
     614             : }
     615             : 
     616       16695 : static int numBytesZTile(int nValues, float zMin, float zMax, double maxZError)
     617             : {
     618       16695 :     if (nValues == 0 || (zMin == 0 && zMax == 0))
     619           0 :         return 1;
     620       33310 :     if (maxZError == 0 || !std::isfinite(zMin) || !std::isfinite(zMax) ||
     621       16615 :         ((double)zMax - zMin) / (2 * maxZError) > MAXQ)  // max of 28 bits
     622          80 :         return (int)(1 + nValues * sizeof(float));       // Stored as such
     623       16615 :     unsigned int maxElem = static_cast<unsigned int>(
     624       16615 :         ((double)zMax - zMin) / (2 * maxZError) + 0.5);
     625       16615 :     int nb = 1 + numBytesFlt(zMin);
     626       16615 :     if (maxElem == 0)
     627        3304 :         return nb;
     628       13311 :     return nb + 1 + numBytesUInt(nValues) + (nValues * nBits(maxElem) + 7) / 8;
     629             : }
     630             : 
     631             : // Pass bArr == nullptr to estimate the size but skip the write
     632          41 : bool Lerc1Image::writeTiles(double maxZError, int numTilesV, int numTilesH,
     633             :                             Byte *bArr, int &numBytes, float &maxValInImg) const
     634             : {
     635          41 :     if (numTilesV == 0 || numTilesH == 0)
     636           0 :         return false;
     637          41 :     numBytes = 0;
     638          41 :     maxValInImg = -FLT_MAX;
     639          41 :     int tileHeight = static_cast<int>(getHeight() / numTilesV);
     640          41 :     int tileWidth = static_cast<int>(getWidth() / numTilesH);
     641        1291 :     for (int v0 = 0; v0 < getHeight(); v0 += tileHeight)
     642             :     {
     643        1250 :         int v1 = std::min(getHeight(), v0 + tileHeight);
     644       74980 :         for (int h0 = 0; h0 < getWidth(); h0 += tileWidth)
     645             :         {
     646       73730 :             int h1 = std::min(getWidth(), h0 + tileWidth);
     647       73730 :             float zMin = 0, zMax = 0;
     648       73730 :             int numValidPixel = 0, numFinite = 0;
     649       73730 :             if (!computeZStats(v0, v1, h0, h1, zMin, zMax, numValidPixel,
     650             :                                numFinite))
     651           0 :                 return false;
     652             : 
     653       73730 :             if (maxValInImg < zMax)
     654         125 :                 maxValInImg = zMax;
     655             : 
     656       73730 :             int numBytesNeeded = 1;
     657       73730 :             if (numValidPixel != 0)
     658             :             {
     659       10613 :                 if (numFinite == 0 && numValidPixel == (v1 - v0) * (h1 - h0) &&
     660         287 :                     isallsameval(v0, v1, h0, h1))
     661         287 :                     numBytesNeeded = 5;  // Stored as non-finite constant block
     662             :                 else
     663             :                 {
     664             :                     numBytesNeeded =
     665       10039 :                         numBytesZTile(numValidPixel, zMin, zMax, maxZError);
     666             :                     // Try moving zMin up by almost maxZError,
     667             :                     // it may require fewer bytes
     668       10039 :                     float zm = static_cast<float>(zMin + 0.999999 * maxZError);
     669       10039 :                     if (numFinite == numValidPixel && zm <= zMax)
     670             :                     {
     671             :                         int nBN =
     672        6655 :                             numBytesZTile(numValidPixel, zm, zMax, maxZError);
     673             :                         // Maybe an int value for zMin saves a few bytes?
     674        6655 :                         if (zMin < floorf(zm))
     675             :                         {
     676           1 :                             int nBNi = numBytesZTile(numValidPixel, floorf(zm),
     677             :                                                      zMax, maxZError);
     678           1 :                             if (nBNi < nBN)
     679             :                             {
     680           1 :                                 zm = floorf(zm);
     681           1 :                                 nBN = nBNi;
     682             :                             }
     683             :                         }
     684        6655 :                         if (nBN < numBytesNeeded)
     685             :                         {
     686           2 :                             zMin = zm;
     687           2 :                             numBytesNeeded = nBN;
     688             :                         }
     689             :                     }
     690             :                 }
     691             :             }
     692       73730 :             numBytes += numBytesNeeded;
     693             : 
     694       73730 :             if (bArr)
     695             :             {  // Skip the write if no pointer was provided
     696       14505 :                 int numBytesWritten = 0;
     697       14569 :                 if (numFinite == 0 && numValidPixel == (v1 - v0) * (h1 - h0) &&
     698          64 :                     isallsameval(v0, v1, h0, h1))
     699             :                 {
     700             :                     // direct write as non-finite const block, 4 byte float
     701          64 :                     *bArr++ = 3;  // 3 | bits67[3]
     702          64 :                     bArr = writeFlt(bArr, (*this)(v0, h0), sizeof(float));
     703          64 :                     numBytesWritten = 5;
     704             :                 }
     705             :                 else
     706             :                 {
     707       14441 :                     if (!writeZTile(&bArr, numBytesWritten, v0, v1, h0, h1,
     708             :                                     numValidPixel, zMin, zMax, maxZError))
     709           0 :                         return false;
     710             :                 }
     711       14505 :                 if (numBytesWritten != numBytesNeeded)
     712           0 :                     return false;
     713             :             }
     714             :         }
     715             :     }
     716          41 :     return true;
     717             : }
     718             : 
     719          16 : bool Lerc1Image::readTiles(double maxZErrorInFile, int numTilesV, int numTilesH,
     720             :                            float maxValInImg, Byte *bArr,
     721             :                            size_t nRemainingBytes)
     722             : {
     723          16 :     if (numTilesV == 0 || numTilesH == 0)
     724           0 :         return false;
     725          16 :     int tileHeight = static_cast<int>(getHeight() / numTilesV);
     726          16 :     int tileWidth = static_cast<int>(getWidth() / numTilesH);
     727          16 :     if (tileWidth <= 0 || tileHeight <= 0)  // Prevent infinite loop
     728           0 :         return false;
     729         267 :     for (int r0 = 0; r0 < getHeight(); r0 += tileHeight)
     730             :     {
     731         251 :         int r1 = std::min(getHeight(), r0 + tileHeight);
     732       14760 :         for (int c0 = 0; c0 < getWidth(); c0 += tileWidth)
     733             :         {
     734       14509 :             int c1 = std::min(getWidth(), c0 + tileWidth);
     735       14509 :             if (!readZTile(&bArr, nRemainingBytes, r0, r1, c0, c1,
     736             :                            maxZErrorInFile, maxValInImg))
     737           0 :                 return false;
     738             :         }
     739             :     }
     740          16 :     return true;
     741             : }
     742             : 
     743       73730 : bool Lerc1Image::computeZStats(int r0, int r1, int c0, int c1, float &zMin,
     744             :                                float &zMax, int &numValidPixel,
     745             :                                int &numFinite) const
     746             : {
     747       73730 :     if (r0 < 0 || c0 < 0 || r1 > getHeight() || c1 > getWidth())
     748           0 :         return false;
     749       73730 :     zMin = FLT_MAX;
     750       73730 :     zMax = -FLT_MAX;
     751       73730 :     numValidPixel = 0;
     752       73730 :     numFinite = 0;
     753      713730 :     for (int row = r0; row < r1; row++)
     754    11387900 :         for (int col = c0; col < c1; col++)
     755    10747900 :             if (IsValid(row, col))
     756             :             {
     757     1050370 :                 numValidPixel++;
     758     1050370 :                 float val = (*this)(row, col);
     759     1050370 :                 if (std::isfinite(val))
     760     1005590 :                     numFinite++;
     761             :                 else
     762       44785 :                     zMin = NAN;  // Serves as a flag, this block will be stored
     763     1050370 :                 if (val < zMin)
     764       32396 :                     zMin = val;
     765     1050370 :                 if (val > zMax)
     766       37154 :                     zMax = val;
     767             :             }
     768       73730 :     if (0 == numValidPixel)
     769       63404 :         zMin = zMax = 0;
     770       73730 :     return true;
     771             : }
     772             : 
     773             : // Returns true if all floats in the region have exactly the same binary
     774             : // representation This makes it usable for non-finite values
     775         351 : bool Lerc1Image::isallsameval(int r0, int r1, int c0, int c1) const
     776             : {
     777         351 :     uint32_t val = *reinterpret_cast<const uint32_t *>(&(*this)(r0, c0));
     778        3959 :     for (int row = r0; row < r1; row++)
     779       42168 :         for (int col = c0; col < c1; col++)
     780       38560 :             if (val != *reinterpret_cast<const uint32_t *>(&(*this)(row, col)))
     781           0 :                 return false;
     782         351 :     return true;
     783             : }
     784             : 
     785             : //
     786             : // Assumes that buffer at *ppByte is large enough for this particular block
     787             : // Returns number of bytes used in numBytes
     788             : //
     789       14441 : bool Lerc1Image::writeZTile(Byte **ppByte, int &numBytes, int r0, int r1,
     790             :                             int c0, int c1, int numValidPixel, float zMin,
     791             :                             float zMax, double maxZError) const
     792             : {
     793       14441 :     Byte *ptr = *ppByte;
     794       14441 :     int cntPixel = 0;
     795       14441 :     if (numValidPixel == 0 || (zMin == 0 && zMax == 0))
     796             :     {
     797       10603 :         *(*ppByte)++ = 2;  // mark tile as constant 0
     798       10603 :         numBytes = 1;
     799       10603 :         return true;
     800             :     }
     801        7657 :     if (maxZError == 0 || !std::isfinite(zMin) || !std::isfinite(zMax) ||
     802        3819 :         ((double)zMax - zMin) / (2 * maxZError) > MAXQ)
     803             :     {  // store valid pixels as floating point
     804          19 :         *ptr++ = 0;
     805         228 :         for (int row = r0; row < r1; row++)
     806        2508 :             for (int col = c0; col < c1; col++)
     807        2299 :                 if (IsValid(row, col))
     808             :                 {
     809        2123 :                     memcpy(ptr, &((*this)(row, col)), sizeof(float));
     810        2123 :                     ptr += sizeof(float);
     811        2123 :                     cntPixel++;
     812             :                 }
     813          19 :         if (cntPixel != numValidPixel)
     814           0 :             return false;
     815             :     }
     816             :     else
     817             :     {
     818        3819 :         Byte flag = 1;               // bitstuffed int array
     819        3819 :         double f = 0.5 / maxZError;  // conversion to int multiplier
     820        3819 :         unsigned int maxElem = (unsigned int)(((double)zMax - zMin) * f + 0.5);
     821        3819 :         if (maxElem == 0)
     822        1364 :             flag = 3;               // mark tile as constant zMin
     823        3819 :         int n = numBytesFlt(zMin);  // n in { 1, 2, 4 }
     824        3819 :         *ptr++ = (flag | bits67[n - 1]);
     825        3819 :         ptr = writeFlt(ptr, zMin, n);
     826        3819 :         if (maxElem > 0)
     827             :         {
     828        2455 :             int numBits = nBits(maxElem);
     829        2455 :             n = numBytesUInt(numValidPixel);
     830             :             // use bits67 to encode the type used for numElements: Byte, ushort, or uint
     831             :             // n is in {1, 2, 4}
     832             :             // 0xc0 is invalid, will trigger an error
     833        2455 :             *ptr++ = static_cast<Byte>(numBits | bits67[n - 1]);
     834        2455 :             memcpy(ptr, &numValidPixel, n);
     835        2455 :             ptr += n;
     836             : 
     837        2455 :             unsigned int acc = 0;  // Accumulator
     838        2455 :             int bits = 32;         // Available
     839             : 
     840       26310 :             for (int row = r0; row < r1; row++)
     841     2281090 :                 for (int col = c0; col < c1; col++)
     842     2257240 :                     if (IsValid(row, col))
     843             :                     {
     844      162134 :                         cntPixel++;
     845             :                         auto val = static_cast<unsigned int>(
     846      162134 :                             ((double)(*this)(row, col) - zMin) * f + 0.5);
     847             : 
     848      162134 :                         if (bits >= numBits)
     849             :                         {  // no accumulator overflow
     850      131812 :                             acc |= val << (bits - numBits);
     851      131812 :                             bits -= numBits;
     852             :                         }
     853             :                         else
     854             :                         {  // accum overflowing
     855       30322 :                             acc |= val >> (numBits - bits);
     856       30322 :                             memcpy(ptr, &acc, sizeof(acc));
     857       30322 :                             ptr += sizeof(acc);
     858       30322 :                             bits += 32 - numBits;  // under 32
     859       30322 :                             acc = val << bits;
     860             :                         }
     861             :                     }
     862             : 
     863        2455 :             if (cntPixel != numValidPixel)
     864           0 :                 return false;
     865             : 
     866             :             // There are between 1 and 4 bytes left in the accumulator
     867        2455 :             int nbytes = 4;
     868        2747 :             while (bits >= 8)
     869             :             {
     870         292 :                 acc >>= 8;
     871         292 :                 bits -= 8;
     872         292 :                 nbytes--;
     873             :             }
     874        2455 :             memcpy(ptr, &acc, nbytes);
     875        2455 :             ptr += nbytes;
     876             :         }
     877             :     }
     878             : 
     879        3838 :     numBytes = static_cast<int>(ptr - *ppByte);
     880        3838 :     *ppByte = ptr;
     881        3838 :     return true;
     882             : }
     883             : 
     884             : // Read a float encoded as unsigned char, signed short or float
     885             : // n is the number of bytes
     886        3887 : static float readFlt(const Byte *ptr, int n)
     887             : {
     888        3887 :     if (n == 4)
     889             :     {
     890             :         float val;
     891         128 :         memcpy(&val, ptr, 4);
     892         128 :         return val;
     893             :     }
     894        3759 :     if (n == 2)
     895             :     {
     896             :         signed short s;
     897         169 :         memcpy(&s, ptr, 2);
     898         169 :         return static_cast<float>(s);
     899             :     }
     900        3590 :     return static_cast<float>(static_cast<signed char>(*ptr));
     901             : }
     902             : 
     903       14509 : bool Lerc1Image::readZTile(Byte **ppByte, size_t &nRemainingBytes, int r0,
     904             :                            int r1, int c0, int c1, double maxZErrorInFile,
     905             :                            float maxZInImg)
     906             : {
     907       14509 :     Byte *ptr = *ppByte;
     908             : 
     909       14509 :     if (nRemainingBytes < 1)
     910           0 :         return false;
     911       14509 :     Byte comprFlag = *ptr++;
     912       14509 :     nRemainingBytes -= 1;
     913             :     // Used if bit-stuffed
     914       14509 :     Byte n = stib67[comprFlag >> 6];
     915       14509 :     comprFlag &= 63;
     916             :     // cppcheck-suppress knownConditionTrueFalse
     917       14509 :     if (n == 0 || comprFlag > 3)
     918           0 :         return false;
     919             : 
     920       14509 :     if (comprFlag == 2)
     921             :     {  // entire zTile is 0
     922      101387 :         for (int row = r0; row < r1; row++)
     923      881936 :             for (int col = c0; col < c1; col++)
     924      791152 :                 (*this)(row, col) = 0.0f;
     925       10603 :         *ppByte = ptr;
     926       10603 :         return true;
     927             :     }
     928             : 
     929        3906 :     if (comprFlag == 0)
     930             :     {  // Stored
     931         228 :         for (int row = r0; row < r1; row++)
     932        2508 :             for (int col = c0; col < c1; col++)
     933        2299 :                 if (IsValid(row, col))
     934             :                 {
     935        2123 :                     if (nRemainingBytes < sizeof(float))
     936           0 :                         return false;
     937        2123 :                     memcpy(&(*this)(row, col), ptr, sizeof(float));
     938        2123 :                     ptr += sizeof(float);
     939        2123 :                     nRemainingBytes -= sizeof(float);
     940             :                 }
     941          19 :         *ppByte = ptr;
     942          19 :         return true;
     943             :     }
     944             : 
     945        3887 :     if (nRemainingBytes < n)
     946           0 :         return false;
     947        3887 :     float minval = readFlt(ptr, n);
     948        3887 :     ptr += n;
     949        3887 :     nRemainingBytes -= n;
     950             : 
     951        3887 :     if (comprFlag == 3)
     952             :     {  // all min val, regardless of mask
     953       13044 :         for (int row = r0; row < r1; row++)
     954      106656 :             for (int col = c0; col < c1; col++)
     955       95040 :                 (*this)(row, col) = minval;
     956        1428 :         *ppByte = ptr;
     957        1428 :         return true;
     958             :     }
     959             : 
     960        2459 :     idataVec.resize((r1 - r0) * (c1 - c0));  // max size, gets adjusted
     961        2459 :     if (!blockread(&ptr, nRemainingBytes, idataVec))
     962           0 :         return false;
     963             : 
     964        2459 :     size_t numValid = idataVec.size();
     965        2459 :     size_t i = 0;
     966        2459 :     double q = maxZErrorInFile * 2;  // quanta
     967       28365 :     for (int row = r0; row < r1; row++)
     968     3334790 :         for (int col = c0; col < c1; col++)
     969     3308890 :             if (IsValid(row, col))
     970             :             {
     971      170226 :                 if (i >= numValid)
     972           0 :                     return false;
     973      170226 :                 (*this)(row, col) = std::min(
     974      340452 :                     maxZInImg, static_cast<float>(minval + q * idataVec[i++]));
     975             :             }
     976        2459 :     if (i != numValid)
     977           0 :         return false;
     978             : 
     979        2459 :     *ppByte = ptr;
     980        2459 :     return true;
     981             : }
     982             : 
     983             : NAMESPACE_LERC1_END

Generated by: LCOV version 1.14