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

Generated by: LCOV version 1.14