LCOV - code coverage report
Current view: top level - frmts/rmf - rmfdem.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 309 349 88.5 %
Date: 2025-05-31 00:00:17 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Raster Matrix Format
       4             :  * Purpose:  Implementation of the ad-hoc compression algorithm used in
       5             :  *           GIS "Panorama"/"Integratsia".
       6             :  * Author:   Andrey Kiselev, dron@ak4719.spb.edu
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2009, Andrey Kiselev <dron@ak4719.spb.edu>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_conv.h"
      15             : 
      16             : #include "rmfdataset.h"
      17             : 
      18             : #include <limits>
      19             : 
      20             : /*
      21             :  * The encoded data stream is a series of records.
      22             :  *
      23             :  * Encoded record consist from the 1-byte record header followed by the
      24             :  * encoded data block. Header specifies the number of elements in the data
      25             :  * block and encoding type. Header format
      26             :  *
      27             :  * +---+---+---+---+---+---+---+---+
      28             :  * |   type    |       count       |
      29             :  * +---+---+---+---+---+---+---+---+
      30             :  *   7   6   5   4   3   2   1   0
      31             :  *
      32             :  * If count is zero then it means that there are more than 31 elements in this
      33             :  * record. Read the next byte in the stream and increase its value with 32 to
      34             :  * get the count. In this case maximum number of elements is 287.
      35             :  *
      36             :  * The "type" field specifies encoding type. It can be either difference
      37             :  * between the previous and the next data value (for the first element the
      38             :  * previous value is zero) or out-of-range codes.
      39             :  *
      40             :  * In case of "out of range" or "zero difference" values there are no more
      41             :  * elements in record after the header. Otherwise read as much encoded
      42             :  * elements as count specifies.
      43             :  */
      44             : 
      45             : typedef GInt32 DEMWorkT;
      46             : typedef GInt64 DEMDiffT;
      47             : 
      48             : // Encoding types
      49             : enum RmfTypes
      50             : {
      51             :     TYPE_OUT = 0x00,    // Value is out of range
      52             :     TYPE_ZERO = 0x20,   // Zero difference
      53             :     TYPE_INT4 = 0x40,   // Difference is 4-bit wide
      54             :     TYPE_INT8 = 0x60,   // Difference is 8-bit wide
      55             :     TYPE_INT12 = 0x80,  // Difference is 12-bit wide
      56             :     TYPE_INT16 = 0xA0,  // Difference is 16-bit wide
      57             :     TYPE_INT24 = 0xC0,  // Difference is 24-bit wide
      58             :     TYPE_INT32 = 0xE0   // Difference is 32-bit wide
      59             : };
      60             : 
      61             : // Encoding ranges
      62             : GInt32 RANGE_INT4 = 0x00000007L;   // 4-bit
      63             : GInt32 RANGE_INT8 = 0x0000007FL;   // 8-bit
      64             : GInt32 RANGE_INT12 = 0x000007FFL;  // 12-bit
      65             : GInt32 RANGE_INT16 = 0x00007FFFL;  // 16-bit
      66             : GInt32 RANGE_INT24 = 0x007FFFFFL;  // 24-bit
      67             : 
      68             : // Out of range codes
      69             : GInt32 OUT_INT4 = 0xFFFFFFF8;
      70             : GInt32 OUT_INT8 = 0xFFFFFF80;
      71             : GInt32 OUT_INT12 = 0xFFFFF800;
      72             : GInt32 OUT_INT16 = 0xFFFF8000;
      73             : GInt32 OUT_INT24 = 0xFF800000;
      74             : GInt32 OUT_INT32 = 0x80000000;
      75             : 
      76             : constexpr DEMDiffT DIFF_OUI_OF_RANGE = std::numeric_limits<DEMDiffT>::max();
      77             : 
      78             : // Inversion masks
      79             : GInt32 INV_INT4 = 0xFFFFFFF0L;
      80             : GInt32 INV_INT12 = 0xFFFFF000L;
      81             : GInt32 INV_INT24 = 0xFF000000L;
      82             : 
      83             : // Not sure which behavior we wish for int32 overflow, so just do the
      84             : // addition as uint32 to workaround -ftrapv
      85             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
      86      542772 : static GInt32 AddInt32(GInt32 &nTarget, GInt32 nVal)
      87             : {
      88      542772 :     GUInt32 nTargetU = static_cast<GUInt32>(nTarget);
      89      542772 :     GUInt32 nValU = static_cast<GUInt32>(nVal);
      90      542772 :     nTargetU += nValU;
      91      542772 :     memcpy(&nTarget, &nTargetU, 4);
      92      542772 :     return nTarget;
      93             : }
      94             : 
      95             : /************************************************************************/
      96             : /*                           DEMDecompress()                            */
      97             : /************************************************************************/
      98             : 
      99          18 : size_t RMFDataset::DEMDecompress(const GByte *pabyIn, GUInt32 nSizeIn,
     100             :                                  GByte *pabyOut, GUInt32 nSizeOut, GUInt32,
     101             :                                  GUInt32)
     102             : {
     103          18 :     if (pabyIn == nullptr || pabyOut == nullptr || nSizeOut < nSizeIn ||
     104             :         nSizeIn < 2)
     105           0 :         return 0;
     106             : 
     107          18 :     GInt32 iPrev = 0;  // The last data value decoded.
     108             : 
     109          18 :     const signed char *pabyTempIn =
     110             :         reinterpret_cast<const signed char *>(pabyIn);
     111          18 :     GInt32 *paiOut = reinterpret_cast<GInt32 *>(pabyOut);
     112          18 :     nSizeOut /= sizeof(GInt32);
     113             : 
     114       61662 :     while (nSizeIn > 0)
     115             :     {
     116             :         // Read number of codes in the record and encoding type.
     117       61644 :         GUInt32 nCount = *pabyTempIn & 0x1F;
     118       61644 :         const GUInt32 nType = *pabyTempIn++ & 0xE0;  // The encoding type.
     119       61644 :         nSizeIn--;
     120       61644 :         if (nCount == 0)
     121             :         {
     122        1668 :             if (nSizeIn == 0)
     123           0 :                 break;
     124        1668 :             nCount = 32 + *reinterpret_cast<const GByte *>(pabyTempIn);
     125        1668 :             pabyTempIn++;
     126        1668 :             nSizeIn--;
     127             :         }
     128             : 
     129       61644 :         switch (nType)
     130             :         {
     131       17994 :             case TYPE_ZERO:
     132       17994 :                 if (nSizeOut < nCount)
     133           0 :                     break;
     134       17994 :                 nSizeOut -= nCount;
     135       98978 :                 while (nCount > 0)
     136             :                 {
     137       80984 :                     nCount--;
     138       80984 :                     *paiOut++ = iPrev;
     139             :                 }
     140       17994 :                 break;
     141             : 
     142        1564 :             case TYPE_OUT:
     143        1564 :                 if (nSizeOut < nCount)
     144           0 :                     break;
     145        1564 :                 nSizeOut -= nCount;
     146       26086 :                 while (nCount > 0)
     147             :                 {
     148       24522 :                     nCount--;
     149       24522 :                     *paiOut++ = OUT_INT32;
     150             :                 }
     151        1564 :                 break;
     152             : 
     153        1874 :             case TYPE_INT4:
     154        1874 :                 if (nSizeIn < (nCount + 1) / 2)
     155           0 :                     break;
     156        1874 :                 if (nSizeOut < nCount)
     157           0 :                     break;
     158        1874 :                 nSizeIn -= nCount / 2;
     159        1874 :                 nSizeOut -= nCount;
     160        4902 :                 while (nCount > 0)
     161             :                 {
     162        4014 :                     nCount--;
     163             :                     GInt32 nCode;
     164        4014 :                     nCode = (*pabyTempIn) & 0x0F;
     165        4014 :                     if (nCode > RANGE_INT4)
     166        1752 :                         nCode |= INV_INT4;
     167        4014 :                     *paiOut++ = (nCode == OUT_INT4) ? OUT_INT32
     168        3994 :                                                     : AddInt32(iPrev, nCode);
     169             : 
     170        4014 :                     if (nCount == 0)
     171             :                     {
     172         986 :                         if (nSizeIn)
     173             :                         {
     174         986 :                             pabyTempIn++;
     175         986 :                             nSizeIn--;
     176             :                         }
     177         986 :                         break;
     178             :                     }
     179        3028 :                     nCount--;
     180             : 
     181        3028 :                     nCode = ((*pabyTempIn++) >> 4) & 0x0F;
     182        3028 :                     if (nCode > RANGE_INT4)
     183        1222 :                         nCode |= INV_INT4;
     184        6036 :                     *paiOut++ = (nCode == OUT_INT4) ? OUT_INT32
     185        3008 :                                                     : AddInt32(iPrev, nCode);
     186             :                 }
     187        1874 :                 break;
     188             : 
     189        5924 :             case TYPE_INT8:
     190        5924 :                 if (nSizeIn < nCount)
     191           0 :                     break;
     192        5924 :                 if (nSizeOut < nCount)
     193           0 :                     break;
     194        5924 :                 nSizeIn -= nCount;
     195        5924 :                 nSizeOut -= nCount;
     196       50708 :                 while (nCount > 0)
     197             :                 {
     198       44784 :                     nCount--;
     199             :                     GInt32 nCode;
     200       44784 :                     *paiOut++ = ((nCode = *pabyTempIn++) == OUT_INT8)
     201       44784 :                                     ? OUT_INT32
     202       44766 :                                     : AddInt32(iPrev, nCode);
     203             :                 }
     204        5924 :                 break;
     205             : 
     206       15482 :             case TYPE_INT12:
     207       15482 :                 if (nSizeIn < (3 * nCount + 1) / 2)
     208           0 :                     break;
     209       15482 :                 if (nSizeOut < nCount)
     210           0 :                     break;
     211       15482 :                 nSizeIn -= 3 * nCount / 2;
     212       15482 :                 nSizeOut -= nCount;
     213             : 
     214       78758 :                 while (nCount > 0)
     215             :                 {
     216       71274 :                     nCount--;
     217       71274 :                     GInt32 nCode = CPL_LSBSINT16PTR(pabyTempIn) & 0x0FFF;
     218       71274 :                     pabyTempIn += 1;
     219       71274 :                     if (nCode > RANGE_INT12)
     220       39394 :                         nCode |= INV_INT12;
     221       71274 :                     *paiOut++ = (nCode == OUT_INT12) ? OUT_INT32
     222       70578 :                                                      : AddInt32(iPrev, nCode);
     223             : 
     224       71274 :                     if (nCount == 0)
     225             :                     {
     226        7998 :                         if (nSizeIn)
     227             :                         {
     228        7998 :                             pabyTempIn++;
     229        7998 :                             nSizeIn--;
     230             :                         }
     231        7998 :                         break;
     232             :                     }
     233       63276 :                     nCount--;
     234             : 
     235       63276 :                     nCode = (CPL_LSBSINT16PTR(pabyTempIn) >> 4) & 0x0FFF;
     236       63276 :                     pabyTempIn += 2;
     237       63276 :                     if (nCode > RANGE_INT12)
     238       35672 :                         nCode |= INV_INT12;
     239      125870 :                     *paiOut++ = (nCode == OUT_INT12) ? OUT_INT32
     240       62594 :                                                      : AddInt32(iPrev, nCode);
     241             :                 }
     242       15482 :                 break;
     243             : 
     244       17958 :             case TYPE_INT16:
     245       17958 :                 if (nSizeIn < 2 * nCount)
     246           0 :                     break;
     247       17958 :                 if (nSizeOut < nCount)
     248           0 :                     break;
     249       17958 :                 nSizeIn -= 2 * nCount;
     250       17958 :                 nSizeOut -= nCount;
     251             : 
     252      263522 :                 while (nCount > 0)
     253             :                 {
     254      245564 :                     nCount--;
     255      245564 :                     const GInt32 nCode = CPL_LSBSINT16PTR(pabyTempIn);
     256      245564 :                     pabyTempIn += 2;
     257      485978 :                     *paiOut++ = (nCode == OUT_INT16) ? OUT_INT32
     258      240414 :                                                      : AddInt32(iPrev, nCode);
     259             :                 }
     260       17958 :                 break;
     261             : 
     262         676 :             case TYPE_INT24:
     263         676 :                 if (nSizeIn < 3 * nCount)
     264           0 :                     break;
     265         676 :                 if (nSizeOut < nCount)
     266           0 :                     break;
     267         676 :                 nSizeIn -= 3 * nCount;
     268         676 :                 nSizeOut -= nCount;
     269             : 
     270       70290 :                 while (nCount > 0)
     271             :                 {
     272       69614 :                     nCount--;
     273       69614 :                     GInt32 nCode =
     274       69614 :                         (*reinterpret_cast<const GByte *>(pabyTempIn)) |
     275       69614 :                         ((*reinterpret_cast<const GByte *>(pabyTempIn + 1))
     276       69614 :                          << 8) |
     277       69614 :                         ((*reinterpret_cast<const GByte *>(pabyTempIn + 2))
     278       69614 :                          << 16);
     279       69614 :                     pabyTempIn += 3;
     280       69614 :                     if (nCode > RANGE_INT24)
     281       31998 :                         nCode |= INV_INT24;
     282      137972 :                     *paiOut++ = (nCode == OUT_INT24) ? OUT_INT32
     283       68358 :                                                      : AddInt32(iPrev, nCode);
     284             :                 }
     285         676 :                 break;
     286             : 
     287         172 :             case TYPE_INT32:
     288         172 :                 if (nSizeIn < 4 * nCount)
     289           0 :                     break;
     290         172 :                 if (nSizeOut < nCount)
     291           0 :                     break;
     292         172 :                 nSizeIn -= 4 * nCount;
     293         172 :                 nSizeOut -= nCount;
     294             : 
     295       49232 :                 while (nCount > 0)
     296             :                 {
     297       49060 :                     nCount--;
     298       49060 :                     GInt32 nCode = CPL_LSBSINT32PTR(pabyTempIn);
     299       49060 :                     pabyTempIn += 4;
     300       98120 :                     *paiOut++ = (nCode == OUT_INT32) ? OUT_INT32
     301       49060 :                                                      : AddInt32(iPrev, nCode);
     302             :                 }
     303         172 :                 break;
     304             :         }
     305             :     }
     306             : 
     307          18 :     return reinterpret_cast<GByte *>(paiOut) - pabyOut;
     308             : }
     309             : 
     310             : /************************************************************************/
     311             : /*                            DEMWriteCode()                            */
     312             : /************************************************************************/
     313             : 
     314        1212 : static CPLErr DEMWriteRecord(const DEMDiffT *paiRecord, RmfTypes eRecordType,
     315             :                              GUInt32 nRecordSize, GInt32 nSizeOut,
     316             :                              GByte *&pabyCurrent)
     317             : {
     318        1212 :     const GUInt32 nMaxCountInHeader = 31;
     319             :     GInt32 iCode;
     320             :     GInt32 iPrevCode;
     321             : 
     322        1212 :     if (nRecordSize <= nMaxCountInHeader)
     323             :     {
     324         481 :         nSizeOut -= 1;
     325         481 :         if (nSizeOut <= 0)
     326             :         {
     327           0 :             return CE_Failure;
     328             :         }
     329             : 
     330         481 :         *pabyCurrent++ = static_cast<GByte>(eRecordType | nRecordSize);
     331             :     }
     332             :     else
     333             :     {
     334         731 :         nSizeOut -= 2;
     335         731 :         if (nSizeOut <= 0)
     336             :         {
     337           0 :             return CE_Failure;
     338             :         }
     339             : 
     340         731 :         *pabyCurrent++ = static_cast<GByte>(eRecordType);
     341         731 :         *pabyCurrent++ = static_cast<GByte>(nRecordSize - 32);
     342             :     }
     343             : 
     344        1212 :     switch (eRecordType)
     345             :     {
     346          46 :         case TYPE_INT4:
     347          46 :             nSizeOut -= ((nRecordSize + 1) / 2);
     348          46 :             if (nSizeOut <= 0)
     349             :             {
     350           0 :                 return CE_Failure;
     351             :             }
     352             : 
     353          84 :             for (GUInt32 n = 0; n != nRecordSize; ++n)
     354             :             {
     355          68 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     356             :                 {
     357           0 :                     iCode = OUT_INT4;
     358             :                 }
     359             :                 else
     360             :                 {
     361          68 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     362             :                 }
     363          68 :                 *pabyCurrent = static_cast<GByte>(iCode & 0x0F);
     364             : 
     365          68 :                 ++n;
     366          68 :                 if (n == nRecordSize)
     367             :                 {
     368          30 :                     pabyCurrent++;
     369          30 :                     break;
     370             :                 }
     371             : 
     372          38 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     373             :                 {
     374           0 :                     iCode = OUT_INT4;
     375             :                 }
     376             :                 else
     377             :                 {
     378          38 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     379             :                 }
     380          38 :                 *pabyCurrent++ |= static_cast<GByte>((iCode & 0x0F) << 4);
     381             :             }
     382          46 :             break;
     383             : 
     384         100 :         case TYPE_INT8:
     385         100 :             nSizeOut -= nRecordSize;
     386         100 :             if (nSizeOut <= 0)
     387             :             {
     388           0 :                 return CE_Failure;
     389             :             }
     390             : 
     391        8708 :             for (GUInt32 n = 0; n != nRecordSize; ++n)
     392             :             {
     393        8608 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     394             :                 {
     395           9 :                     *pabyCurrent++ = static_cast<GByte>(OUT_INT8);
     396             :                 }
     397             :                 else
     398             :                 {
     399        8599 :                     *pabyCurrent++ = static_cast<GByte>(paiRecord[n]);
     400             :                 }
     401             :             }
     402         100 :             break;
     403             : 
     404         278 :         case TYPE_INT12:
     405         278 :             nSizeOut -= ((nRecordSize * 3 + 1) / 2);
     406         278 :             if (nSizeOut <= 0)
     407             :             {
     408           0 :                 return CE_Failure;
     409             :             }
     410             : 
     411        6851 :             for (GUInt32 n = 0; n != nRecordSize; ++n)
     412             :             {
     413        6744 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     414             :                 {
     415         348 :                     iCode = OUT_INT12;
     416             :                 }
     417             :                 else
     418             :                 {
     419        6396 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     420             :                 }
     421             : 
     422        6744 :                 iPrevCode = iCode;
     423        6744 :                 *pabyCurrent++ = static_cast<GByte>(iCode & 0x00FF);
     424             : 
     425        6744 :                 ++n;
     426        6744 :                 if (n == nRecordSize)
     427             :                 {
     428         171 :                     *pabyCurrent++ =
     429         171 :                         static_cast<GByte>((iPrevCode & 0x0F00) >> 8);
     430         171 :                     break;
     431             :                 }
     432             : 
     433        6573 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     434             :                 {
     435         341 :                     iCode = OUT_INT12;
     436             :                 }
     437             :                 else
     438             :                 {
     439        6232 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     440             :                 }
     441        6573 :                 iCode = (((iPrevCode & 0x0F00) >> 8) | ((iCode & 0x0FFF) << 4));
     442             : 
     443        6573 :                 CPL_LSBPTR32(&iCode);
     444        6573 :                 memcpy(pabyCurrent, &iCode, 2);
     445        6573 :                 pabyCurrent += 2;
     446             :             }
     447         278 :             break;
     448             : 
     449         395 :         case TYPE_INT16:
     450         395 :             nSizeOut -= (nRecordSize * 2);
     451         395 :             if (nSizeOut <= 0)
     452             :             {
     453           0 :                 return CE_Failure;
     454             :             }
     455             : 
     456      103286 :             for (GUInt32 n = 0; n != nRecordSize; ++n)
     457             :             {
     458      102891 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     459             :                 {
     460        2575 :                     iCode = OUT_INT16;
     461             :                 }
     462             :                 else
     463             :                 {
     464      100316 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     465             :                 }
     466      102891 :                 CPL_LSBPTR32(&iCode);
     467      102891 :                 memcpy(pabyCurrent, &iCode, 2);
     468      102891 :                 pabyCurrent += 2;
     469             :             }
     470         395 :             break;
     471             : 
     472         137 :         case TYPE_INT24:
     473         137 :             nSizeOut -= (nRecordSize * 3);
     474         137 :             if (nSizeOut <= 0)
     475             :             {
     476           0 :                 return CE_Failure;
     477             :             }
     478             : 
     479       34743 :             for (GUInt32 n = 0; n != nRecordSize; ++n)
     480             :             {
     481       34606 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     482             :                 {
     483         628 :                     iCode = OUT_INT24;
     484             :                 }
     485             :                 else
     486             :                 {
     487       33978 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     488             :                 }
     489       34606 :                 CPL_LSBPTR32(&iCode);
     490       34606 :                 memcpy(pabyCurrent, &iCode, 3);
     491       34606 :                 pabyCurrent += 3;
     492             :             }
     493         137 :             break;
     494             : 
     495          86 :         case TYPE_INT32:
     496          86 :             nSizeOut -= (nRecordSize * 4);
     497          86 :             if (nSizeOut <= 0)
     498             :             {
     499           0 :                 return CE_Failure;
     500             :             }
     501             : 
     502       24616 :             for (GUInt32 n = 0; n != nRecordSize; ++n)
     503             :             {
     504       24530 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     505             :                 {
     506           0 :                     iCode = OUT_INT32;
     507             :                 }
     508             :                 else
     509             :                 {
     510       24530 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     511             :                 }
     512       24530 :                 CPL_LSBPTR32(&iCode);
     513       24530 :                 memcpy(pabyCurrent, &iCode, 4);
     514       24530 :                 pabyCurrent += 4;
     515             :             }
     516          86 :             break;
     517             : 
     518         170 :         case TYPE_ZERO:
     519             :         case TYPE_OUT:
     520         170 :             break;
     521             : 
     522           0 :         default:
     523           0 :             return CE_Failure;
     524             :     }
     525             : 
     526        1212 :     return CE_None;
     527             : }
     528             : 
     529             : /************************************************************************/
     530             : /*                             DEMDeltaType()                           */
     531             : /************************************************************************/
     532             : 
     533      189311 : static RmfTypes DEMDeltaType(DEMDiffT delta)
     534             : {
     535      189311 :     if (delta <= RANGE_INT12)
     536             :     {
     537      141083 :         if (delta <= RANGE_INT4)
     538             :         {
     539       61786 :             if (delta == 0)
     540             :             {
     541       49823 :                 return TYPE_ZERO;
     542             :             }
     543             :             else
     544             :             {
     545       11963 :                 return TYPE_INT4;
     546             :             }
     547             :         }
     548             :         else
     549             :         {
     550       79297 :             if (delta <= RANGE_INT8)
     551             :             {
     552       23225 :                 return TYPE_INT8;
     553             :             }
     554             :             else
     555             :             {
     556       56072 :                 return TYPE_INT12;
     557             :             }
     558             :         }
     559             :     }
     560             :     else
     561             :     {
     562       48228 :         if (delta <= RANGE_INT24)
     563             :         {
     564       33338 :             if (delta <= RANGE_INT16)
     565             :             {
     566       24341 :                 return TYPE_INT16;
     567             :             }
     568             :             else
     569             :             {
     570        8997 :                 return TYPE_INT24;
     571             :             }
     572             :         }
     573             :         else
     574             :         {
     575       14890 :             return TYPE_INT32;
     576             :         }
     577             :     }
     578             : }
     579             : 
     580             : /************************************************************************/
     581             : /*                             DEMCompress()                            */
     582             : /************************************************************************/
     583             : 
     584           5 : size_t RMFDataset::DEMCompress(const GByte *pabyIn, GUInt32 nSizeIn,
     585             :                                GByte *pabyOut, GUInt32 nSizeOut, GUInt32,
     586             :                                GUInt32, const RMFDataset *poDS)
     587             : {
     588           5 :     if (pabyIn == nullptr || pabyOut == nullptr || nSizeIn < sizeof(DEMWorkT))
     589           0 :         return 0;
     590             : 
     591           5 :     const GUInt32 anDeltaTypeSize[8] = {0, 0, 4, 8, 12, 16, 24, 32};
     592           5 :     const GUInt32 nMaxRecordSize = 255 + 32;
     593             : 
     594           5 :     DEMWorkT iMin(std::numeric_limits<DEMWorkT>::min() + 1);
     595           5 :     if (poDS != nullptr &&
     596           5 :         poDS->sHeader.adfElevMinMax[0] < poDS->sHeader.adfElevMinMax[1])
     597             :     {
     598           0 :         iMin = static_cast<DEMWorkT>(poDS->sHeader.adfElevMinMax[0]);
     599             :     }
     600           5 :     GUInt32 nLessCount = 0;
     601           5 :     GUInt32 nRecordSize = 0;
     602           5 :     RmfTypes eRecordType = TYPE_OUT;
     603           5 :     DEMDiffT aiRecord[nMaxRecordSize] = {0};
     604           5 :     DEMWorkT aiPrev[nMaxRecordSize] = {0};
     605             : 
     606           5 :     GByte *pabyCurrent = pabyOut;
     607           5 :     DEMWorkT iPrev = 0;
     608             : 
     609           5 :     nSizeIn = nSizeIn / sizeof(DEMWorkT);
     610             : 
     611           5 :     const DEMWorkT *paiIn = reinterpret_cast<const DEMWorkT *>(pabyIn);
     612           5 :     const DEMWorkT *paiInEnd = paiIn + nSizeIn;
     613             : 
     614             :     while (true)
     615             :     {
     616      197413 :         GUInt32 nRecordElementSize = 0;
     617             : 
     618      197413 :         if (paiIn >= paiInEnd)
     619             :         {
     620          10 :             if (nRecordSize == 0)
     621             :             {
     622           5 :                 return pabyCurrent - pabyOut;
     623             :             }
     624             : 
     625           5 :             if (CE_None != DEMWriteRecord(aiRecord, eRecordType, nRecordSize,
     626             :                                           nSizeOut, pabyCurrent))
     627             :             {
     628           0 :                 return 0;
     629             :             }
     630           5 :             nRecordSize = 0;
     631           5 :             continue;
     632             :         }
     633             : 
     634      197403 :         DEMWorkT iCurr = *(paiIn++);
     635             :         RmfTypes eCurrType;
     636             : 
     637      197403 :         if (iCurr < iMin)
     638             :         {
     639        8092 :             eCurrType = TYPE_OUT;
     640        8092 :             aiRecord[nRecordSize] = DIFF_OUI_OF_RANGE;
     641        8092 :             aiPrev[nRecordSize] = iPrev;
     642             :         }
     643             :         else
     644             :         {
     645      189311 :             DEMDiffT delta =
     646      189311 :                 static_cast<DEMDiffT>(iCurr) - static_cast<DEMDiffT>(iPrev);
     647             : 
     648      189311 :             aiRecord[nRecordSize] = delta;
     649      189311 :             aiPrev[nRecordSize] = iCurr;
     650             : 
     651      189311 :             if (delta < 0)
     652       79880 :                 delta = -delta;
     653             : 
     654      189311 :             eCurrType = DEMDeltaType(delta);
     655      189311 :             iPrev = iCurr;
     656             :         }
     657      197403 :         nRecordSize++;
     658             : 
     659      197403 :         if (nRecordSize == 1)
     660             :         {
     661        1212 :             eRecordType = eCurrType;
     662             :             // nRecordElementSize = anDeltaTypeSize[eCurrType >> 5];
     663        1212 :             continue;
     664             :         }
     665             : 
     666      196191 :         if (nRecordSize == nMaxRecordSize)
     667             :         {
     668         602 :             nLessCount = 0;
     669         602 :             if (CE_None != DEMWriteRecord(aiRecord, eRecordType, nRecordSize,
     670             :                                           nSizeOut, pabyCurrent))
     671             :             {
     672           0 :                 return 0;
     673             :             }
     674         602 :             iPrev = aiPrev[nRecordSize - 1];
     675         602 :             nRecordSize = 0;
     676         602 :             continue;
     677             :         }
     678             : 
     679      195589 :         if (eCurrType == eRecordType)
     680             :         {
     681       59166 :             nLessCount = 0;
     682       59166 :             continue;
     683             :         }
     684             : 
     685      136423 :         if ((eCurrType > eRecordType) || (eCurrType | eRecordType) == TYPE_ZERO)
     686             :         {
     687         605 :             --paiIn;
     688         605 :             if (CE_None != DEMWriteRecord(aiRecord, eRecordType,
     689             :                                           nRecordSize - 1, nSizeOut,
     690             :                                           pabyCurrent))
     691             :             {
     692           0 :                 return 0;
     693             :             }
     694         605 :             iPrev = aiPrev[nRecordSize - 2];
     695         605 :             nRecordSize = 0;
     696         605 :             nLessCount = 0;
     697         605 :             continue;
     698             :         }
     699             : 
     700      135818 :         nLessCount++;
     701             : 
     702      135818 :         GUInt32 nDeltaSize(anDeltaTypeSize[eCurrType >> 5]);
     703      135818 :         if (nRecordElementSize < nDeltaSize ||
     704       45035 :             (nRecordElementSize - nDeltaSize) * nLessCount < 16)
     705             :         {
     706      135818 :             continue;
     707             :         }
     708             : 
     709           0 :         paiIn -= nLessCount;
     710           0 :         if (CE_None != DEMWriteRecord(aiRecord, eRecordType,
     711             :                                       nRecordSize - nLessCount, nSizeOut,
     712             :                                       pabyCurrent))
     713             :         {
     714           0 :             return 0;
     715             :         }
     716           0 :         iPrev = aiPrev[nRecordSize - nLessCount - 1];
     717           0 :         nRecordSize = 0;
     718           0 :         nLessCount = 0;
     719      197408 :     }
     720             : 
     721             :     return 0;
     722             : }

Generated by: LCOV version 1.14