LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/osm - gpb.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 143 155 92.3 %
Date: 2025-01-18 12:42:00 Functions: 28 28 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       5             :  * Purpose:  Google Protocol Buffer generic handling functions
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2012, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #ifndef GPB_H_INCLUDED
      14             : #define GPB_H_INCLUDED
      15             : 
      16             : #include "cpl_port.h"
      17             : #include "cpl_error.h"
      18             : #include "cpl_string.h"
      19             : 
      20             : #include <string>
      21             : #include <exception>
      22             : 
      23             : #ifndef CHECK_OOB
      24             : #define CHECK_OOB 1
      25             : #endif
      26             : 
      27             : class GPBException : public std::exception
      28             : {
      29             :     std::string m_osMessage;
      30             : 
      31             :   public:
      32           6 :     explicit GPBException(int nLine)
      33           6 :         : m_osMessage(CPLSPrintf("Parsing error occurred at line %d", nLine))
      34             :     {
      35           6 :     }
      36             : 
      37           2 :     const char *what() const noexcept override
      38             :     {
      39           2 :         return m_osMessage.c_str();
      40             :     }
      41             : };
      42             : 
      43             : #define THROW_GPB_EXCEPTION throw GPBException(__LINE__)
      44             : 
      45             : /************************************************************************/
      46             : /*                Google Protocol Buffer definitions                    */
      47             : /************************************************************************/
      48             : 
      49             : // TODO(schwehr): This should be an enum.
      50             : constexpr int WT_VARINT = 0;
      51             : constexpr int WT_64BIT = 1;
      52             : constexpr int WT_DATA = 2;
      53             : // constexpr WT_STARTGROUP = 3; // unused
      54             : // constexpr WT_ENDGROUP = 4; // unused
      55             : constexpr int WT_32BIT = 5;
      56             : 
      57             : #define MAKE_KEY(nFieldNumber, nWireType) ((nFieldNumber << 3) | nWireType)
      58             : #define GET_WIRETYPE(nKey) (nKey & 0x7)
      59             : #define GET_FIELDNUMBER(nKey) (nKey >> 3)
      60             : 
      61             : /************************************************************************/
      62             : /*                          ReadVarUInt32()                             */
      63             : /************************************************************************/
      64             : 
      65      371009 : inline int ReadVarUInt32(const GByte **ppabyData)
      66             : {
      67      371009 :     unsigned int nVal = 0;
      68      371009 :     int nShift = 0;
      69      371009 :     const GByte *pabyData = *ppabyData;
      70             : 
      71             :     while (true)
      72             :     {
      73      380575 :         int nByte = *pabyData;
      74      380575 :         if (!(nByte & 0x80))
      75             :         {
      76      371009 :             *ppabyData = pabyData + 1;
      77      371009 :             return nVal | (static_cast<unsigned>(nByte) << nShift);
      78             :         }
      79        9566 :         nVal |= (nByte & 0x7f) << nShift;
      80        9566 :         pabyData++;
      81        9566 :         nShift += 7;
      82        9566 :         if (nShift == 28)
      83             :         {
      84           0 :             nByte = *pabyData;
      85           0 :             if (!(nByte & 0x80))
      86             :             {
      87           0 :                 *ppabyData = pabyData + 1;
      88           0 :                 return nVal | ((static_cast<unsigned>(nByte) & 0xf) << nShift);
      89             :             }
      90           0 :             *ppabyData = pabyData;
      91           0 :             return nVal;
      92             :         }
      93        9566 :     }
      94             : }
      95             : 
      96             : #define READ_VARUINT32(pabyData, pabyDataLimit, nVal)                          \
      97             :     {                                                                          \
      98             :         nVal = ReadVarUInt32(&pabyData);                                       \
      99             :         if (CHECK_OOB && pabyData > pabyDataLimit)                             \
     100             :             THROW_GPB_EXCEPTION;                                               \
     101             :     }
     102             : 
     103             : #define READ_SIZE(pabyData, pabyDataLimit, nSize)                              \
     104             :     {                                                                          \
     105             :         READ_VARUINT32(pabyData, pabyDataLimit, nSize);                        \
     106             :         if (CHECK_OOB &&                                                       \
     107             :             nSize > static_cast<unsigned int>(pabyDataLimit - pabyData))       \
     108             :             THROW_GPB_EXCEPTION;                                               \
     109             :     }
     110             : 
     111             : /************************************************************************/
     112             : /*                          ReadVarUInt64()                             */
     113             : /************************************************************************/
     114             : 
     115      879462 : inline GUIntBig ReadVarUInt64(const GByte **ppabyData)
     116             : {
     117      879462 :     GUIntBig nVal = 0;
     118      879462 :     int nShift = 0;
     119      879462 :     const GByte *pabyData = *ppabyData;
     120             : 
     121             :     while (true)
     122             :     {
     123      933616 :         int nByte = *pabyData;
     124      933616 :         if (!(nByte & 0x80))
     125             :         {
     126      879340 :             *ppabyData = pabyData + 1;
     127      879340 :             return nVal | (static_cast<GUIntBig>(nByte) << nShift);
     128             :         }
     129       54276 :         nVal |= (static_cast<GUIntBig>(nByte & 0x7f)) << nShift;
     130       54276 :         pabyData++;
     131       54276 :         nShift += 7;
     132       54276 :         if (nShift == 63)
     133             :         {
     134         122 :             nByte = *pabyData;
     135         122 :             if (!(nByte & 0x80))
     136             :             {
     137         117 :                 *ppabyData = pabyData + 1;
     138         117 :                 return nVal | ((static_cast<GUIntBig>(nByte) & 1) << nShift);
     139             :             }
     140           5 :             *ppabyData = pabyData;
     141           5 :             return nVal;
     142             :         }
     143       54154 :     }
     144             : }
     145             : 
     146             : #define READ_VARUINT64(pabyData, pabyDataLimit, nVal)                          \
     147             :     {                                                                          \
     148             :         nVal = ReadVarUInt64(&pabyData);                                       \
     149             :         if (CHECK_OOB && pabyData > pabyDataLimit)                             \
     150             :             THROW_GPB_EXCEPTION;                                               \
     151             :     }
     152             : 
     153             : #define READ_SIZE64(pabyData, pabyDataLimit, nSize)                            \
     154             :     {                                                                          \
     155             :         READ_VARUINT64(pabyData, pabyDataLimit, nSize);                        \
     156             :         if (CHECK_OOB &&                                                       \
     157             :             nSize > static_cast<unsigned int>(pabyDataLimit - pabyData))       \
     158             :             THROW_GPB_EXCEPTION;                                               \
     159             :     }
     160             : 
     161             : /************************************************************************/
     162             : /*                           ReadVarInt64()                             */
     163             : /************************************************************************/
     164             : 
     165        2730 : inline GIntBig ReadVarInt64(const GByte **ppabyData)
     166             : {
     167        2730 :     return static_cast<GIntBig>(ReadVarUInt64(ppabyData));
     168             : }
     169             : 
     170             : #define READ_VARINT64(pabyData, pabyDataLimit, nVal)                           \
     171             :     {                                                                          \
     172             :         nVal = ReadVarInt64(&pabyData);                                        \
     173             :         if (CHECK_OOB && pabyData > pabyDataLimit)                             \
     174             :             THROW_GPB_EXCEPTION;                                               \
     175             :     }
     176             : 
     177             : /************************************************************************/
     178             : /*                            DecodeSInt()                              */
     179             : /************************************************************************/
     180             : 
     181       27502 : inline GIntBig DecodeSInt(GUIntBig nVal)
     182             : {
     183       27502 :     return ((nVal & 1) == 0) ? static_cast<GIntBig>(nVal >> 1)
     184       27502 :                              : -static_cast<GIntBig>(nVal >> 1) - 1;
     185             : }
     186             : 
     187      711993 : inline GInt32 DecodeSInt(GUInt32 nVal)
     188             : {
     189      711993 :     return ((nVal & 1) == 0) ? static_cast<GInt32>(nVal >> 1)
     190      711993 :                              : -static_cast<GInt32>(nVal >> 1) - 1;
     191             : }
     192             : 
     193             : /************************************************************************/
     194             : /*                            ReadVarSInt64()                           */
     195             : /************************************************************************/
     196             : 
     197       27502 : inline GIntBig ReadVarSInt64(const GByte **ppabyPtr)
     198             : {
     199       27502 :     return DecodeSInt(ReadVarUInt64(ppabyPtr));
     200             : }
     201             : 
     202             : #define READ_VARSINT64(pabyData, pabyDataLimit, nVal)                          \
     203             :     {                                                                          \
     204             :         nVal = ReadVarSInt64(&pabyData);                                       \
     205             :         if (CHECK_OOB && pabyData > pabyDataLimit)                             \
     206             :             THROW_GPB_EXCEPTION;                                               \
     207             :     }
     208             : 
     209             : #define READ_VARSINT64_NOCHECK(pabyData, pabyDataLimit, nVal)                  \
     210             :     {                                                                          \
     211             :         nVal = ReadVarSInt64(&pabyData);                                       \
     212             :     }
     213             : 
     214             : /************************************************************************/
     215             : /*                           ReadVarInt32()                             */
     216             : /************************************************************************/
     217             : 
     218      130087 : inline int ReadVarInt32(const GByte **ppabyData)
     219             : {
     220             :     /*  If you use int32 or int64 as the type for a negative number, */
     221             :     /* the resulting varint is always ten bytes long */
     222      130087 :     GIntBig nVal = static_cast<GIntBig>(ReadVarUInt64(ppabyData));
     223      130087 :     return static_cast<int>(nVal);
     224             : }
     225             : 
     226             : #define READ_VARINT32(pabyData, pabyDataLimit, nVal)                           \
     227             :     {                                                                          \
     228             :         nVal = ReadVarInt32(&pabyData);                                        \
     229             :         if (CHECK_OOB && pabyData > pabyDataLimit)                             \
     230             :             THROW_GPB_EXCEPTION;                                               \
     231             :     }
     232             : 
     233             : #define READ_VARSINT32(pabyData, pabyDataLimit, nVal)                          \
     234             :     {                                                                          \
     235             :         nVal = DecodeSInt(static_cast<GUInt32>(ReadVarUInt64(&pabyData)));     \
     236             :         if (CHECK_OOB && pabyData > pabyDataLimit)                             \
     237             :             THROW_GPB_EXCEPTION;                                               \
     238             :     }
     239             : 
     240             : /************************************************************************/
     241             : /*                            ReadFloat32()                             */
     242             : /************************************************************************/
     243             : 
     244         623 : inline float ReadFloat32(const GByte **ppabyData, const GByte *pabyDataLimit)
     245             : {
     246         623 :     if (*ppabyData + sizeof(float) > pabyDataLimit)
     247           0 :         THROW_GPB_EXCEPTION;
     248             :     float fValue;
     249         623 :     memcpy(&fValue, *ppabyData, sizeof(float));
     250         623 :     CPL_LSBPTR32(&fValue);
     251         623 :     *ppabyData += sizeof(float);
     252         623 :     return fValue;
     253             : }
     254             : 
     255             : /************************************************************************/
     256             : /*                            ReadFloat64()                             */
     257             : /************************************************************************/
     258             : 
     259        1519 : inline double ReadFloat64(const GByte **ppabyData, const GByte *pabyDataLimit)
     260             : {
     261        1519 :     if (*ppabyData + sizeof(double) > pabyDataLimit)
     262           0 :         THROW_GPB_EXCEPTION;
     263             :     double dfValue;
     264        1519 :     memcpy(&dfValue, *ppabyData, sizeof(double));
     265        1519 :     CPL_LSBPTR64(&dfValue);
     266        1519 :     *ppabyData += sizeof(double);
     267        1519 :     return dfValue;
     268             : }
     269             : 
     270             : /************************************************************************/
     271             : /*                            SkipVarInt()                              */
     272             : /************************************************************************/
     273             : 
     274       24076 : inline void SkipVarInt(const GByte **ppabyData)
     275             : {
     276       24076 :     const GByte *pabyData = *ppabyData;
     277             :     while (true)
     278             :     {
     279       27579 :         int nByte = *pabyData;
     280       27579 :         if (!(nByte & 0x80))
     281             :         {
     282       24076 :             *ppabyData = pabyData + 1;
     283       24076 :             return;
     284             :         }
     285        3503 :         pabyData++;
     286        3503 :     }
     287             : }
     288             : 
     289             : #define SKIP_VARINT(pabyData, pabyDataLimit)                                   \
     290             :     {                                                                          \
     291             :         SkipVarInt(&pabyData);                                                 \
     292             :         if (CHECK_OOB && pabyData > pabyDataLimit)                             \
     293             :             THROW_GPB_EXCEPTION;                                               \
     294             :     }
     295             : 
     296             : #define READ_FIELD_KEY(nKey) READ_VARINT32(pabyData, pabyDataLimit, nKey)
     297             : 
     298             : #define READ_TEXT_WITH_SIZE(pabyData, pabyDataLimit, pszTxt, l_nDataLength)    \
     299             :     do                                                                         \
     300             :     {                                                                          \
     301             :         READ_SIZE(pabyData, pabyDataLimit, l_nDataLength);                     \
     302             :         pszTxt = static_cast<char *>(VSI_MALLOC_VERBOSE(l_nDataLength + 1));   \
     303             :         if (pszTxt == nullptr)                                                 \
     304             :             THROW_GPB_EXCEPTION;                                               \
     305             :         memcpy(pszTxt, pabyData, l_nDataLength);                               \
     306             :         pszTxt[l_nDataLength] = 0;                                             \
     307             :         pabyData += l_nDataLength;                                             \
     308             :     } while (0)
     309             : 
     310             : #define READ_TEXT(pabyData, pabyDataLimit, pszTxt)                             \
     311             :     do                                                                         \
     312             :     {                                                                          \
     313             :         unsigned int l_nDataLength;                                            \
     314             :         READ_TEXT_WITH_SIZE(pabyData, pabyDataLimit, pszTxt, l_nDataLength);   \
     315             :     } while (0)
     316             : 
     317             : /************************************************************************/
     318             : /*                         SkipUnknownField()                           */
     319             : /************************************************************************/
     320             : 
     321             : #define SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose)            \
     322             :     int nWireType = GET_WIRETYPE(nKey);                                        \
     323             :     if (verbose)                                                               \
     324             :     {                                                                          \
     325             :         int nFieldNumber = GET_FIELDNUMBER(nKey);                              \
     326             :         CPLDebug("PBF", "Unhandled case: nFieldNumber = %d, nWireType = %d",   \
     327             :                  nFieldNumber, nWireType);                                     \
     328             :     }                                                                          \
     329             :     switch (nWireType)                                                         \
     330             :     {                                                                          \
     331             :         case WT_VARINT:                                                        \
     332             :         {                                                                      \
     333             :             SKIP_VARINT(pabyData, pabyDataLimit);                              \
     334             :             break;                                                             \
     335             :         }                                                                      \
     336             :         case WT_64BIT:                                                         \
     337             :         {                                                                      \
     338             :             if (CHECK_OOB && pabyDataLimit - pabyData < 8)                     \
     339             :                 THROW_GPB_EXCEPTION;                                           \
     340             :             pabyData += 8;                                                     \
     341             :             break;                                                             \
     342             :         }                                                                      \
     343             :         case WT_DATA:                                                          \
     344             :         {                                                                      \
     345             :             unsigned int nDataLength;                                          \
     346             :             READ_SIZE(pabyData, pabyDataLimit, nDataLength);                   \
     347             :             pabyData += nDataLength;                                           \
     348             :             break;                                                             \
     349             :         }                                                                      \
     350             :         case WT_32BIT:                                                         \
     351             :         {                                                                      \
     352             :             if (CHECK_OOB && pabyDataLimit - pabyData < 4)                     \
     353             :                 THROW_GPB_EXCEPTION;                                           \
     354             :             pabyData += 4;                                                     \
     355             :             break;                                                             \
     356             :         }                                                                      \
     357             :         default:                                                               \
     358             :             THROW_GPB_EXCEPTION;                                               \
     359             :     }
     360             : 
     361       76067 : inline int SkipUnknownField(int nKey, const GByte *pabyData,
     362             :                             const GByte *pabyDataLimit, int verbose)
     363             : {
     364       76067 :     const GByte *pabyDataBefore = pabyData;
     365             :     try
     366             :     {
     367       76067 :         SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose);
     368       76067 :         return static_cast<int>(pabyData - pabyDataBefore);
     369             :     }
     370           0 :     catch (const GPBException &e)
     371             :     {
     372           0 :         if (verbose)
     373             :         {
     374           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     375             :         }
     376           0 :         return -1;
     377             :     }
     378             : }
     379             : 
     380             : #define SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, verbose)                   \
     381             :     {                                                                          \
     382             :         int _nOffset =                                                         \
     383             :             SkipUnknownField(nKey, pabyData, pabyDataLimit, verbose);          \
     384             :         if (_nOffset < 0)                                                      \
     385             :             THROW_GPB_EXCEPTION;                                               \
     386             :         pabyData += _nOffset;                                                  \
     387             :     }
     388             : 
     389             : /************************************************************************/
     390             : /*                          GetVarUIntSize()                            */
     391             : /************************************************************************/
     392             : 
     393      112703 : inline int GetVarUIntSize(GUIntBig nVal)
     394             : {
     395      112703 :     int nBytes = 1;
     396      123733 :     while (nVal > 127)
     397             :     {
     398       11030 :         nBytes++;
     399       11030 :         nVal >>= 7;
     400             :     }
     401      112703 :     return nBytes;
     402             : }
     403             : 
     404             : /************************************************************************/
     405             : /*                            EncodeSInt()                              */
     406             : /************************************************************************/
     407             : 
     408         123 : inline GUIntBig EncodeSInt(GIntBig nVal)
     409             : {
     410         123 :     if (nVal < 0)
     411         120 :         return (static_cast<GUIntBig>(-(nVal + 1)) << 1) | 1;
     412             :     else
     413           7 :         return static_cast<GUIntBig>(nVal) << 1;
     414             : }
     415             : 
     416        6135 : inline GUInt32 EncodeSInt(GInt32 nVal)
     417             : {
     418        6135 :     if (nVal < 0)
     419         733 :         return (static_cast<GUInt32>(-(nVal + 1)) << 1) | 1;
     420             :     else
     421        5402 :         return static_cast<GUInt32>(nVal) << 1;
     422             : }
     423             : 
     424             : /************************************************************************/
     425             : /*                          GetVarIntSize()                             */
     426             : /************************************************************************/
     427             : 
     428           8 : inline int GetVarIntSize(GIntBig nVal)
     429             : {
     430           8 :     return GetVarUIntSize(static_cast<GUIntBig>(nVal));
     431             : }
     432             : 
     433             : /************************************************************************/
     434             : /*                          GetVarSIntSize()                            */
     435             : /************************************************************************/
     436             : 
     437          91 : inline int GetVarSIntSize(GIntBig nVal)
     438             : {
     439          91 :     return GetVarUIntSize(EncodeSInt(nVal));
     440             : }
     441             : 
     442             : /************************************************************************/
     443             : /*                           WriteVarUInt()                             */
     444             : /************************************************************************/
     445             : 
     446       69445 : inline void WriteVarUInt(GByte **ppabyData, GUIntBig nVal)
     447             : {
     448       69445 :     GByte *pabyData = *ppabyData;
     449       75912 :     while (nVal > 127)
     450             :     {
     451        6467 :         *pabyData = static_cast<GByte>((nVal & 0x7f) | 0x80);
     452        6467 :         pabyData++;
     453        6467 :         nVal >>= 7;
     454             :     }
     455       69445 :     *pabyData = static_cast<GByte>(nVal);
     456       69445 :     pabyData++;
     457       69445 :     *ppabyData = pabyData;
     458       69445 : }
     459             : 
     460             : /************************************************************************/
     461             : /*                        WriteVarUIntSingleByte()                      */
     462             : /************************************************************************/
     463             : 
     464       47130 : inline void WriteVarUIntSingleByte(GByte **ppabyData, GUIntBig nVal)
     465             : {
     466       47130 :     GByte *pabyData = *ppabyData;
     467       47130 :     CPLAssert(nVal < 128);
     468       47130 :     *pabyData = static_cast<GByte>(nVal);
     469       47130 :     pabyData++;
     470       47130 :     *ppabyData = pabyData;
     471       47130 : }
     472             : 
     473             : /************************************************************************/
     474             : /*                           WriteVarInt()                              */
     475             : /************************************************************************/
     476             : 
     477           3 : inline void WriteVarInt(GByte **ppabyData, GIntBig nVal)
     478             : {
     479           3 :     WriteVarUInt(ppabyData, static_cast<GUIntBig>(nVal));
     480           3 : }
     481             : 
     482             : /************************************************************************/
     483             : /*                           WriteVarSInt()                             */
     484             : /************************************************************************/
     485             : 
     486          32 : inline void WriteVarSInt(GByte **ppabyData, GIntBig nVal)
     487             : {
     488          32 :     WriteVarUInt(ppabyData, EncodeSInt(nVal));
     489          32 : }
     490             : 
     491             : /************************************************************************/
     492             : /*                           WriteFloat32()                             */
     493             : /************************************************************************/
     494             : 
     495          49 : inline void WriteFloat32(GByte **ppabyData, float fVal)
     496             : {
     497          49 :     CPL_LSBPTR32(&fVal);
     498          49 :     memcpy(*ppabyData, &fVal, sizeof(float));
     499          49 :     *ppabyData += sizeof(float);
     500          49 : }
     501             : 
     502             : /************************************************************************/
     503             : /*                           WriteFloat64()                             */
     504             : /************************************************************************/
     505             : 
     506        1547 : inline void WriteFloat64(GByte **ppabyData, double dfVal)
     507             : {
     508        1547 :     CPL_LSBPTR64(&dfVal);
     509        1539 :     memcpy(*ppabyData, &dfVal, sizeof(double));
     510        1539 :     *ppabyData += sizeof(double);
     511        1539 : }
     512             : 
     513             : /************************************************************************/
     514             : /*                           GetTextSize()                              */
     515             : /************************************************************************/
     516             : 
     517           2 : inline int GetTextSize(const char *pszText)
     518             : {
     519           2 :     size_t nTextSize = strlen(pszText);
     520           2 :     return GetVarUIntSize(nTextSize) + static_cast<int>(nTextSize);
     521             : }
     522             : 
     523       10794 : inline int GetTextSize(const std::string &osText)
     524             : {
     525       10794 :     size_t nTextSize = osText.size();
     526       10755 :     return GetVarUIntSize(nTextSize) + static_cast<int>(nTextSize);
     527             : }
     528             : 
     529             : /************************************************************************/
     530             : /*                            WriteText()                               */
     531             : /************************************************************************/
     532             : 
     533           1 : inline void WriteText(GByte **ppabyData, const char *pszText)
     534             : {
     535           1 :     size_t nTextSize = strlen(pszText);
     536           1 :     WriteVarUInt(ppabyData, nTextSize);
     537           1 :     memcpy(*ppabyData, pszText, nTextSize);
     538           1 :     *ppabyData += nTextSize;
     539           1 : }
     540             : 
     541       10741 : inline void WriteText(GByte **ppabyData, const std::string &osText)
     542             : {
     543       10741 :     size_t nTextSize = osText.size();
     544       10739 :     WriteVarUInt(ppabyData, nTextSize);
     545       10759 :     memcpy(*ppabyData, osText.c_str(), nTextSize);
     546       10807 :     *ppabyData += nTextSize;
     547       10807 : }
     548             : 
     549             : #endif /* GPB_H_INCLUDED */

Generated by: LCOV version 1.14