LCOV - code coverage report
Current view: top level - port - cpl_json.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 549 597 92.0 %
Date: 2024-04-29 01:40:10 Functions: 91 92 98.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Project:  Common Portability Library
       3             :  * Purpose:  Function wrapper for libjson-c access.
       4             :  * Author:   Dmitry Baryshnikov, dmitry.baryshnikov@nextgis.com
       5             :  *
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2017-2018 NextGIS, <info@nextgis.com>
       8             :  *
       9             :  * Permission is hereby granted, free of charge, to any person obtaining a
      10             :  * copy of this software and associated documentation files (the "Software"),
      11             :  * to deal in the Software without restriction, including without limitation
      12             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      13             :  * and/or sell copies of the Software, and to permit persons to whom the
      14             :  * Software is furnished to do so, subject to the following conditions:
      15             :  *
      16             :  * The above copyright notice and this permission notice shall be included
      17             :  * in all copies or substantial portions of the Software.
      18             :  *
      19             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      20             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      22             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      24             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      25             :  * DEALINGS IN THE SOFTWARE.
      26             :  ****************************************************************************/
      27             : 
      28             : #include "cpl_json.h"
      29             : 
      30             : #include "cpl_error.h"
      31             : #include "cpl_json_header.h"
      32             : #include "cpl_vsi.h"
      33             : 
      34             : #include "cpl_http.h"
      35             : #include "cpl_multiproc.h"
      36             : 
      37             : #define TO_JSONOBJ(x) static_cast<json_object *>(x)
      38             : 
      39             : static const char *JSON_PATH_DELIMITER = "/";
      40             : 
      41             : static const char *INVALID_OBJ_KEY = "__INVALID_OBJ_KEY__";
      42             : 
      43             : #define JSON_C_VER_014 (14 << 8)
      44             : 
      45             : // json_object_new_uint64() was added in libjson-c 0.14
      46             : #if (!defined(JSON_C_VERSION_NUM)) || (JSON_C_VERSION_NUM < JSON_C_VER_014)
      47             : 
      48             : static int CPLJSON_json_object_new_uint64_formatter(struct json_object *jso,
      49             :                                                     struct printbuf *pb,
      50             :                                                     int /* level */,
      51             :                                                     int /* flags */)
      52             : {
      53             :     const char *pszStr = json_object_get_string(jso);
      54             :     return printbuf_memappend(pb, pszStr, static_cast<int>(strlen(pszStr)));
      55             : }
      56             : 
      57             : static json_object *CPLJSON_json_object_new_uint64(uint64_t nVal)
      58             : {
      59             :     json_object *jso = json_object_new_string(
      60             :         CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nVal)));
      61             :     json_object_set_serializer(jso, CPLJSON_json_object_new_uint64_formatter,
      62             :                                nullptr, nullptr);
      63             :     return jso;
      64             : }
      65             : 
      66             : #define json_object_new_uint64 CPLJSON_json_object_new_uint64
      67             : 
      68             : #endif
      69             : 
      70             : //------------------------------------------------------------------------------
      71             : // JSONDocument
      72             : //------------------------------------------------------------------------------
      73             : /*! @cond Doxygen_Suppress */
      74        8001 : CPLJSONDocument::CPLJSONDocument() : m_poRootJsonObject(nullptr)
      75             : {
      76        8001 : }
      77             : 
      78       16014 : CPLJSONDocument::~CPLJSONDocument()
      79             : {
      80        8007 :     if (m_poRootJsonObject)
      81        7248 :         json_object_put(TO_JSONOBJ(m_poRootJsonObject));
      82        8007 : }
      83             : 
      84           5 : CPLJSONDocument::CPLJSONDocument(const CPLJSONDocument &other)
      85           5 :     : m_poRootJsonObject(json_object_get(TO_JSONOBJ(other.m_poRootJsonObject)))
      86             : {
      87           5 : }
      88             : 
      89           2 : CPLJSONDocument &CPLJSONDocument::operator=(const CPLJSONDocument &other)
      90             : {
      91           2 :     if (this == &other)
      92           1 :         return *this;
      93             : 
      94           1 :     if (m_poRootJsonObject)
      95           1 :         json_object_put(TO_JSONOBJ(m_poRootJsonObject));
      96           1 :     m_poRootJsonObject = json_object_get(TO_JSONOBJ(other.m_poRootJsonObject));
      97             : 
      98           1 :     return *this;
      99             : }
     100             : 
     101           1 : CPLJSONDocument::CPLJSONDocument(CPLJSONDocument &&other)
     102           1 :     : m_poRootJsonObject(other.m_poRootJsonObject)
     103             : {
     104           1 :     other.m_poRootJsonObject = nullptr;
     105           1 : }
     106             : 
     107         110 : CPLJSONDocument &CPLJSONDocument::operator=(CPLJSONDocument &&other)
     108             : {
     109         110 :     if (this == &other)
     110           0 :         return *this;
     111             : 
     112         110 :     if (m_poRootJsonObject)
     113          17 :         json_object_put(TO_JSONOBJ(m_poRootJsonObject));
     114         110 :     m_poRootJsonObject = other.m_poRootJsonObject;
     115         110 :     other.m_poRootJsonObject = nullptr;
     116             : 
     117         110 :     return *this;
     118             : }
     119             : 
     120             : /*! @endcond */
     121             : 
     122             : /**
     123             :  * Save json document at specified path
     124             :  * @param  osPath Path to save json document
     125             :  * @return         true on success. If error occurred it can be received using
     126             :  * CPLGetLastErrorMsg method.
     127             :  *
     128             :  * @since GDAL 2.3
     129             :  */
     130        1196 : bool CPLJSONDocument::Save(const std::string &osPath) const
     131             : {
     132        1196 :     VSILFILE *fp = VSIFOpenL(osPath.c_str(), "wt");
     133        1196 :     if (nullptr == fp)
     134             :     {
     135           2 :         CPLError(CE_Failure, CPLE_NoWriteAccess, "Open file %s to write failed",
     136             :                  osPath.c_str());
     137           2 :         return false;
     138             :     }
     139             : 
     140        2388 :     const char *pabyData = json_object_to_json_string_ext(
     141        1194 :         TO_JSONOBJ(m_poRootJsonObject), JSON_C_TO_STRING_PRETTY);
     142        1194 :     VSIFWriteL(pabyData, 1, strlen(pabyData), fp);
     143             : 
     144        1194 :     VSIFCloseL(fp);
     145             : 
     146        1194 :     return true;
     147             : }
     148             : 
     149             : /**
     150             :  * Return the json document as a serialized string.
     151             :  * @return         serialized document.
     152             :  *
     153             :  * @since GDAL 2.3
     154             :  */
     155        1261 : std::string CPLJSONDocument::SaveAsString() const
     156             : {
     157        1261 :     return json_object_to_json_string_ext(TO_JSONOBJ(m_poRootJsonObject),
     158        1261 :                                           JSON_C_TO_STRING_PRETTY);
     159             : }
     160             : 
     161             : /**
     162             :  * Get json document root object
     163             :  * @return CPLJSONObject class instance
     164             :  *
     165             :  * @since GDAL 3.1
     166             :  */
     167          87 : const CPLJSONObject CPLJSONDocument::GetRoot() const
     168             : {
     169          87 :     return const_cast<CPLJSONDocument *>(this)->GetRoot();
     170             : }
     171             : 
     172             : /**
     173             :  * Get json document root object
     174             :  * @return CPLJSONObject class instance
     175             :  *
     176             :  * @since GDAL 2.3
     177             :  */
     178       13089 : CPLJSONObject CPLJSONDocument::GetRoot()
     179             : {
     180       13089 :     if (nullptr == m_poRootJsonObject)
     181             :     {
     182         955 :         m_poRootJsonObject = json_object_new_object();
     183             :     }
     184             : 
     185       13089 :     if (json_object_get_type(TO_JSONOBJ(m_poRootJsonObject)) == json_type_array)
     186             :     {
     187         342 :         return CPLJSONArray("", m_poRootJsonObject);
     188             :     }
     189             :     else
     190             :     {
     191       12918 :         return CPLJSONObject("", m_poRootJsonObject);
     192             :     }
     193             : }
     194             : 
     195             : /**
     196             :  * Set json document root object
     197             :  * @param oRoot CPLJSONObject root object
     198             :  *
     199             :  * @since GDAL 3.4
     200             :  */
     201        1678 : void CPLJSONDocument::SetRoot(const CPLJSONObject &oRoot)
     202             : {
     203        1678 :     if (m_poRootJsonObject)
     204           0 :         json_object_put(TO_JSONOBJ(m_poRootJsonObject));
     205        1678 :     m_poRootJsonObject = json_object_get(TO_JSONOBJ(oRoot.m_poJsonObject));
     206        1678 : }
     207             : 
     208             : /**
     209             :  * Load json document from file by provided path
     210             :  * @param  osPath Path to json file.
     211             :  * @return         true on success. If error occurred it can be received using
     212             :  * CPLGetLastErrorMsg method.
     213             :  *
     214             :  * @since GDAL 2.3
     215             :  */
     216        2629 : bool CPLJSONDocument::Load(const std::string &osPath)
     217             : {
     218        2629 :     GByte *pabyOut = nullptr;
     219        2629 :     vsi_l_offset nSize = 0;
     220        2629 :     if (!VSIIngestFile(nullptr, osPath.c_str(), &pabyOut, &nSize,
     221             :                        100 * 1024 * 1024))  // Maximum 100 Mb allowed
     222             :     {
     223         259 :         CPLError(CE_Failure, CPLE_FileIO, "Load json file %s failed",
     224             :                  osPath.c_str());
     225         259 :         return false;
     226             :     }
     227             : 
     228        2370 :     bool bResult = LoadMemory(pabyOut, static_cast<int>(nSize));
     229        2370 :     VSIFree(pabyOut);
     230        2370 :     return bResult;
     231             : }
     232             : 
     233             : /**
     234             :  * Load json document from memory buffer.
     235             :  * @param  pabyData Buffer.data.
     236             :  * @param  nLength  Buffer size.
     237             :  * @return          true on success. If error occurred it can be received using
     238             :  * CPLGetLastErrorMsg method.
     239             :  *
     240             :  * @since GDAL 2.3
     241             :  */
     242        5838 : bool CPLJSONDocument::LoadMemory(const GByte *pabyData, int nLength)
     243             : {
     244        5838 :     if (nullptr == pabyData)
     245             :     {
     246           1 :         return false;
     247             :     }
     248             : 
     249        5837 :     if (m_poRootJsonObject)
     250        1197 :         json_object_put(TO_JSONOBJ(m_poRootJsonObject));
     251             : 
     252        5837 :     if (nLength == 4 &&
     253           5 :         memcmp(reinterpret_cast<const char *>(pabyData), "true", nLength) == 0)
     254             :     {
     255           5 :         m_poRootJsonObject = json_object_new_boolean(true);
     256           5 :         return true;
     257             :     }
     258             : 
     259        5832 :     if (nLength == 5 &&
     260           4 :         memcmp(reinterpret_cast<const char *>(pabyData), "false", nLength) == 0)
     261             :     {
     262           2 :         m_poRootJsonObject = json_object_new_boolean(false);
     263           2 :         return true;
     264             :     }
     265             : 
     266        5830 :     json_tokener *jstok = json_tokener_new();
     267        5830 :     m_poRootJsonObject = json_tokener_parse_ex(
     268             :         jstok, reinterpret_cast<const char *>(pabyData), nLength);
     269        5830 :     bool bParsed = jstok->err == json_tokener_success;
     270        5830 :     if (!bParsed)
     271             :     {
     272          12 :         CPLError(CE_Failure, CPLE_AppDefined,
     273             :                  "JSON parsing error: %s (at offset %d)",
     274             :                  json_tokener_error_desc(jstok->err), jstok->char_offset);
     275          12 :         json_tokener_free(jstok);
     276          12 :         return false;
     277             :     }
     278        5818 :     json_tokener_free(jstok);
     279        5818 :     return bParsed;
     280             : }
     281             : 
     282             : /**
     283             :  * Load json document from memory buffer.
     284             :  * @param  osStr    String
     285             :  * @return          true on success. If error occurred it can be received using
     286             :  * CPLGetLastErrorMsg method.
     287             :  *
     288             :  * @since GDAL 2.3
     289             :  */
     290        3375 : bool CPLJSONDocument::LoadMemory(const std::string &osStr)
     291             : {
     292        3375 :     if (osStr.empty())
     293           3 :         return false;
     294        3372 :     return LoadMemory(reinterpret_cast<const GByte *>(osStr.data()),
     295        6744 :                       static_cast<int>(osStr.size()));
     296             : }
     297             : 
     298             : /**
     299             :  * Load json document from file using small chunks of data.
     300             :  * @param  osPath      Path to json document file.
     301             :  * @param  nChunkSize   Chunk size.
     302             :  * @param  pfnProgress  a function to report progress of the json data loading.
     303             :  * @param  pProgressArg application data passed into progress function.
     304             :  * @return              true on success. If error occurred it can be received
     305             :  * using CPLGetLastErrorMsg method.
     306             :  *
     307             :  * @since GDAL 2.3
     308             :  */
     309           3 : bool CPLJSONDocument::LoadChunks(const std::string &osPath, size_t nChunkSize,
     310             :                                  GDALProgressFunc pfnProgress,
     311             :                                  void *pProgressArg)
     312             : {
     313             :     VSIStatBufL sStatBuf;
     314           3 :     if (VSIStatL(osPath.c_str(), &sStatBuf) != 0)
     315             :     {
     316           2 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", osPath.c_str());
     317           2 :         return false;
     318             :     }
     319             : 
     320           1 :     VSILFILE *fp = VSIFOpenL(osPath.c_str(), "rb");
     321           1 :     if (fp == nullptr)
     322             :     {
     323           0 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", osPath.c_str());
     324           0 :         return false;
     325             :     }
     326             : 
     327           1 :     void *pBuffer = CPLMalloc(nChunkSize);
     328           1 :     json_tokener *tok = json_tokener_new();
     329           1 :     bool bSuccess = true;
     330           1 :     GUInt32 nFileSize = static_cast<GUInt32>(sStatBuf.st_size);
     331           1 :     double dfTotalRead = 0.0;
     332             : 
     333             :     while (true)
     334             :     {
     335           6 :         size_t nRead = VSIFReadL(pBuffer, 1, nChunkSize, fp);
     336           6 :         dfTotalRead += nRead;
     337             : 
     338           6 :         if (m_poRootJsonObject)
     339           1 :             json_object_put(TO_JSONOBJ(m_poRootJsonObject));
     340             : 
     341           6 :         m_poRootJsonObject = json_tokener_parse_ex(
     342             :             tok, static_cast<const char *>(pBuffer), static_cast<int>(nRead));
     343             : 
     344           6 :         enum json_tokener_error jerr = json_tokener_get_error(tok);
     345           6 :         if (jerr != json_tokener_continue && jerr != json_tokener_success)
     346             :         {
     347           0 :             CPLError(CE_Failure, CPLE_AppDefined, "JSON error: %s",
     348             :                      json_tokener_error_desc(jerr));
     349           0 :             bSuccess = false;
     350           0 :             break;
     351             :         }
     352             : 
     353           6 :         if (nRead < nChunkSize)
     354             :         {
     355           1 :             break;
     356             :         }
     357             : 
     358           5 :         if (nullptr != pfnProgress)
     359             :         {
     360           0 :             pfnProgress(dfTotalRead / nFileSize, "Loading ...", pProgressArg);
     361             :         }
     362           5 :     }
     363             : 
     364           1 :     json_tokener_free(tok);
     365           1 :     CPLFree(pBuffer);
     366           1 :     VSIFCloseL(fp);
     367             : 
     368           1 :     if (nullptr != pfnProgress)
     369             :     {
     370           0 :         pfnProgress(1.0, "Loading ...", pProgressArg);
     371             :     }
     372             : 
     373           1 :     return bSuccess;
     374             : }
     375             : 
     376             : /*! @cond Doxygen_Suppress */
     377             : #ifdef HAVE_CURL
     378             : 
     379             : typedef struct
     380             : {
     381             :     json_object *pObject;
     382             :     json_tokener *pTokener;
     383             : } JsonContext, *JsonContextL;
     384             : 
     385           0 : static size_t CPLJSONWriteFunction(void *pBuffer, size_t nSize, size_t nMemb,
     386             :                                    void *pUserData)
     387             : {
     388           0 :     size_t nLength = nSize * nMemb;
     389           0 :     JsonContextL ctx = static_cast<JsonContextL>(pUserData);
     390           0 :     if (ctx->pObject != nullptr)
     391             :     {
     392           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     393             :                  "A complete JSon object had already been parsed before new "
     394             :                  "content is appended to it");
     395           0 :         return 0;
     396             :     }
     397           0 :     ctx->pObject =
     398           0 :         json_tokener_parse_ex(ctx->pTokener, static_cast<const char *>(pBuffer),
     399             :                               static_cast<int>(nLength));
     400           0 :     switch (json_tokener_get_error(ctx->pTokener))
     401             :     {
     402           0 :         case json_tokener_continue:
     403             :         case json_tokener_success:
     404           0 :             return nLength;
     405           0 :         default:
     406           0 :             return 0; /* error: interrupt the transfer */
     407             :     }
     408             : }
     409             : 
     410             : #endif  // HAVE_CURL
     411             : /*! @endcond */
     412             : 
     413             : /**
     414             :  * Load json document from web.
     415             :  * @param  osUrl       Url to json document.
     416             :  * @param  papszOptions Option list as a NULL-terminated array of strings. May
     417             :  * be NULL. The available keys are same for CPLHTTPFetch method. Additional key
     418             :  * JSON_DEPTH define json parse depth. Default is 10.
     419             :  * @param  pfnProgress  a function to report progress of the json data loading.
     420             :  * @param  pProgressArg application data passed into progress function.
     421             :  * @return              true on success. If error occurred it can be received
     422             :  * using CPLGetLastErrorMsg method.
     423             :  *
     424             :  * @since GDAL 2.3
     425             :  */
     426             : 
     427             : #ifdef HAVE_CURL
     428           2 : bool CPLJSONDocument::LoadUrl(const std::string &osUrl,
     429             :                               const char *const *papszOptions,
     430             :                               GDALProgressFunc pfnProgress, void *pProgressArg)
     431             : #else
     432             : bool CPLJSONDocument::LoadUrl(const std::string & /*osUrl*/,
     433             :                               const char *const * /*papszOptions*/,
     434             :                               GDALProgressFunc /*pfnProgress*/,
     435             :                               void * /*pProgressArg*/)
     436             : #endif  // HAVE_CURL
     437             : {
     438             : #ifdef HAVE_CURL
     439             :     int nDepth =
     440           2 :         atoi(CSLFetchNameValueDef(papszOptions, "JSON_DEPTH",
     441             :                                   "32"));  // Same as JSON_TOKENER_DEFAULT_DEPTH
     442           2 :     JsonContext ctx = {nullptr, json_tokener_new_ex(nDepth)};
     443             : 
     444           2 :     CPLHTTPFetchWriteFunc pWriteFunc = CPLJSONWriteFunction;
     445             :     CPLHTTPResult *psResult =
     446           2 :         CPLHTTPFetchEx(osUrl.c_str(), papszOptions, pfnProgress, pProgressArg,
     447             :                        pWriteFunc, &ctx);
     448             : 
     449           2 :     bool bResult =
     450           2 :         psResult->nStatus == 0 /*CURLE_OK*/ && psResult->pszErrBuf == nullptr;
     451             : 
     452           2 :     CPLHTTPDestroyResult(psResult);
     453             : 
     454             :     enum json_tokener_error jerr;
     455           2 :     if ((jerr = json_tokener_get_error(ctx.pTokener)) != json_tokener_success)
     456             :     {
     457           0 :         CPLError(CE_Failure, CPLE_AppDefined, "JSON error: %s\n",
     458             :                  json_tokener_error_desc(jerr));
     459           0 :         bResult = false;
     460             :     }
     461             :     else
     462             :     {
     463           2 :         if (m_poRootJsonObject)
     464           1 :             json_object_put(TO_JSONOBJ(m_poRootJsonObject));
     465             : 
     466           2 :         m_poRootJsonObject = ctx.pObject;
     467             :     }
     468           2 :     json_tokener_free(ctx.pTokener);
     469             : 
     470           2 :     return bResult;
     471             : #else
     472             :     CPLError(CE_Failure, CPLE_NotSupported,
     473             :              "LoadUrl() not supported in a build without Curl");
     474             :     return false;
     475             : #endif
     476             : }
     477             : 
     478             : //------------------------------------------------------------------------------
     479             : // JSONObject
     480             : //------------------------------------------------------------------------------
     481             : /*! @cond Doxygen_Suppress */
     482      107950 : CPLJSONObject::CPLJSONObject() : m_poJsonObject(json_object_new_object())
     483             : {
     484      107950 : }
     485             : 
     486           1 : CPLJSONObject::CPLJSONObject(std::nullptr_t) : m_poJsonObject(nullptr)
     487             : {
     488           1 : }
     489             : 
     490           1 : CPLJSONObject::CPLJSONObject(const std::string &osVal)
     491           1 :     : m_poJsonObject(json_object_new_string(osVal.c_str()))
     492             : {
     493           1 : }
     494             : 
     495           1 : CPLJSONObject::CPLJSONObject(const char *pszValue)
     496           1 :     : m_poJsonObject(json_object_new_string(pszValue))
     497             : {
     498           1 : }
     499             : 
     500           1 : CPLJSONObject::CPLJSONObject(bool bVal)
     501           1 :     : m_poJsonObject(json_object_new_boolean(bVal))
     502             : {
     503           1 : }
     504             : 
     505           1 : CPLJSONObject::CPLJSONObject(int nVal)
     506           1 :     : m_poJsonObject(json_object_new_int(nVal))
     507             : {
     508           1 : }
     509             : 
     510           1 : CPLJSONObject::CPLJSONObject(int64_t nVal)
     511           1 :     : m_poJsonObject(json_object_new_int64(nVal))
     512             : {
     513           1 : }
     514             : 
     515           1 : CPLJSONObject::CPLJSONObject(uint64_t nVal)
     516           1 :     : m_poJsonObject(json_object_new_uint64(nVal))
     517             : {
     518           1 : }
     519             : 
     520           1 : CPLJSONObject::CPLJSONObject(double dfVal)
     521           1 :     : m_poJsonObject(json_object_new_double(dfVal))
     522             : {
     523           1 : }
     524             : 
     525         809 : CPLJSONObject::CPLJSONObject(const std::string &osName,
     526         809 :                              const CPLJSONObject &oParent)
     527         809 :     : m_poJsonObject(json_object_get(json_object_new_object())), m_osKey(osName)
     528             : {
     529         809 :     json_object_object_add(TO_JSONOBJ(oParent.m_poJsonObject), osName.c_str(),
     530         809 :                            TO_JSONOBJ(m_poJsonObject));
     531         809 : }
     532             : 
     533      776390 : CPLJSONObject::CPLJSONObject(const std::string &osName,
     534      776390 :                              JSONObjectH poJsonObject)
     535      776390 :     : m_poJsonObject(json_object_get(TO_JSONOBJ(poJsonObject))), m_osKey(osName)
     536             : {
     537      776390 : }
     538             : 
     539         499 : CPLJSONObject CPLJSONObject::Clone() const
     540             : {
     541         499 :     CPLJSONObject oRet;
     542         499 :     if (IsValid())
     543             :     {
     544         998 :         CPLJSONDocument oTmpDoc;
     545         499 :         oTmpDoc.SetRoot(*this);
     546         499 :         std::string osStr = oTmpDoc.SaveAsString();
     547         499 :         CPL_IGNORE_RET_VAL(oTmpDoc.LoadMemory(osStr));
     548         499 :         oRet = oTmpDoc.GetRoot();
     549             :     }
     550         499 :     return oRet;
     551             : }
     552             : 
     553     1598380 : CPLJSONObject::~CPLJSONObject()
     554             : {
     555             :     // Should delete m_poJsonObject only if CPLJSONObject has no parent
     556     1598380 :     if (m_poJsonObject)
     557             :     {
     558     1360460 :         json_object_put(TO_JSONOBJ(m_poJsonObject));
     559     1360460 :         m_poJsonObject = nullptr;
     560             :     }
     561     1598380 : }
     562             : 
     563      537985 : CPLJSONObject::CPLJSONObject(const CPLJSONObject &other)
     564      537985 :     : m_poJsonObject(json_object_get(TO_JSONOBJ(other.m_poJsonObject))),
     565      537985 :       m_osKey(other.m_osKey)
     566             : {
     567      537985 : }
     568             : 
     569      175237 : CPLJSONObject::CPLJSONObject(CPLJSONObject &&other)
     570      175237 :     : m_poJsonObject(other.m_poJsonObject), m_osKey(std::move(other.m_osKey))
     571             : {
     572      175237 :     other.m_poJsonObject = nullptr;
     573      175237 : }
     574             : 
     575       50233 : CPLJSONObject &CPLJSONObject::operator=(const CPLJSONObject &other)
     576             : {
     577       50233 :     if (this == &other)
     578           1 :         return *this;
     579             : 
     580       50232 :     m_osKey = other.m_osKey;
     581       50232 :     if (m_poJsonObject)
     582       49500 :         json_object_put(TO_JSONOBJ(m_poJsonObject));
     583       50232 :     m_poJsonObject = json_object_get(TO_JSONOBJ(other.m_poJsonObject));
     584       50232 :     return *this;
     585             : }
     586             : 
     587       11101 : CPLJSONObject &CPLJSONObject::operator=(CPLJSONObject &&other)
     588             : {
     589       11101 :     if (this == &other)
     590           0 :         return *this;
     591             : 
     592       11101 :     m_osKey = std::move(other.m_osKey);
     593       11101 :     if (m_poJsonObject)
     594        6117 :         json_object_put(TO_JSONOBJ(m_poJsonObject));
     595       11101 :     m_poJsonObject = other.m_poJsonObject;
     596       11101 :     other.m_poJsonObject = nullptr;
     597       11101 :     return *this;
     598             : }
     599             : 
     600             : /*! @endcond */
     601             : 
     602             : /**
     603             :  * Add new key - value pair to json object.
     604             :  * @param osName Key name.
     605             :  * @param osValue String value.
     606             :  *
     607             :  * @since GDAL 2.3
     608             :  */
     609       10669 : void CPLJSONObject::Add(const std::string &osName, const std::string &osValue)
     610             : {
     611       21338 :     std::string objectName;
     612       10669 :     if (m_osKey == INVALID_OBJ_KEY)
     613           0 :         m_osKey.clear();
     614       21338 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     615       10669 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     616             :                                 object.m_poJsonObject)) == json_type_object)
     617             :     {
     618       10669 :         json_object *poVal = json_object_new_string(osValue.c_str());
     619       10669 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     620             :                                objectName.c_str(), poVal);
     621             :     }
     622       10669 : }
     623             : 
     624             : /**
     625             :  * Add new key - value pair to json object.
     626             :  * @param osName Key name.
     627             :  * @param pszValue String value.
     628             :  *
     629             :  * @since GDAL 2.3
     630             :  */
     631       12415 : void CPLJSONObject::Add(const std::string &osName, const char *pszValue)
     632             : {
     633       12415 :     if (nullptr == pszValue)
     634             :     {
     635           1 :         return;
     636             :     }
     637       12414 :     if (m_osKey == INVALID_OBJ_KEY)
     638           0 :         m_osKey.clear();
     639       24828 :     std::string objectName;
     640       24828 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     641       12414 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     642             :                                 object.m_poJsonObject)) == json_type_object)
     643             :     {
     644       12414 :         json_object *poVal = json_object_new_string(pszValue);
     645       12414 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     646             :                                objectName.c_str(), poVal);
     647             :     }
     648             : }
     649             : 
     650             : // defined in ogr/ogrsf_frmts/geojson/ogrgeojsonwriter.cpp
     651             : CPL_C_START
     652             : /* %.XXXg formatting */
     653             : json_object CPL_DLL *
     654             : json_object_new_double_with_significant_figures(double dfVal,
     655             :                                                 int nSignificantFigures);
     656             : CPL_C_END
     657             : 
     658             : /**
     659             :  * Add new key - value pair to json object.
     660             :  * @param osName  Key name.
     661             :  * @param dfValue Double value.
     662             :  *
     663             :  * @since GDAL 2.3
     664             :  */
     665        8241 : void CPLJSONObject::Add(const std::string &osName, double dfValue)
     666             : {
     667       16482 :     std::string objectName;
     668        8241 :     if (m_osKey == INVALID_OBJ_KEY)
     669           0 :         m_osKey.clear();
     670       16482 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     671        8241 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     672             :                                 object.m_poJsonObject)) == json_type_object)
     673             :     {
     674             :         json_object *poVal =
     675        8241 :             json_object_new_double_with_significant_figures(dfValue, -1);
     676        8241 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     677             :                                objectName.c_str(), poVal);
     678             :     }
     679        8241 : }
     680             : 
     681             : /**
     682             :  * Add new key - value pair to json object.
     683             :  * @param osName  Key name.
     684             :  * @param nValue Integer value.
     685             :  *
     686             :  * @since GDAL 2.3
     687             :  */
     688       12156 : void CPLJSONObject::Add(const std::string &osName, int nValue)
     689             : {
     690       24312 :     std::string objectName;
     691       12156 :     if (m_osKey == INVALID_OBJ_KEY)
     692           0 :         m_osKey.clear();
     693       24312 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     694       12156 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     695             :                                 object.m_poJsonObject)) == json_type_object)
     696             :     {
     697       12156 :         json_object *poVal = json_object_new_int(nValue);
     698       12156 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     699             :                                objectName.c_str(), poVal);
     700             :     }
     701       12156 : }
     702             : 
     703             : /**
     704             :  * Add new key - value pair to json object.
     705             :  * @param osName  Key name.
     706             :  * @param nValue Long value.
     707             :  *
     708             :  * @since GDAL 2.3
     709             :  */
     710        3514 : void CPLJSONObject::Add(const std::string &osName, GInt64 nValue)
     711             : {
     712        7028 :     std::string objectName;
     713        3514 :     if (m_osKey == INVALID_OBJ_KEY)
     714           0 :         m_osKey.clear();
     715        7028 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     716        3514 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     717             :                                 object.m_poJsonObject)) == json_type_object)
     718             :     {
     719             :         json_object *poVal =
     720        3514 :             json_object_new_int64(static_cast<int64_t>(nValue));
     721        3514 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     722             :                                objectName.c_str(), poVal);
     723             :     }
     724        3514 : }
     725             : 
     726             : /**
     727             :  * Add new key - value pair to json object.
     728             :  * @param osName  Key name.
     729             :  * @param nValue uint64_t value.
     730             :  *
     731             :  * @since GDAL 3.8
     732             :  */
     733         452 : void CPLJSONObject::Add(const std::string &osName, uint64_t nValue)
     734             : {
     735         904 :     std::string objectName;
     736         452 :     if (m_osKey == INVALID_OBJ_KEY)
     737           0 :         m_osKey.clear();
     738         904 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     739         452 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     740             :                                 object.m_poJsonObject)) == json_type_object)
     741             :     {
     742         452 :         json_object *poVal = json_object_new_uint64(nValue);
     743         452 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     744             :                                objectName.c_str(), poVal);
     745             :     }
     746         452 : }
     747             : 
     748             : /**
     749             :  * Add new key - value pair to json object.
     750             :  * @param osName  Key name.
     751             :  * @param oValue   Array value.
     752             :  *
     753             :  * @since GDAL 2.3
     754             :  */
     755        4215 : void CPLJSONObject::Add(const std::string &osName, const CPLJSONArray &oValue)
     756             : {
     757        8430 :     std::string objectName;
     758        4215 :     if (m_osKey == INVALID_OBJ_KEY)
     759           0 :         m_osKey.clear();
     760        8430 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     761        4215 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     762             :                                 object.m_poJsonObject)) == json_type_object)
     763             :     {
     764        8430 :         json_object_object_add(
     765        4215 :             TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
     766        4215 :             json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
     767             :     }
     768        4215 : }
     769             : 
     770             : /**
     771             :  * Add new key - value pair to json object.
     772             :  * @param osName  Key name.
     773             :  * @param oValue   Json object value.
     774             :  *
     775             :  * @since GDAL 2.3
     776             :  */
     777       12027 : void CPLJSONObject::Add(const std::string &osName, const CPLJSONObject &oValue)
     778             : {
     779       12027 :     std::string objectName;
     780       12027 :     if (m_osKey == INVALID_OBJ_KEY)
     781           0 :         m_osKey.clear();
     782       12027 :     if (osName.empty())
     783             :     {
     784          18 :         json_object_object_add(
     785           9 :             TO_JSONOBJ(GetInternalHandle()), "",
     786           9 :             json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
     787           9 :         return;
     788             :     }
     789       24036 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     790       12018 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     791             :                                 object.m_poJsonObject)) == json_type_object)
     792             :     {
     793       24036 :         json_object_object_add(
     794       12018 :             TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
     795       12018 :             json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
     796             :     }
     797             : }
     798             : 
     799             : /**
     800             :  * Add new key - value pair to json object.
     801             :  * @param osName  Key name (do not split it on '/')
     802             :  * @param oValue   Json object value.
     803             :  *
     804             :  * @since GDAL 3.2
     805             :  */
     806         816 : void CPLJSONObject::AddNoSplitName(const std::string &osName,
     807             :                                    const CPLJSONObject &oValue)
     808             : {
     809         816 :     if (m_osKey == INVALID_OBJ_KEY)
     810           0 :         m_osKey.clear();
     811        1632 :     if (IsValid() &&
     812         816 :         json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_object)
     813             :     {
     814        1632 :         json_object_object_add(
     815         816 :             TO_JSONOBJ(GetInternalHandle()), osName.c_str(),
     816         816 :             json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
     817             :     }
     818         816 : }
     819             : 
     820             : /**
     821             :  * Add new key - value pair to json object.
     822             :  * @param osName  Key name.
     823             :  * @param bValue   Boolean value.
     824             :  *
     825             :  * @since GDAL 2.3
     826             :  */
     827         860 : void CPLJSONObject::Add(const std::string &osName, bool bValue)
     828             : {
     829        1720 :     std::string objectName;
     830         860 :     if (m_osKey == INVALID_OBJ_KEY)
     831           0 :         m_osKey.clear();
     832        1720 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     833         860 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     834             :                                 object.m_poJsonObject)) == json_type_object)
     835             :     {
     836         860 :         json_object *poVal = json_object_new_boolean(bValue);
     837         860 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     838             :                                objectName.c_str(), poVal);
     839             :     }
     840         860 : }
     841             : 
     842             : /**
     843             :  * Add new key - null pair to json object.
     844             :  * @param osName  Key name.
     845             :  *
     846             :  * @since GDAL 2.3
     847             :  */
     848        7117 : void CPLJSONObject::AddNull(const std::string &osName)
     849             : {
     850       14234 :     std::string objectName;
     851        7117 :     if (m_osKey == INVALID_OBJ_KEY)
     852           0 :         m_osKey.clear();
     853       14234 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     854        7117 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     855             :                                 object.m_poJsonObject)) == json_type_object)
     856             :     {
     857        7117 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     858             :                                objectName.c_str(), nullptr);
     859             :     }
     860        7117 : }
     861             : 
     862             : /**
     863             :  * Change value by key.
     864             :  * @param osName  Key name.
     865             :  * @param osValue String value.
     866             :  *
     867             :  * @since GDAL 2.3
     868             :  */
     869         500 : void CPLJSONObject::Set(const std::string &osName, const std::string &osValue)
     870             : {
     871         500 :     Delete(osName);
     872         500 :     Add(osName, osValue);
     873         500 : }
     874             : 
     875             : /**
     876             :  * Change value by key.
     877             :  * @param osName  Key name.
     878             :  * @param pszValue String value.
     879             :  *
     880             :  * @since GDAL 2.3
     881             :  */
     882        3523 : void CPLJSONObject::Set(const std::string &osName, const char *pszValue)
     883             : {
     884        3523 :     if (nullptr == pszValue)
     885           1 :         return;
     886        3522 :     Delete(osName);
     887        3522 :     Add(osName, pszValue);
     888             : }
     889             : 
     890             : /**
     891             :  * Change value by key.
     892             :  * @param osName  Key name.
     893             :  * @param dfValue  Double value.
     894             :  *
     895             :  * @since GDAL 2.3
     896             :  */
     897         515 : void CPLJSONObject::Set(const std::string &osName, double dfValue)
     898             : {
     899         515 :     Delete(osName);
     900         515 :     Add(osName, dfValue);
     901         515 : }
     902             : 
     903             : /**
     904             :  * Change value by key.
     905             :  * @param osName  Key name.
     906             :  * @param nValue   Integer value.
     907             :  *
     908             :  * @since GDAL 2.3
     909             :  */
     910        1382 : void CPLJSONObject::Set(const std::string &osName, int nValue)
     911             : {
     912        1382 :     Delete(osName);
     913        1382 :     Add(osName, nValue);
     914        1382 : }
     915             : 
     916             : /**
     917             :  * Change value by key.
     918             :  * @param osName  Key name.
     919             :  * @param nValue   Long value.
     920             :  *
     921             :  * @since GDAL 2.3
     922             :  */
     923         218 : void CPLJSONObject::Set(const std::string &osName, GInt64 nValue)
     924             : {
     925         218 :     Delete(osName);
     926         218 :     Add(osName, nValue);
     927         218 : }
     928             : 
     929             : /**
     930             :  * Change value by key.
     931             :  * @param osName  Key name.
     932             :  * @param nValue   uint64_t value.
     933             :  *
     934             :  * @since GDAL 3.8
     935             :  */
     936          40 : void CPLJSONObject::Set(const std::string &osName, uint64_t nValue)
     937             : {
     938          40 :     Delete(osName);
     939          40 :     Add(osName, nValue);
     940          40 : }
     941             : 
     942             : /**
     943             :  * Change value by key.
     944             :  * @param osName  Key name.
     945             :  * @param bValue   Boolean value.
     946             :  *
     947             :  * @since GDAL 2.3
     948             :  */
     949         414 : void CPLJSONObject::Set(const std::string &osName, bool bValue)
     950             : {
     951         414 :     Delete(osName);
     952         414 :     Add(osName, bValue);
     953         414 : }
     954             : 
     955             : /**
     956             :  * Change value by key.
     957             :  * @param osName  Key name.
     958             :  *
     959             :  * @since GDAL 2.3
     960             :  */
     961          13 : void CPLJSONObject::SetNull(const std::string &osName)
     962             : {
     963          13 :     Delete(osName);
     964          13 :     AddNull(osName);
     965          13 : }
     966             : 
     967             : /**
     968             :  * Get value by key.
     969             :  * @param  osName Key name.
     970             :  * @return         Json array object.
     971             :  *
     972             :  * @since GDAL 2.3
     973             :  */
     974       19683 : CPLJSONArray CPLJSONObject::GetArray(const std::string &osName) const
     975             : {
     976       39366 :     std::string objectName;
     977       39366 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     978       19683 :     if (object.IsValid())
     979             :     {
     980       19683 :         json_object *poVal = nullptr;
     981       19683 :         if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
     982       19683 :                                       objectName.c_str(), &poVal))
     983             :         {
     984       14449 :             if (poVal && json_object_get_type(poVal) == json_type_array)
     985             :             {
     986       14409 :                 return CPLJSONArray(objectName, poVal);
     987             :             }
     988             :         }
     989             :     }
     990        5274 :     return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
     991             : }
     992             : 
     993             : /**
     994             :  * Get value by key.
     995             :  * @param  osName Key name.
     996             :  * @return         Json object.
     997             :  *
     998             :  * @since GDAL 2.3
     999             :  */
    1000      394812 : CPLJSONObject CPLJSONObject::GetObj(const std::string &osName) const
    1001             : {
    1002      789624 :     std::string objectName;
    1003      789624 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
    1004      394812 :     if (object.IsValid())
    1005             :     {
    1006      394087 :         json_object *poVal = nullptr;
    1007      394087 :         if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
    1008      394087 :                                       objectName.c_str(), &poVal))
    1009             :         {
    1010      354334 :             return CPLJSONObject(objectName, poVal);
    1011             :         }
    1012             :     }
    1013       40478 :     return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
    1014             : }
    1015             : 
    1016             : /**
    1017             :  * Get value by key.
    1018             :  * @param  osName Key name.
    1019             :  * @return         Json object.
    1020             :  *
    1021             :  * @since GDAL 2.3
    1022             :  */
    1023       97516 : CPLJSONObject CPLJSONObject::operator[](const std::string &osName) const
    1024             : {
    1025       97516 :     return GetObj(osName);
    1026             : }
    1027             : 
    1028             : /**
    1029             :  * Delete json object by key.
    1030             :  * @param  osName Key name.
    1031             :  *
    1032             :  * @since GDAL 2.3
    1033             :  */
    1034        8831 : void CPLJSONObject::Delete(const std::string &osName)
    1035             : {
    1036       17662 :     std::string objectName;
    1037        8831 :     if (m_osKey == INVALID_OBJ_KEY)
    1038           0 :         m_osKey.clear();
    1039       17662 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
    1040        8831 :     if (object.IsValid())
    1041             :     {
    1042        8831 :         json_object_object_del(TO_JSONOBJ(object.GetInternalHandle()),
    1043             :                                objectName.c_str());
    1044             :     }
    1045        8831 : }
    1046             : 
    1047             : /**
    1048             :  * Delete json object by key (without splitting on /)
    1049             :  * @param  osName Key name.
    1050             :  *
    1051             :  * @since GDAL 3.4
    1052             :  */
    1053         829 : void CPLJSONObject::DeleteNoSplitName(const std::string &osName)
    1054             : {
    1055         829 :     if (m_osKey == INVALID_OBJ_KEY)
    1056           0 :         m_osKey.clear();
    1057         829 :     if (m_poJsonObject)
    1058             :     {
    1059         829 :         json_object_object_del(TO_JSONOBJ(m_poJsonObject), osName.c_str());
    1060             :     }
    1061         829 : }
    1062             : 
    1063             : /**
    1064             :  * Get value by key.
    1065             :  * @param  osName    Key name.
    1066             :  * @param  osDefault Default value.
    1067             :  * @return            String value.
    1068             :  *
    1069             :  * @since GDAL 2.3
    1070             :  */
    1071      235288 : std::string CPLJSONObject::GetString(const std::string &osName,
    1072             :                                      const std::string &osDefault) const
    1073             : {
    1074      470576 :     CPLJSONObject object = GetObj(osName);
    1075      470576 :     return object.ToString(osDefault);
    1076             : }
    1077             : 
    1078             : /**
    1079             :  * Get value.
    1080             :  * @param  osDefault Default value.
    1081             :  * @return            String value.
    1082             :  *
    1083             :  * @since GDAL 2.3
    1084             :  */
    1085      376755 : std::string CPLJSONObject::ToString(const std::string &osDefault) const
    1086             : {
    1087      376755 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1088             :             json_type_string*/ )
    1089             :     {
    1090             :         const char *pszString =
    1091      363151 :             json_object_get_string(TO_JSONOBJ(m_poJsonObject));
    1092      363151 :         if (nullptr != pszString)
    1093             :         {
    1094      363151 :             return pszString;
    1095             :         }
    1096             :     }
    1097       13604 :     return osDefault;
    1098             : }
    1099             : 
    1100             : /**
    1101             :  * Get value by key.
    1102             :  * @param  osName    Key name.
    1103             :  * @param  dfDefault  Default value.
    1104             :  * @return            Double value.
    1105             :  *
    1106             :  * @since GDAL 2.3
    1107             :  */
    1108        4854 : double CPLJSONObject::GetDouble(const std::string &osName,
    1109             :                                 double dfDefault) const
    1110             : {
    1111        9708 :     CPLJSONObject object = GetObj(osName);
    1112        9708 :     return object.ToDouble(dfDefault);
    1113             : }
    1114             : 
    1115             : /**
    1116             :  * Get value
    1117             :  * @param  dfDefault  Default value.
    1118             :  * @return            Double value.
    1119             :  *
    1120             :  * @since GDAL 2.3
    1121             :  */
    1122       18806 : double CPLJSONObject::ToDouble(double dfDefault) const
    1123             : {
    1124       18806 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1125             :             json_type_double*/ )
    1126       18372 :         return json_object_get_double(TO_JSONOBJ(m_poJsonObject));
    1127         434 :     return dfDefault;
    1128             : }
    1129             : 
    1130             : /**
    1131             :  * Get value by key.
    1132             :  * @param  osName    Key name.
    1133             :  * @param  nDefault   Default value.
    1134             :  * @return            Integer value.
    1135             :  *
    1136             :  * @since GDAL 2.3
    1137             :  */
    1138       20176 : int CPLJSONObject::GetInteger(const std::string &osName, int nDefault) const
    1139             : {
    1140       40352 :     CPLJSONObject object = GetObj(osName);
    1141       40352 :     return object.ToInteger(nDefault);
    1142             : }
    1143             : 
    1144             : /**
    1145             :  * Get value.
    1146             :  * @param  nDefault   Default value.
    1147             :  * @return            Integer value.
    1148             :  *
    1149             :  * @since GDAL 2.3
    1150             :  */
    1151       21843 : int CPLJSONObject::ToInteger(int nDefault) const
    1152             : {
    1153       21843 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1154             :             json_type_int*/ )
    1155       20434 :         return json_object_get_int(TO_JSONOBJ(m_poJsonObject));
    1156        1409 :     return nDefault;
    1157             : }
    1158             : 
    1159             : /**
    1160             :  * Get value by key.
    1161             :  * @param  osName    Key name.
    1162             :  * @param  nDefault   Default value.
    1163             :  * @return            Long value.
    1164             :  *
    1165             :  * @since GDAL 2.3
    1166             :  */
    1167          70 : GInt64 CPLJSONObject::GetLong(const std::string &osName, GInt64 nDefault) const
    1168             : {
    1169         140 :     CPLJSONObject object = GetObj(osName);
    1170         140 :     return object.ToLong(nDefault);
    1171             : }
    1172             : 
    1173             : /**
    1174             :  * Get value.
    1175             :  * @param  nDefault   Default value.
    1176             :  * @return            Long value.
    1177             :  *
    1178             :  * @since GDAL 2.3
    1179             :  */
    1180        2443 : GInt64 CPLJSONObject::ToLong(GInt64 nDefault) const
    1181             : {
    1182        2443 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1183             :             json_type_int*/ )
    1184             :         return static_cast<GInt64>(
    1185        2408 :             json_object_get_int64(TO_JSONOBJ(m_poJsonObject)));
    1186          35 :     return nDefault;
    1187             : }
    1188             : 
    1189             : /**
    1190             :  * Get value by key.
    1191             :  * @param  osName    Key name.
    1192             :  * @param  bDefault   Default value.
    1193             :  * @return            Boolean value.
    1194             :  *
    1195             :  * @since GDAL 2.3
    1196             :  */
    1197          67 : bool CPLJSONObject::GetBool(const std::string &osName, bool bDefault) const
    1198             : {
    1199         134 :     CPLJSONObject object = GetObj(osName);
    1200         134 :     return object.ToBool(bDefault);
    1201             : }
    1202             : 
    1203             : /**
    1204             :  * \brief Get json object children.
    1205             :  *
    1206             :  * This function is useful when keys is not know and need to
    1207             :  * iterate over json object items and get keys and values.
    1208             :  *
    1209             :  * @return Array of CPLJSONObject class instance.
    1210             :  *
    1211             :  * @since GDAL 2.3
    1212             :  */
    1213       11505 : std::vector<CPLJSONObject> CPLJSONObject::GetChildren() const
    1214             : {
    1215       11505 :     std::vector<CPLJSONObject> aoChildren;
    1216       23010 :     if (nullptr == m_poJsonObject ||
    1217       11505 :         json_object_get_type(TO_JSONOBJ(m_poJsonObject)) != json_type_object)
    1218             :     {
    1219           1 :         return aoChildren;
    1220             :     }
    1221             : 
    1222             :     json_object_iter it;
    1223       11504 :     it.key = nullptr;
    1224       11504 :     it.val = nullptr;
    1225       11504 :     it.entry = nullptr;
    1226             :     // cppcheck-suppress cstyleCast
    1227       58159 :     json_object_object_foreachC(TO_JSONOBJ(m_poJsonObject), it)
    1228             :     {
    1229       46655 :         aoChildren.push_back(CPLJSONObject(it.key, it.val));
    1230             :     }
    1231             : 
    1232       11504 :     return aoChildren;
    1233             : }
    1234             : 
    1235             : /**
    1236             :  * Get value.
    1237             :  * @param  bDefault   Default value.
    1238             :  * @return            Boolean value.
    1239             :  *
    1240             :  * @since GDAL 2.3
    1241             :  */
    1242          79 : bool CPLJSONObject::ToBool(bool bDefault) const
    1243             : {
    1244          79 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1245             :             json_type_boolean*/ )
    1246          22 :         return json_object_get_boolean(TO_JSONOBJ(m_poJsonObject)) == 1;
    1247          57 :     return bDefault;
    1248             : }
    1249             : 
    1250             : /**
    1251             :  * Get value.
    1252             :  * @return            Array
    1253             :  *
    1254             :  * @since GDAL 2.3
    1255             :  */
    1256        6915 : CPLJSONArray CPLJSONObject::ToArray() const
    1257             : {
    1258       12942 :     if (m_poJsonObject &&
    1259        6027 :         json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_array)
    1260        6023 :         return CPLJSONArray("", TO_JSONOBJ(m_poJsonObject));
    1261         892 :     return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
    1262             : }
    1263             : 
    1264             : /**
    1265             :  * Stringify object to json format.
    1266             :  * @param  eFormat Format type,
    1267             :  * @return         A string in JSON format.
    1268             :  *
    1269             :  * @since GDAL 2.3
    1270             :  */
    1271       15987 : std::string CPLJSONObject::Format(PrettyFormat eFormat) const
    1272             : {
    1273       15987 :     if (m_poJsonObject)
    1274             :     {
    1275       15987 :         const char *pszFormatString = nullptr;
    1276       15987 :         switch (eFormat)
    1277             :         {
    1278           1 :             case PrettyFormat::Spaced:
    1279           2 :                 pszFormatString = json_object_to_json_string_ext(
    1280           1 :                     TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_SPACED);
    1281           1 :                 break;
    1282         174 :             case PrettyFormat::Pretty:
    1283         348 :                 pszFormatString = json_object_to_json_string_ext(
    1284         174 :                     TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PRETTY);
    1285         174 :                 break;
    1286       15812 :             default:
    1287       15812 :                 pszFormatString = json_object_to_json_string_ext(
    1288       15812 :                     TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PLAIN);
    1289             :         }
    1290       15987 :         if (nullptr != pszFormatString)
    1291             :         {
    1292       15987 :             return pszFormatString;
    1293             :         }
    1294             :     }
    1295           0 :     return "";
    1296             : }
    1297             : 
    1298             : /*! @cond Doxygen_Suppress */
    1299      494982 : CPLJSONObject CPLJSONObject::GetObjectByPath(const std::string &osPath,
    1300             :                                              std::string &osName) const
    1301             : {
    1302      494982 :     json_object *poVal = nullptr;
    1303             : 
    1304             :     // Typically for keys that contain / character
    1305      494982 :     if (json_object_object_get_ex(TO_JSONOBJ(GetInternalHandle()),
    1306      494982 :                                   osPath.c_str(), &poVal))
    1307             :     {
    1308      369181 :         osName = osPath;
    1309      369181 :         return *this;
    1310             :     }
    1311             : 
    1312             :     CPLStringList pathPortions(
    1313      251602 :         CSLTokenizeString2(osPath.c_str(), JSON_PATH_DELIMITER, 0));
    1314      125801 :     int portionsCount = pathPortions.size();
    1315      125801 :     if (portionsCount > 100)
    1316             :     {
    1317           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Too many components in path");
    1318           0 :         return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
    1319             :     }
    1320      125801 :     if (0 == portionsCount)
    1321           0 :         return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
    1322      251602 :     CPLJSONObject object = *this;
    1323      128067 :     for (int i = 0; i < portionsCount - 1; ++i)
    1324             :     {
    1325             :         // TODO: check array index in path - i.e.
    1326             :         // settings/catalog/root/id:1/name if EQUALN(pathPortions[i+1], "id:",
    1327             :         // 3) -> getArray
    1328        2266 :         if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
    1329        4532 :                                       pathPortions[i], &poVal))
    1330             :         {
    1331        1457 :             object = CPLJSONObject(pathPortions[i], poVal);
    1332             :         }
    1333             :         else
    1334             :         {
    1335         809 :             if (json_object_get_type(TO_JSONOBJ(object.m_poJsonObject)) !=
    1336             :                 json_type_object)
    1337             :             {
    1338           0 :                 return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
    1339             :             }
    1340         809 :             object = CPLJSONObject(pathPortions[i], object);
    1341             :         }
    1342             :     }
    1343             : 
    1344             :     //    // Check if such object already  exists
    1345             :     //    if(json_object_object_get_ex(object.m_jsonObject,
    1346             :     //                                 pathPortions[portionsCount - 1], &poVal))
    1347             :     //        return JSONObject(nullptr);
    1348             :     //
    1349      125801 :     osName = pathPortions[portionsCount - 1];
    1350      125801 :     return object;
    1351             : }
    1352             : 
    1353             : /*! @endcond */
    1354             : 
    1355             : /**
    1356             :  * Get json object type.
    1357             :  * @return Json object type.
    1358             :  *
    1359             :  * @since GDAL 2.3
    1360             :  */
    1361       79638 : CPLJSONObject::Type CPLJSONObject::GetType() const
    1362             : {
    1363       79638 :     if (nullptr == m_poJsonObject)
    1364             :     {
    1365       10904 :         if (m_osKey == INVALID_OBJ_KEY)
    1366        8320 :             return CPLJSONObject::Type::Unknown;
    1367        2584 :         return CPLJSONObject::Type::Null;
    1368             :     }
    1369       68734 :     auto jsonObj(TO_JSONOBJ(m_poJsonObject));
    1370       68734 :     switch (json_object_get_type(jsonObj))
    1371             :     {
    1372          11 :         case json_type_boolean:
    1373          11 :             return CPLJSONObject::Type::Boolean;
    1374        2973 :         case json_type_double:
    1375        2973 :             return CPLJSONObject::Type::Double;
    1376       15175 :         case json_type_int:
    1377             :         {
    1378       15175 :             if (CPL_INT64_FITS_ON_INT32(json_object_get_int64(jsonObj)))
    1379       15138 :                 return CPLJSONObject::Type::Integer;
    1380             :             else
    1381          37 :                 return CPLJSONObject::Type::Long;
    1382             :         }
    1383        8479 :         case json_type_object:
    1384        8479 :             return CPLJSONObject::Type::Object;
    1385        4362 :         case json_type_array:
    1386        4362 :             return CPLJSONObject::Type::Array;
    1387       37734 :         case json_type_string:
    1388       37734 :             return CPLJSONObject::Type::String;
    1389           0 :         default:
    1390           0 :             break;
    1391             :     }
    1392           0 :     return CPLJSONObject::Type::Unknown;
    1393             : }
    1394             : 
    1395             : /**
    1396             :  * Check if json object valid.
    1397             :  * @return true if json object valid.
    1398             :  *
    1399             :  * @since GDAL 2.3
    1400             :  */
    1401      543500 : bool CPLJSONObject::IsValid() const
    1402             : {
    1403      543500 :     return m_osKey != INVALID_OBJ_KEY;
    1404             : }
    1405             : 
    1406             : /**
    1407             :  * Decrement reference counter and make pointer NULL.
    1408             :  * A json object will become invalid.
    1409             :  *
    1410             :  * @since GDAL 2.3
    1411             :  */
    1412        8687 : void CPLJSONObject::Deinit()
    1413             : {
    1414        8687 :     if (m_poJsonObject)
    1415             :     {
    1416        6496 :         json_object_put(TO_JSONOBJ(m_poJsonObject));
    1417        6496 :         m_poJsonObject = nullptr;
    1418             :     }
    1419        8687 :     m_osKey = INVALID_OBJ_KEY;
    1420        8687 : }
    1421             : 
    1422             : //------------------------------------------------------------------------------
    1423             : // JSONArray
    1424             : //------------------------------------------------------------------------------
    1425             : /*! @cond Doxygen_Suppress */
    1426       26514 : CPLJSONArray::CPLJSONArray()
    1427             : {
    1428       26514 :     json_object_put(TO_JSONOBJ(m_poJsonObject));
    1429       26514 :     m_poJsonObject = json_object_new_array();
    1430       26514 : }
    1431             : 
    1432           1 : CPLJSONArray::CPLJSONArray(const std::string &osName)
    1433           1 :     : CPLJSONObject(osName, json_object_new_array())
    1434             : {
    1435           1 :     json_object_put(TO_JSONOBJ(m_poJsonObject));
    1436           1 : }
    1437             : 
    1438       26769 : CPLJSONArray::CPLJSONArray(const std::string &osName, JSONObjectH poJsonObject)
    1439       26769 :     : CPLJSONObject(osName, poJsonObject)
    1440             : {
    1441       26769 : }
    1442             : 
    1443           9 : CPLJSONArray::CPLJSONArray(const CPLJSONObject &other) : CPLJSONObject(other)
    1444             : {
    1445           9 : }
    1446             : 
    1447             : /*! @endcond */
    1448             : 
    1449             : /**
    1450             :  * Get array size.
    1451             :  * @return Array size.
    1452             :  *
    1453             :  * @since GDAL 2.3
    1454             :  */
    1455      271664 : int CPLJSONArray::Size() const
    1456             : {
    1457      271664 :     if (m_poJsonObject)
    1458             :         return static_cast<int>(
    1459      269571 :             json_object_array_length(TO_JSONOBJ(m_poJsonObject)));
    1460        2093 :     return 0;
    1461             : }
    1462             : 
    1463             : /**
    1464             :  * Add null object to array.
    1465             :  *
    1466             :  * @since GDAL 3.8
    1467             :  */
    1468        1406 : void CPLJSONArray::AddNull()
    1469             : {
    1470        1406 :     if (m_poJsonObject)
    1471        1406 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject), nullptr);
    1472        1406 : }
    1473             : 
    1474             : /**
    1475             :  * Add json object to array.
    1476             :  * @param oValue Json array.
    1477             :  *
    1478             :  * @since GDAL 2.3
    1479             :  */
    1480        3370 : void CPLJSONArray::Add(const CPLJSONObject &oValue)
    1481             : {
    1482        3370 :     if (m_poJsonObject && oValue.m_poJsonObject)
    1483        6740 :         json_object_array_add(
    1484        3370 :             TO_JSONOBJ(m_poJsonObject),
    1485        3370 :             json_object_get(TO_JSONOBJ(oValue.m_poJsonObject)));
    1486        3370 : }
    1487             : 
    1488             : /**
    1489             :  * Add value to array
    1490             :  * @param osValue Value to add.
    1491             :  *
    1492             :  * @since GDAL 2.3
    1493             :  */
    1494        5637 : void CPLJSONArray::Add(const std::string &osValue)
    1495             : {
    1496        5637 :     if (m_poJsonObject)
    1497        5637 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1498             :                               json_object_new_string(osValue.c_str()));
    1499        5637 : }
    1500             : 
    1501             : /**
    1502             :  * Add value to array
    1503             :  * @param pszValue Value to add.
    1504             :  *
    1505             :  * @since GDAL 2.3
    1506             :  */
    1507         896 : void CPLJSONArray::Add(const char *pszValue)
    1508             : {
    1509         896 :     if (nullptr == pszValue)
    1510           0 :         return;
    1511         896 :     if (m_poJsonObject)
    1512         896 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1513             :                               json_object_new_string(pszValue));
    1514             : }
    1515             : 
    1516             : /**
    1517             :  * Add value to array
    1518             :  * @param dfValue Value to add.
    1519             :  *
    1520             :  * @since GDAL 2.3
    1521             :  */
    1522        1923 : void CPLJSONArray::Add(double dfValue)
    1523             : {
    1524        1923 :     if (m_poJsonObject)
    1525        1923 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1526             :                               json_object_new_double(dfValue));
    1527        1923 : }
    1528             : 
    1529             : /**
    1530             :  * Add value to array
    1531             :  * @param nValue Value to add.
    1532             :  *
    1533             :  * @since GDAL 2.3
    1534             :  */
    1535         582 : void CPLJSONArray::Add(int nValue)
    1536             : {
    1537         582 :     if (m_poJsonObject)
    1538         582 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1539             :                               json_object_new_int(nValue));
    1540         582 : }
    1541             : 
    1542             : /**
    1543             :  * Add value to array
    1544             :  * @param nValue Value to add.
    1545             :  *
    1546             :  * @since GDAL 2.3
    1547             :  */
    1548        1404 : void CPLJSONArray::Add(GInt64 nValue)
    1549             : {
    1550        1404 :     if (m_poJsonObject)
    1551        1404 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1552             :                               json_object_new_int64(nValue));
    1553        1404 : }
    1554             : 
    1555             : /**
    1556             :  * Add value to array
    1557             :  * @param nValue Value to add.
    1558             :  *
    1559             :  * @since GDAL 3.8
    1560             :  */
    1561          16 : void CPLJSONArray::Add(uint64_t nValue)
    1562             : {
    1563          16 :     if (m_poJsonObject)
    1564             :     {
    1565          16 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1566             :                               json_object_new_uint64(nValue));
    1567             :     }
    1568          16 : }
    1569             : 
    1570             : /**
    1571             :  * Add value to array
    1572             :  * @param bValue Value to add.
    1573             :  *
    1574             :  * @since GDAL 2.3
    1575             :  */
    1576          18 : void CPLJSONArray::Add(bool bValue)
    1577             : {
    1578          18 :     if (m_poJsonObject)
    1579          18 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1580             :                               json_object_new_boolean(bValue));
    1581          18 : }
    1582             : 
    1583             : /**
    1584             :  * Get array item by index.
    1585             :  * @param  nIndex Item index.
    1586             :  * @return        Json object.
    1587             :  *
    1588             :  * @since GDAL 2.3
    1589             :  */
    1590        2929 : CPLJSONObject CPLJSONArray::operator[](int nIndex)
    1591             : {
    1592             :     return CPLJSONObject(
    1593             :         CPLSPrintf("id:%d", nIndex),
    1594        2929 :         json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
    1595             : }
    1596             : 
    1597             : /**
    1598             :  * Get array const item by index.
    1599             :  * @param  nIndex Item index.
    1600             :  * @return        Json object.
    1601             :  *
    1602             :  * @since GDAL 2.3
    1603             :  */
    1604      290849 : const CPLJSONObject CPLJSONArray::operator[](int nIndex) const
    1605             : {
    1606             :     return CPLJSONObject(
    1607             :         CPLSPrintf("id:%d", nIndex),
    1608      290849 :         json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
    1609             : }
    1610             : 
    1611             : /************************************************************************/
    1612             : /*                      CPLParseKeyValueJson()                          */
    1613             : /************************************************************************/
    1614             : 
    1615             : /** Return a string list of key/value pairs extracted from a JSON doc.
    1616             : 
    1617             :     We are expecting simple documents with key:value pairs, like the
    1618             :     following with no hierarchy or complex structure.
    1619             :     \verbatim
    1620             :     {
    1621             :       "Code" : "Success",
    1622             :       "LastUpdated" : "2017-07-03T16:20:17Z",
    1623             :       "Type" : "AWS-HMAC",
    1624             :       "AccessKeyId" : "bla",
    1625             :       "SecretAccessKey" : "bla",
    1626             :       "Token" : "bla",
    1627             :       "Expiration" : "2017-07-03T22:42:58Z"
    1628             :     }
    1629             :     \endverbatim
    1630             :     @since GDAL 3.7
    1631             :  */
    1632          34 : CPLStringList CPLParseKeyValueJson(const char *pszJson)
    1633             : {
    1634          68 :     CPLJSONDocument oDoc;
    1635          34 :     CPLStringList oNameValue;
    1636          34 :     if (pszJson != nullptr && oDoc.LoadMemory(pszJson))
    1637             :     {
    1638         122 :         for (const auto &obj : oDoc.GetRoot().GetChildren())
    1639             :         {
    1640          88 :             const auto eType = obj.GetType();
    1641          88 :             if (eType == CPLJSONObject::Type::String ||
    1642           0 :                 eType == CPLJSONObject::Type::Integer ||
    1643             :                 eType == CPLJSONObject::Type::Double)
    1644             :             {
    1645         176 :                 oNameValue.SetNameValue(obj.GetName().c_str(),
    1646         264 :                                         obj.ToString().c_str());
    1647             :             }
    1648             :         }
    1649             :     }
    1650          68 :     return oNameValue;
    1651             : }

Generated by: LCOV version 1.14