LCOV - code coverage report
Current view: top level - frmts/rmf - rmfdem.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 305 345 88.4 %
Date: 2024-11-21 22:18:42 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 + *((GByte *)pabyTempIn++);
     125        1668 :             nSizeIn--;
     126             :         }
     127             : 
     128       61644 :         switch (nType)
     129             :         {
     130       17994 :             case TYPE_ZERO:
     131       17994 :                 if (nSizeOut < nCount)
     132           0 :                     break;
     133       17994 :                 nSizeOut -= nCount;
     134       98978 :                 while (nCount > 0)
     135             :                 {
     136       80984 :                     nCount--;
     137       80984 :                     *paiOut++ = iPrev;
     138             :                 }
     139       17994 :                 break;
     140             : 
     141        1564 :             case TYPE_OUT:
     142        1564 :                 if (nSizeOut < nCount)
     143           0 :                     break;
     144        1564 :                 nSizeOut -= nCount;
     145       26086 :                 while (nCount > 0)
     146             :                 {
     147       24522 :                     nCount--;
     148       24522 :                     *paiOut++ = OUT_INT32;
     149             :                 }
     150        1564 :                 break;
     151             : 
     152        1874 :             case TYPE_INT4:
     153        1874 :                 if (nSizeIn < (nCount + 1) / 2)
     154           0 :                     break;
     155        1874 :                 if (nSizeOut < nCount)
     156           0 :                     break;
     157        1874 :                 nSizeIn -= nCount / 2;
     158        1874 :                 nSizeOut -= nCount;
     159        4902 :                 while (nCount > 0)
     160             :                 {
     161        4014 :                     nCount--;
     162             :                     GInt32 nCode;
     163        4014 :                     nCode = (*pabyTempIn) & 0x0F;
     164        4014 :                     if (nCode > RANGE_INT4)
     165        1752 :                         nCode |= INV_INT4;
     166        4014 :                     *paiOut++ = (nCode == OUT_INT4) ? OUT_INT32
     167        3994 :                                                     : AddInt32(iPrev, nCode);
     168             : 
     169        4014 :                     if (nCount == 0)
     170             :                     {
     171         986 :                         if (nSizeIn)
     172             :                         {
     173         986 :                             pabyTempIn++;
     174         986 :                             nSizeIn--;
     175             :                         }
     176         986 :                         break;
     177             :                     }
     178        3028 :                     nCount--;
     179             : 
     180        3028 :                     nCode = ((*pabyTempIn++) >> 4) & 0x0F;
     181        3028 :                     if (nCode > RANGE_INT4)
     182        1222 :                         nCode |= INV_INT4;
     183        6036 :                     *paiOut++ = (nCode == OUT_INT4) ? OUT_INT32
     184        3008 :                                                     : AddInt32(iPrev, nCode);
     185             :                 }
     186        1874 :                 break;
     187             : 
     188        5924 :             case TYPE_INT8:
     189        5924 :                 if (nSizeIn < nCount)
     190           0 :                     break;
     191        5924 :                 if (nSizeOut < nCount)
     192           0 :                     break;
     193        5924 :                 nSizeIn -= nCount;
     194        5924 :                 nSizeOut -= nCount;
     195       50708 :                 while (nCount > 0)
     196             :                 {
     197       44784 :                     nCount--;
     198             :                     GInt32 nCode;
     199       44784 :                     *paiOut++ = ((nCode = *pabyTempIn++) == OUT_INT8)
     200       44784 :                                     ? OUT_INT32
     201       44766 :                                     : AddInt32(iPrev, nCode);
     202             :                 }
     203        5924 :                 break;
     204             : 
     205       15482 :             case TYPE_INT12:
     206       15482 :                 if (nSizeIn < (3 * nCount + 1) / 2)
     207           0 :                     break;
     208       15482 :                 if (nSizeOut < nCount)
     209           0 :                     break;
     210       15482 :                 nSizeIn -= 3 * nCount / 2;
     211       15482 :                 nSizeOut -= nCount;
     212             : 
     213       78758 :                 while (nCount > 0)
     214             :                 {
     215       71274 :                     nCount--;
     216       71274 :                     GInt32 nCode = CPL_LSBSINT16PTR(pabyTempIn) & 0x0FFF;
     217       71274 :                     pabyTempIn += 1;
     218       71274 :                     if (nCode > RANGE_INT12)
     219       39394 :                         nCode |= INV_INT12;
     220       71274 :                     *paiOut++ = (nCode == OUT_INT12) ? OUT_INT32
     221       70578 :                                                      : AddInt32(iPrev, nCode);
     222             : 
     223       71274 :                     if (nCount == 0)
     224             :                     {
     225        7998 :                         if (nSizeIn)
     226             :                         {
     227        7998 :                             pabyTempIn++;
     228        7998 :                             nSizeIn--;
     229             :                         }
     230        7998 :                         break;
     231             :                     }
     232       63276 :                     nCount--;
     233             : 
     234       63276 :                     nCode = (CPL_LSBSINT16PTR(pabyTempIn) >> 4) & 0x0FFF;
     235       63276 :                     pabyTempIn += 2;
     236       63276 :                     if (nCode > RANGE_INT12)
     237       35672 :                         nCode |= INV_INT12;
     238      125870 :                     *paiOut++ = (nCode == OUT_INT12) ? OUT_INT32
     239       62594 :                                                      : AddInt32(iPrev, nCode);
     240             :                 }
     241       15482 :                 break;
     242             : 
     243       17958 :             case TYPE_INT16:
     244       17958 :                 if (nSizeIn < 2 * nCount)
     245           0 :                     break;
     246       17958 :                 if (nSizeOut < nCount)
     247           0 :                     break;
     248       17958 :                 nSizeIn -= 2 * nCount;
     249       17958 :                 nSizeOut -= nCount;
     250             : 
     251      263522 :                 while (nCount > 0)
     252             :                 {
     253      245564 :                     nCount--;
     254      245564 :                     const GInt32 nCode = CPL_LSBSINT16PTR(pabyTempIn);
     255      245564 :                     pabyTempIn += 2;
     256      485978 :                     *paiOut++ = (nCode == OUT_INT16) ? OUT_INT32
     257      240414 :                                                      : AddInt32(iPrev, nCode);
     258             :                 }
     259       17958 :                 break;
     260             : 
     261         676 :             case TYPE_INT24:
     262         676 :                 if (nSizeIn < 3 * nCount)
     263           0 :                     break;
     264         676 :                 if (nSizeOut < nCount)
     265           0 :                     break;
     266         676 :                 nSizeIn -= 3 * nCount;
     267         676 :                 nSizeOut -= nCount;
     268             : 
     269       70290 :                 while (nCount > 0)
     270             :                 {
     271       69614 :                     nCount--;
     272       69614 :                     GInt32 nCode = (*(GByte *)pabyTempIn) |
     273       69614 :                                    ((*(GByte *)(pabyTempIn + 1)) << 8) |
     274       69614 :                                    ((*(GByte *)(pabyTempIn + 2)) << 16);
     275       69614 :                     pabyTempIn += 3;
     276       69614 :                     if (nCode > RANGE_INT24)
     277       31998 :                         nCode |= INV_INT24;
     278      137972 :                     *paiOut++ = (nCode == OUT_INT24) ? OUT_INT32
     279       68358 :                                                      : AddInt32(iPrev, nCode);
     280             :                 }
     281         676 :                 break;
     282             : 
     283         172 :             case TYPE_INT32:
     284         172 :                 if (nSizeIn < 4 * nCount)
     285           0 :                     break;
     286         172 :                 if (nSizeOut < nCount)
     287           0 :                     break;
     288         172 :                 nSizeIn -= 4 * nCount;
     289         172 :                 nSizeOut -= nCount;
     290             : 
     291       49232 :                 while (nCount > 0)
     292             :                 {
     293       49060 :                     nCount--;
     294       49060 :                     GInt32 nCode = CPL_LSBSINT32PTR(pabyTempIn);
     295       49060 :                     pabyTempIn += 4;
     296       98120 :                     *paiOut++ = (nCode == OUT_INT32) ? OUT_INT32
     297       49060 :                                                      : AddInt32(iPrev, nCode);
     298             :                 }
     299         172 :                 break;
     300             :         }
     301             :     }
     302             : 
     303          18 :     return (GByte *)paiOut - pabyOut;
     304             : }
     305             : 
     306             : /************************************************************************/
     307             : /*                            DEMWriteCode()                            */
     308             : /************************************************************************/
     309             : 
     310        1212 : static CPLErr DEMWriteRecord(const DEMDiffT *paiRecord, RmfTypes eRecordType,
     311             :                              GUInt32 nRecordSize, GInt32 nSizeOut,
     312             :                              GByte *&pabyCurrent)
     313             : {
     314        1212 :     const GUInt32 nMaxCountInHeader = 31;
     315             :     GInt32 iCode;
     316             :     GInt32 iPrevCode;
     317             : 
     318        1212 :     if (nRecordSize <= nMaxCountInHeader)
     319             :     {
     320         481 :         nSizeOut -= 1;
     321         481 :         if (nSizeOut <= 0)
     322             :         {
     323           0 :             return CE_Failure;
     324             :         }
     325             : 
     326         481 :         *pabyCurrent++ = static_cast<GByte>(eRecordType | nRecordSize);
     327             :     }
     328             :     else
     329             :     {
     330         731 :         nSizeOut -= 2;
     331         731 :         if (nSizeOut <= 0)
     332             :         {
     333           0 :             return CE_Failure;
     334             :         }
     335             : 
     336         731 :         *pabyCurrent++ = static_cast<GByte>(eRecordType);
     337         731 :         *pabyCurrent++ = static_cast<GByte>(nRecordSize - 32);
     338             :     }
     339             : 
     340        1212 :     switch (eRecordType)
     341             :     {
     342          46 :         case TYPE_INT4:
     343          46 :             nSizeOut -= ((nRecordSize + 1) / 2);
     344          46 :             if (nSizeOut <= 0)
     345             :             {
     346           0 :                 return CE_Failure;
     347             :             }
     348             : 
     349          84 :             for (GUInt32 n = 0; n != nRecordSize; ++n)
     350             :             {
     351          68 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     352             :                 {
     353           0 :                     iCode = OUT_INT4;
     354             :                 }
     355             :                 else
     356             :                 {
     357          68 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     358             :                 }
     359          68 :                 *pabyCurrent = static_cast<GByte>(iCode & 0x0F);
     360             : 
     361          68 :                 ++n;
     362          68 :                 if (n == nRecordSize)
     363             :                 {
     364          30 :                     pabyCurrent++;
     365          30 :                     break;
     366             :                 }
     367             : 
     368          38 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     369             :                 {
     370           0 :                     iCode = OUT_INT4;
     371             :                 }
     372             :                 else
     373             :                 {
     374          38 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     375             :                 }
     376          38 :                 *pabyCurrent++ |= static_cast<GByte>((iCode & 0x0F) << 4);
     377             :             }
     378          46 :             break;
     379             : 
     380         100 :         case TYPE_INT8:
     381         100 :             nSizeOut -= nRecordSize;
     382         100 :             if (nSizeOut <= 0)
     383             :             {
     384           0 :                 return CE_Failure;
     385             :             }
     386             : 
     387        8708 :             for (GUInt32 n = 0; n != nRecordSize; ++n)
     388             :             {
     389        8608 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     390             :                 {
     391           9 :                     *pabyCurrent++ = static_cast<GByte>(OUT_INT8);
     392             :                 }
     393             :                 else
     394             :                 {
     395        8599 :                     *pabyCurrent++ = static_cast<GByte>(paiRecord[n]);
     396             :                 }
     397             :             }
     398         100 :             break;
     399             : 
     400         278 :         case TYPE_INT12:
     401         278 :             nSizeOut -= ((nRecordSize * 3 + 1) / 2);
     402         278 :             if (nSizeOut <= 0)
     403             :             {
     404           0 :                 return CE_Failure;
     405             :             }
     406             : 
     407        6851 :             for (GUInt32 n = 0; n != nRecordSize; ++n)
     408             :             {
     409        6744 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     410             :                 {
     411         348 :                     iCode = OUT_INT12;
     412             :                 }
     413             :                 else
     414             :                 {
     415        6396 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     416             :                 }
     417             : 
     418        6744 :                 iPrevCode = iCode;
     419        6744 :                 *pabyCurrent++ = static_cast<GByte>(iCode & 0x00FF);
     420             : 
     421        6744 :                 ++n;
     422        6744 :                 if (n == nRecordSize)
     423             :                 {
     424         171 :                     *pabyCurrent++ =
     425         171 :                         static_cast<GByte>((iPrevCode & 0x0F00) >> 8);
     426         171 :                     break;
     427             :                 }
     428             : 
     429        6573 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     430             :                 {
     431         341 :                     iCode = OUT_INT12;
     432             :                 }
     433             :                 else
     434             :                 {
     435        6232 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     436             :                 }
     437        6573 :                 iCode = (((iPrevCode & 0x0F00) >> 8) | ((iCode & 0x0FFF) << 4));
     438             : 
     439        6573 :                 CPL_LSBPTR32(&iCode);
     440        6573 :                 memcpy(pabyCurrent, &iCode, 2);
     441        6573 :                 pabyCurrent += 2;
     442             :             }
     443         278 :             break;
     444             : 
     445         395 :         case TYPE_INT16:
     446         395 :             nSizeOut -= (nRecordSize * 2);
     447         395 :             if (nSizeOut <= 0)
     448             :             {
     449           0 :                 return CE_Failure;
     450             :             }
     451             : 
     452      103286 :             for (GUInt32 n = 0; n != nRecordSize; ++n)
     453             :             {
     454      102891 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     455             :                 {
     456        2575 :                     iCode = OUT_INT16;
     457             :                 }
     458             :                 else
     459             :                 {
     460      100316 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     461             :                 }
     462      102891 :                 CPL_LSBPTR32(&iCode);
     463      102891 :                 memcpy(pabyCurrent, &iCode, 2);
     464      102891 :                 pabyCurrent += 2;
     465             :             }
     466         395 :             break;
     467             : 
     468         137 :         case TYPE_INT24:
     469         137 :             nSizeOut -= (nRecordSize * 3);
     470         137 :             if (nSizeOut <= 0)
     471             :             {
     472           0 :                 return CE_Failure;
     473             :             }
     474             : 
     475       34743 :             for (GUInt32 n = 0; n != nRecordSize; ++n)
     476             :             {
     477       34606 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     478             :                 {
     479         628 :                     iCode = OUT_INT24;
     480             :                 }
     481             :                 else
     482             :                 {
     483       33978 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     484             :                 }
     485       34606 :                 CPL_LSBPTR32(&iCode);
     486       34606 :                 memcpy(pabyCurrent, &iCode, 3);
     487       34606 :                 pabyCurrent += 3;
     488             :             }
     489         137 :             break;
     490             : 
     491          86 :         case TYPE_INT32:
     492          86 :             nSizeOut -= (nRecordSize * 4);
     493          86 :             if (nSizeOut <= 0)
     494             :             {
     495           0 :                 return CE_Failure;
     496             :             }
     497             : 
     498       24616 :             for (GUInt32 n = 0; n != nRecordSize; ++n)
     499             :             {
     500       24530 :                 if (paiRecord[n] == DIFF_OUI_OF_RANGE)
     501             :                 {
     502           0 :                     iCode = OUT_INT32;
     503             :                 }
     504             :                 else
     505             :                 {
     506       24530 :                     iCode = static_cast<GInt32>(paiRecord[n]);
     507             :                 }
     508       24530 :                 CPL_LSBPTR32(&iCode);
     509       24530 :                 memcpy(pabyCurrent, &iCode, 4);
     510       24530 :                 pabyCurrent += 4;
     511             :             }
     512          86 :             break;
     513             : 
     514         170 :         case TYPE_ZERO:
     515             :         case TYPE_OUT:
     516         170 :             break;
     517             : 
     518           0 :         default:
     519           0 :             return CE_Failure;
     520             :     }
     521             : 
     522        1212 :     return CE_None;
     523             : }
     524             : 
     525             : /************************************************************************/
     526             : /*                             DEMDeltaType()                           */
     527             : /************************************************************************/
     528             : 
     529      189311 : static RmfTypes DEMDeltaType(DEMDiffT delta)
     530             : {
     531      189311 :     if (delta <= RANGE_INT12)
     532             :     {
     533      141083 :         if (delta <= RANGE_INT4)
     534             :         {
     535       61786 :             if (delta == 0)
     536             :             {
     537       49823 :                 return TYPE_ZERO;
     538             :             }
     539             :             else
     540             :             {
     541       11963 :                 return TYPE_INT4;
     542             :             }
     543             :         }
     544             :         else
     545             :         {
     546       79297 :             if (delta <= RANGE_INT8)
     547             :             {
     548       23225 :                 return TYPE_INT8;
     549             :             }
     550             :             else
     551             :             {
     552       56072 :                 return TYPE_INT12;
     553             :             }
     554             :         }
     555             :     }
     556             :     else
     557             :     {
     558       48228 :         if (delta <= RANGE_INT24)
     559             :         {
     560       33338 :             if (delta <= RANGE_INT16)
     561             :             {
     562       24341 :                 return TYPE_INT16;
     563             :             }
     564             :             else
     565             :             {
     566        8997 :                 return TYPE_INT24;
     567             :             }
     568             :         }
     569             :         else
     570             :         {
     571       14890 :             return TYPE_INT32;
     572             :         }
     573             :     }
     574             : }
     575             : 
     576             : /************************************************************************/
     577             : /*                             DEMCompress()                            */
     578             : /************************************************************************/
     579             : 
     580           5 : size_t RMFDataset::DEMCompress(const GByte *pabyIn, GUInt32 nSizeIn,
     581             :                                GByte *pabyOut, GUInt32 nSizeOut, GUInt32,
     582             :                                GUInt32, const RMFDataset *poDS)
     583             : {
     584           5 :     if (pabyIn == nullptr || pabyOut == nullptr || nSizeIn < sizeof(DEMWorkT))
     585           0 :         return 0;
     586             : 
     587           5 :     const GUInt32 anDeltaTypeSize[8] = {0, 0, 4, 8, 12, 16, 24, 32};
     588           5 :     const GUInt32 nMaxRecordSize = 255 + 32;
     589             : 
     590           5 :     DEMWorkT iMin(std::numeric_limits<DEMWorkT>::min() + 1);
     591           5 :     if (poDS != nullptr &&
     592           5 :         poDS->sHeader.adfElevMinMax[0] < poDS->sHeader.adfElevMinMax[1])
     593             :     {
     594           0 :         iMin = static_cast<DEMWorkT>(poDS->sHeader.adfElevMinMax[0]);
     595             :     }
     596           5 :     GUInt32 nLessCount = 0;
     597           5 :     GUInt32 nRecordSize = 0;
     598           5 :     RmfTypes eRecordType = TYPE_OUT;
     599           5 :     DEMDiffT aiRecord[nMaxRecordSize] = {0};
     600           5 :     DEMWorkT aiPrev[nMaxRecordSize] = {0};
     601             : 
     602           5 :     GByte *pabyCurrent = pabyOut;
     603           5 :     DEMWorkT iPrev = 0;
     604             : 
     605           5 :     nSizeIn = nSizeIn / sizeof(DEMWorkT);
     606             : 
     607           5 :     const DEMWorkT *paiIn = reinterpret_cast<const DEMWorkT *>(pabyIn);
     608           5 :     const DEMWorkT *paiInEnd = paiIn + nSizeIn;
     609             : 
     610             :     while (true)
     611             :     {
     612      197413 :         GUInt32 nRecordElementSize = 0;
     613             : 
     614      197413 :         if (paiIn >= paiInEnd)
     615             :         {
     616          10 :             if (nRecordSize == 0)
     617             :             {
     618           5 :                 return pabyCurrent - pabyOut;
     619             :             }
     620             : 
     621           5 :             if (CE_None != DEMWriteRecord(aiRecord, eRecordType, nRecordSize,
     622             :                                           nSizeOut, pabyCurrent))
     623             :             {
     624           0 :                 return 0;
     625             :             }
     626           5 :             nRecordSize = 0;
     627           5 :             continue;
     628             :         }
     629             : 
     630      197403 :         DEMWorkT iCurr = *(paiIn++);
     631             :         RmfTypes eCurrType;
     632             : 
     633      197403 :         if (iCurr < iMin)
     634             :         {
     635        8092 :             eCurrType = TYPE_OUT;
     636        8092 :             aiRecord[nRecordSize] = DIFF_OUI_OF_RANGE;
     637        8092 :             aiPrev[nRecordSize] = iPrev;
     638             :         }
     639             :         else
     640             :         {
     641      189311 :             DEMDiffT delta =
     642      189311 :                 static_cast<DEMDiffT>(iCurr) - static_cast<DEMDiffT>(iPrev);
     643             : 
     644      189311 :             aiRecord[nRecordSize] = delta;
     645      189311 :             aiPrev[nRecordSize] = iCurr;
     646             : 
     647      189311 :             if (delta < 0)
     648       79880 :                 delta = -delta;
     649             : 
     650      189311 :             eCurrType = DEMDeltaType(delta);
     651      189311 :             iPrev = iCurr;
     652             :         }
     653      197403 :         nRecordSize++;
     654             : 
     655      197403 :         if (nRecordSize == 1)
     656             :         {
     657        1212 :             eRecordType = eCurrType;
     658             :             // nRecordElementSize = anDeltaTypeSize[eCurrType >> 5];
     659        1212 :             continue;
     660             :         }
     661             : 
     662      196191 :         if (nRecordSize == nMaxRecordSize)
     663             :         {
     664         602 :             nLessCount = 0;
     665         602 :             if (CE_None != DEMWriteRecord(aiRecord, eRecordType, nRecordSize,
     666             :                                           nSizeOut, pabyCurrent))
     667             :             {
     668           0 :                 return 0;
     669             :             }
     670         602 :             iPrev = aiPrev[nRecordSize - 1];
     671         602 :             nRecordSize = 0;
     672         602 :             continue;
     673             :         }
     674             : 
     675      195589 :         if (eCurrType == eRecordType)
     676             :         {
     677       59166 :             nLessCount = 0;
     678       59166 :             continue;
     679             :         }
     680             : 
     681      136423 :         if ((eCurrType > eRecordType) || (eCurrType | eRecordType) == TYPE_ZERO)
     682             :         {
     683         605 :             --paiIn;
     684         605 :             if (CE_None != DEMWriteRecord(aiRecord, eRecordType,
     685             :                                           nRecordSize - 1, nSizeOut,
     686             :                                           pabyCurrent))
     687             :             {
     688           0 :                 return 0;
     689             :             }
     690         605 :             iPrev = aiPrev[nRecordSize - 2];
     691         605 :             nRecordSize = 0;
     692         605 :             nLessCount = 0;
     693         605 :             continue;
     694             :         }
     695             : 
     696      135818 :         nLessCount++;
     697             : 
     698      135818 :         GUInt32 nDeltaSize(anDeltaTypeSize[eCurrType >> 5]);
     699      135818 :         if (nRecordElementSize < nDeltaSize ||
     700       45035 :             (nRecordElementSize - nDeltaSize) * nLessCount < 16)
     701             :         {
     702      135818 :             continue;
     703             :         }
     704             : 
     705           0 :         paiIn -= nLessCount;
     706           0 :         if (CE_None != DEMWriteRecord(aiRecord, eRecordType,
     707             :                                       nRecordSize - nLessCount, nSizeOut,
     708             :                                       pabyCurrent))
     709             :         {
     710           0 :             return 0;
     711             :         }
     712           0 :         iPrev = aiPrev[nRecordSize - nLessCount - 1];
     713           0 :         nRecordSize = 0;
     714           0 :         nLessCount = 0;
     715      197408 :     }
     716             : 
     717             :     return 0;
     718             : }

Generated by: LCOV version 1.14