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

Generated by: LCOV version 1.14