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: 2024-11-21 22:18:42 Functions: 28 28 100.0 %

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

Generated by: LCOV version 1.14