LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/geojson - ogrjsoncollectionstreamingparser.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 196 209 93.8 %
Date: 2024-05-03 15:49:35 Functions: 15 16 93.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Streaming parser for GeoJSON-like FeatureCollection
       5             :  * Author:   Even Rouault <even.rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2017, Even Rouault <even.rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "ogrjsoncollectionstreamingparser.h"
      30             : 
      31             : #include "cpl_string.h"
      32             : #include "ogrgeojsonreader.h"  // CPL_json_object_object_get
      33             : 
      34             : #define JSON_C_VER_013 (13 << 8)
      35             : 
      36             : #include <json.h>  // JSON-C
      37             : 
      38             : #if (!defined(JSON_C_VERSION_NUM)) || (JSON_C_VERSION_NUM < JSON_C_VER_013)
      39             : #include <json_object_private.h>  // just for sizeof(struct json_object)
      40             : #endif
      41             : 
      42             : #include <limits>
      43             : 
      44             : #if (!defined(JSON_C_VERSION_NUM)) || (JSON_C_VERSION_NUM < JSON_C_VER_013)
      45             : const size_t ESTIMATE_BASE_OBJECT_SIZE = sizeof(struct json_object);
      46             : #elif JSON_C_VERSION_NUM == JSON_C_VER_013  // no way to get the size
      47             : #if SIZEOF_VOIDP == 8
      48             : const size_t ESTIMATE_BASE_OBJECT_SIZE = 72;
      49             : #else
      50             : const size_t ESTIMATE_BASE_OBJECT_SIZE = 36;
      51             : #endif
      52             : #elif JSON_C_VERSION_NUM > JSON_C_VER_013  // we have json_c_object_sizeof()
      53             : const size_t ESTIMATE_BASE_OBJECT_SIZE = json_c_object_sizeof();
      54             : #endif
      55             : 
      56             : const size_t ESTIMATE_ARRAY_SIZE =
      57             :     ESTIMATE_BASE_OBJECT_SIZE + sizeof(struct array_list);
      58             : const size_t ESTIMATE_ARRAY_ELT_SIZE = sizeof(void *);
      59             : const size_t ESTIMATE_OBJECT_ELT_SIZE = sizeof(struct lh_entry);
      60             : const size_t ESTIMATE_OBJECT_SIZE =
      61             :     ESTIMATE_BASE_OBJECT_SIZE + sizeof(struct lh_table) +
      62             :     JSON_OBJECT_DEF_HASH_ENTRIES * ESTIMATE_OBJECT_ELT_SIZE;
      63             : 
      64             : /************************************************************************/
      65             : /*                     OGRJSONCollectionStreamingParser()                */
      66             : /************************************************************************/
      67             : 
      68         763 : OGRJSONCollectionStreamingParser::OGRJSONCollectionStreamingParser(
      69         763 :     bool bFirstPass, bool bStoreNativeData, size_t nMaxObjectSize)
      70             :     : m_bFirstPass(bFirstPass), m_bStoreNativeData(bStoreNativeData),
      71         763 :       m_nMaxObjectSize(nMaxObjectSize)
      72             : {
      73         763 : }
      74             : 
      75             : /************************************************************************/
      76             : /*                   ~OGRJSONCollectionStreamingParser()                */
      77             : /************************************************************************/
      78             : 
      79         763 : OGRJSONCollectionStreamingParser::~OGRJSONCollectionStreamingParser()
      80             : {
      81         763 :     if (m_poRootObj)
      82           3 :         json_object_put(m_poRootObj);
      83         763 :     if (m_poCurObj && m_poCurObj != m_poRootObj)
      84           1 :         json_object_put(m_poCurObj);
      85         763 : }
      86             : 
      87             : /************************************************************************/
      88             : /*                          StealRootObject()                           */
      89             : /************************************************************************/
      90             : 
      91         329 : json_object *OGRJSONCollectionStreamingParser::StealRootObject()
      92             : {
      93         329 :     json_object *poRet = m_poRootObj;
      94         329 :     if (m_poCurObj == m_poRootObj)
      95          22 :         m_poCurObj = nullptr;
      96         329 :     m_poRootObj = nullptr;
      97         329 :     return poRet;
      98             : }
      99             : 
     100             : /************************************************************************/
     101             : /*                            AppendObject()                            */
     102             : /************************************************************************/
     103             : 
     104      524656 : void OGRJSONCollectionStreamingParser::AppendObject(json_object *poNewObj)
     105             : {
     106      524656 :     if (m_bKeySet)
     107             :     {
     108       33505 :         CPLAssert(json_object_get_type(m_apoCurObj.back()) == json_type_object);
     109       33505 :         json_object_object_add(m_apoCurObj.back(), m_osCurKey.c_str(),
     110             :                                poNewObj);
     111       33505 :         m_osCurKey.clear();
     112       33505 :         m_bKeySet = false;
     113             :     }
     114             :     else
     115             :     {
     116      491151 :         CPLAssert(json_object_get_type(m_apoCurObj.back()) == json_type_array);
     117      491151 :         json_object_array_add(m_apoCurObj.back(), poNewObj);
     118             :     }
     119      524656 : }
     120             : 
     121             : /************************************************************************/
     122             : /*                            StartObject()                             */
     123             : /************************************************************************/
     124             : 
     125       14325 : void OGRJSONCollectionStreamingParser::StartObject()
     126             : {
     127       14325 :     if (m_nMaxObjectSize > 0 && m_nCurObjMemEstimate > m_nMaxObjectSize)
     128             :     {
     129           0 :         TooComplex();
     130           0 :         return;
     131             :     }
     132             : 
     133       14325 :     if (m_bInFeaturesArray && m_nDepth == 2)
     134             :     {
     135        4412 :         m_poCurObj = json_object_new_object();
     136        4412 :         m_apoCurObj.push_back(m_poCurObj);
     137        4412 :         if (m_bStoreNativeData)
     138             :         {
     139         905 :             m_osJson = "{";
     140         905 :             m_abFirstMember.push_back(true);
     141             :         }
     142        4412 :         m_bStartFeature = true;
     143             :     }
     144        9913 :     else if (m_poCurObj)
     145             :     {
     146        9194 :         if (m_bInFeaturesArray && m_bStoreNativeData && m_nDepth >= 3)
     147             :         {
     148        1779 :             m_osJson += "{";
     149        1779 :             m_abFirstMember.push_back(true);
     150             :         }
     151             : 
     152        9194 :         m_nCurObjMemEstimate += ESTIMATE_OBJECT_SIZE;
     153             : 
     154        9194 :         json_object *poNewObj = json_object_new_object();
     155        9194 :         AppendObject(poNewObj);
     156        9194 :         m_apoCurObj.push_back(poNewObj);
     157             :     }
     158         719 :     else if (m_bFirstPass && m_nDepth == 0)
     159             :     {
     160         332 :         m_poRootObj = json_object_new_object();
     161         332 :         m_apoCurObj.push_back(m_poRootObj);
     162         332 :         m_poCurObj = m_poRootObj;
     163             :     }
     164             : 
     165       14325 :     m_nDepth++;
     166             : }
     167             : 
     168             : /************************************************************************/
     169             : /*                             EndObject()                              */
     170             : /************************************************************************/
     171             : 
     172       14321 : void OGRJSONCollectionStreamingParser::EndObject()
     173             : {
     174       14321 :     if (m_nMaxObjectSize > 0 && m_nCurObjMemEstimate > m_nMaxObjectSize)
     175             :     {
     176           0 :         TooComplex();
     177           0 :         return;
     178             :     }
     179             : 
     180       14321 :     m_nDepth--;
     181             : 
     182       14321 :     if (m_bInFeaturesArray && m_nDepth == 2 && m_poCurObj)
     183             :     {
     184        4411 :         if (m_bStoreNativeData)
     185             :         {
     186         905 :             m_abFirstMember.pop_back();
     187         905 :             m_osJson += "}";
     188         905 :             m_nTotalOGRFeatureMemEstimate +=
     189         905 :                 m_osJson.size() + strlen("application/vnd.geo+json");
     190             :         }
     191             : 
     192             :         json_object *poObjTypeObj =
     193        4411 :             CPL_json_object_object_get(m_poCurObj, "type");
     194        8822 :         if (poObjTypeObj &&
     195        4411 :             json_object_get_type(poObjTypeObj) == json_type_string)
     196             :         {
     197        4411 :             const char *pszObjType = json_object_get_string(poObjTypeObj);
     198        4411 :             if (strcmp(pszObjType, "Feature") == 0)
     199             :             {
     200        4411 :                 GotFeature(m_poCurObj, m_bFirstPass, m_osJson);
     201             :             }
     202             :         }
     203             : 
     204        4411 :         json_object_put(m_poCurObj);
     205        4411 :         m_poCurObj = nullptr;
     206        4411 :         m_apoCurObj.clear();
     207        4411 :         m_nCurObjMemEstimate = 0;
     208        4411 :         m_bInCoordinates = false;
     209        4411 :         m_nTotalOGRFeatureMemEstimate += sizeof(OGRFeature);
     210        4411 :         m_osJson.clear();
     211        4411 :         m_abFirstMember.clear();
     212        4411 :         m_bEndFeature = true;
     213             :     }
     214        9910 :     else if (m_poCurObj)
     215             :     {
     216        9216 :         if (m_bInFeaturesArray && m_bStoreNativeData && m_nDepth >= 3)
     217             :         {
     218        1779 :             m_abFirstMember.pop_back();
     219        1779 :             m_osJson += "}";
     220             :         }
     221             : 
     222        9216 :         m_apoCurObj.pop_back();
     223             :     }
     224         694 :     else if (m_nDepth == 1)
     225             :     {
     226          28 :         m_bInFeatures = false;
     227             :     }
     228             : }
     229             : 
     230             : /************************************************************************/
     231             : /*                         StartObjectMember()                          */
     232             : /************************************************************************/
     233             : 
     234       35321 : void OGRJSONCollectionStreamingParser::StartObjectMember(const char *pszKey,
     235             :                                                          size_t nKeyLen)
     236             : {
     237       35321 :     if (m_nMaxObjectSize > 0 && m_nCurObjMemEstimate > m_nMaxObjectSize)
     238             :     {
     239           0 :         TooComplex();
     240           0 :         return;
     241             :     }
     242             : 
     243       35321 :     if (m_nDepth == 1)
     244             :     {
     245        2059 :         m_bInFeatures = strcmp(pszKey, "features") == 0;
     246        2059 :         m_bCanEasilyAppend = m_bInFeatures;
     247        2059 :         m_bInType = strcmp(pszKey, "type") == 0;
     248        2059 :         if (m_bInType || m_bInFeatures)
     249             :         {
     250        1318 :             m_poCurObj = nullptr;
     251        1318 :             m_apoCurObj.clear();
     252        1318 :             m_nRootObjMemEstimate = m_nCurObjMemEstimate;
     253             :         }
     254         741 :         else if (m_poRootObj)
     255             :         {
     256         347 :             m_poCurObj = m_poRootObj;
     257         347 :             m_apoCurObj.clear();
     258         347 :             m_apoCurObj.push_back(m_poCurObj);
     259         347 :             m_nCurObjMemEstimate = m_nRootObjMemEstimate;
     260             :         }
     261             :     }
     262       33262 :     else if (m_nDepth == 3 && m_bInFeaturesArray)
     263             :     {
     264       30040 :         m_bInCoordinates = strcmp(pszKey, "coordinates") == 0 ||
     265       15020 :                            strcmp(pszKey, "geometries") == 0;
     266             :     }
     267             : 
     268       35321 :     if (m_poCurObj)
     269             :     {
     270       33505 :         if (m_bInFeaturesArray && m_bStoreNativeData && m_nDepth >= 3)
     271             :         {
     272        5125 :             if (!m_abFirstMember.back())
     273        2738 :                 m_osJson += ",";
     274        5125 :             m_abFirstMember.back() = false;
     275             :             m_osJson +=
     276        5125 :                 CPLJSonStreamingParser::GetSerializedString(pszKey) + ":";
     277             :         }
     278             : 
     279       33505 :         m_nCurObjMemEstimate += ESTIMATE_OBJECT_ELT_SIZE;
     280       33505 :         m_osCurKey.assign(pszKey, nKeyLen);
     281       33505 :         m_bKeySet = true;
     282             :     }
     283             : }
     284             : 
     285             : /************************************************************************/
     286             : /*                             StartArray()                             */
     287             : /************************************************************************/
     288             : 
     289      178878 : void OGRJSONCollectionStreamingParser::StartArray()
     290             : {
     291      178878 :     if (m_nMaxObjectSize > 0 && m_nCurObjMemEstimate > m_nMaxObjectSize)
     292             :     {
     293        6221 :         TooComplex();
     294        6221 :         return;
     295             :     }
     296             : 
     297      172657 :     if (m_nDepth == 1 && m_bInFeatures)
     298             :     {
     299         659 :         m_bInFeaturesArray = true;
     300             :     }
     301      171998 :     else if (m_poCurObj)
     302             :     {
     303      171900 :         if (m_bInFeaturesArray && m_bStoreNativeData && m_nDepth >= 3)
     304             :         {
     305        6374 :             m_osJson += "[";
     306        6374 :             m_abFirstMember.push_back(true);
     307             :         }
     308             : 
     309      171900 :         m_nCurObjMemEstimate += ESTIMATE_ARRAY_SIZE;
     310             : 
     311      171900 :         json_object *poNewObj = json_object_new_array();
     312      171900 :         AppendObject(poNewObj);
     313      171900 :         m_apoCurObj.push_back(poNewObj);
     314             :     }
     315      172657 :     m_nDepth++;
     316             : }
     317             : 
     318             : /************************************************************************/
     319             : /*                          StartArrayMember()                          */
     320             : /************************************************************************/
     321             : 
     322      514340 : void OGRJSONCollectionStreamingParser::StartArrayMember()
     323             : {
     324      514340 :     if (m_poCurObj)
     325             :     {
     326      509815 :         m_nCurObjMemEstimate += ESTIMATE_ARRAY_ELT_SIZE;
     327             : 
     328      509815 :         if (m_bInFeaturesArray && m_bStoreNativeData && m_nDepth >= 3)
     329             :         {
     330       14837 :             if (!m_abFirstMember.back())
     331        8465 :                 m_osJson += ",";
     332       14837 :             m_abFirstMember.back() = false;
     333             :         }
     334             :     }
     335      514340 : }
     336             : 
     337             : /************************************************************************/
     338             : /*                               EndArray()                             */
     339             : /************************************************************************/
     340             : 
     341      178874 : void OGRJSONCollectionStreamingParser::EndArray()
     342             : {
     343      178874 :     if (m_nMaxObjectSize > 0 && m_nCurObjMemEstimate > m_nMaxObjectSize)
     344             :     {
     345        6221 :         TooComplex();
     346        6221 :         return;
     347             :     }
     348             : 
     349      172653 :     m_nDepth--;
     350      172653 :     if (m_nDepth == 1 && m_bInFeaturesArray)
     351             :     {
     352         657 :         m_bInFeaturesArray = false;
     353             :     }
     354      171996 :     else if (m_poCurObj)
     355             :     {
     356      171898 :         if (m_bInFeaturesArray && m_bStoreNativeData && m_nDepth >= 3)
     357             :         {
     358        6374 :             m_abFirstMember.pop_back();
     359        6374 :             m_osJson += "]";
     360             :         }
     361             : 
     362      171898 :         m_apoCurObj.pop_back();
     363             :     }
     364             : }
     365             : 
     366             : /************************************************************************/
     367             : /*                              String()                                */
     368             : /************************************************************************/
     369             : 
     370       13667 : void OGRJSONCollectionStreamingParser::String(const char *pszValue, size_t nLen)
     371             : {
     372       13667 :     if (m_nMaxObjectSize > 0 && m_nCurObjMemEstimate > m_nMaxObjectSize)
     373             :     {
     374           0 :         TooComplex();
     375           0 :         return;
     376             :     }
     377             : 
     378       13667 :     if (m_nDepth == 1 && m_bInType)
     379             :     {
     380         659 :         m_bIsTypeKnown = true;
     381         659 :         m_bIsFeatureCollection = strcmp(pszValue, "FeatureCollection") == 0;
     382             :     }
     383       13008 :     else if (m_poCurObj)
     384             :     {
     385       12586 :         if (m_bFirstPass)
     386             :         {
     387        7655 :             if (m_bInFeaturesArray)
     388        7261 :                 m_nTotalOGRFeatureMemEstimate += sizeof(OGRField) + nLen;
     389             : 
     390        7655 :             m_nCurObjMemEstimate += ESTIMATE_BASE_OBJECT_SIZE;
     391        7655 :             m_nCurObjMemEstimate += nLen + sizeof(void *);
     392             :         }
     393       12586 :         if (m_bInFeaturesArray && m_bStoreNativeData && m_nDepth >= 3)
     394             :         {
     395        1821 :             m_osJson += CPLJSonStreamingParser::GetSerializedString(pszValue);
     396             :         }
     397       12586 :         AppendObject(json_object_new_string(pszValue));
     398             :     }
     399             : }
     400             : 
     401             : /************************************************************************/
     402             : /*                              Number()                                */
     403             : /************************************************************************/
     404             : 
     405      341984 : void OGRJSONCollectionStreamingParser::Number(const char *pszValue, size_t nLen)
     406             : {
     407      341984 :     if (m_nMaxObjectSize > 0 && m_nCurObjMemEstimate > m_nMaxObjectSize)
     408             :     {
     409       12443 :         TooComplex();
     410       12443 :         return;
     411             :     }
     412             : 
     413      329541 :     if (m_poCurObj)
     414             :     {
     415      329523 :         if (m_bFirstPass)
     416             :         {
     417      143423 :             if (m_bInFeaturesArray)
     418             :             {
     419      143363 :                 if (m_bInCoordinates)
     420           0 :                     m_nTotalOGRFeatureMemEstimate += sizeof(double);
     421             :                 else
     422      143363 :                     m_nTotalOGRFeatureMemEstimate += sizeof(OGRField);
     423             :             }
     424             : 
     425      143423 :             m_nCurObjMemEstimate += ESTIMATE_BASE_OBJECT_SIZE;
     426             :         }
     427      329523 :         if (m_bInFeaturesArray && m_bStoreNativeData && m_nDepth >= 3)
     428             :         {
     429        9953 :             m_osJson.append(pszValue, nLen);
     430             :         }
     431             : 
     432      329523 :         if (CPLGetValueType(pszValue) == CPL_VALUE_REAL)
     433             :         {
     434      282638 :             AppendObject(json_object_new_double(CPLAtof(pszValue)));
     435             :         }
     436       46885 :         else if (nLen == strlen("Infinity") && EQUAL(pszValue, "Infinity"))
     437             :         {
     438           2 :             AppendObject(json_object_new_double(
     439             :                 std::numeric_limits<double>::infinity()));
     440             :         }
     441       46883 :         else if (nLen == strlen("-Infinity") && EQUAL(pszValue, "-Infinity"))
     442             :         {
     443           2 :             AppendObject(json_object_new_double(
     444           2 :                 -std::numeric_limits<double>::infinity()));
     445             :         }
     446       46881 :         else if (nLen == strlen("NaN") && EQUAL(pszValue, "NaN"))
     447             :         {
     448           2 :             AppendObject(json_object_new_double(
     449             :                 std::numeric_limits<double>::quiet_NaN()));
     450             :         }
     451             :         else
     452             :         {
     453       46879 :             AppendObject(json_object_new_int64(CPLAtoGIntBig(pszValue)));
     454             :         }
     455             :     }
     456             : }
     457             : 
     458             : /************************************************************************/
     459             : /*                              Boolean()                               */
     460             : /************************************************************************/
     461             : 
     462         150 : void OGRJSONCollectionStreamingParser::Boolean(bool bVal)
     463             : {
     464         150 :     if (m_nMaxObjectSize > 0 && m_nCurObjMemEstimate > m_nMaxObjectSize)
     465             :     {
     466           0 :         TooComplex();
     467           0 :         return;
     468             :     }
     469             : 
     470         150 :     if (m_poCurObj)
     471             :     {
     472         138 :         if (m_bFirstPass)
     473             :         {
     474          76 :             if (m_bInFeaturesArray)
     475          62 :                 m_nTotalOGRFeatureMemEstimate += sizeof(OGRField);
     476             : 
     477          76 :             m_nCurObjMemEstimate += ESTIMATE_BASE_OBJECT_SIZE;
     478             :         }
     479         138 :         if (m_bInFeaturesArray && m_bStoreNativeData && m_nDepth >= 3)
     480             :         {
     481           4 :             m_osJson += bVal ? "true" : "false";
     482             :         }
     483             : 
     484         138 :         AppendObject(json_object_new_boolean(bVal));
     485             :     }
     486             : }
     487             : 
     488             : /************************************************************************/
     489             : /*                               Null()                                 */
     490             : /************************************************************************/
     491             : 
     492        1317 : void OGRJSONCollectionStreamingParser::Null()
     493             : {
     494        1317 :     if (m_nMaxObjectSize > 0 && m_nCurObjMemEstimate > m_nMaxObjectSize)
     495             :     {
     496           0 :         TooComplex();
     497           0 :         return;
     498             :     }
     499             : 
     500        1317 :     if (m_poCurObj)
     501             :     {
     502        1315 :         if (m_bInFeaturesArray && m_bStoreNativeData && m_nDepth >= 3)
     503             :         {
     504          31 :             m_osJson += "null";
     505             :         }
     506             : 
     507        1315 :         m_nCurObjMemEstimate += ESTIMATE_BASE_OBJECT_SIZE;
     508        1315 :         AppendObject(nullptr);
     509             :     }
     510             : }
     511             : 
     512             : /************************************************************************/
     513             : /*                             Exception()                              */
     514             : /************************************************************************/
     515             : 
     516           2 : void OGRJSONCollectionStreamingParser::Exception(const char *pszMessage)
     517             : {
     518           2 :     CPLError(CE_Failure, CPLE_AppDefined, "%s", pszMessage);
     519           2 : }

Generated by: LCOV version 1.14