LCOV - code coverage report
Current view: top level - port - cpl_json.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 589 662 89.0 %
Date: 2026-07-24 18:27:47 Functions: 91 94 96.8 %

          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       31525 : CPLJSONDocument::CPLJSONDocument() : m_poRootJsonObject(nullptr)
      59             : {
      60       31525 : }
      61             : 
      62       63064 : CPLJSONDocument::~CPLJSONDocument()
      63             : {
      64       31532 :     if (m_poRootJsonObject)
      65       25682 :         json_object_put(TO_JSONOBJ(m_poRootJsonObject));
      66       31532 : }
      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             :  */
     113        1576 : bool CPLJSONDocument::Save(const std::string &osPath) const
     114             : {
     115        1576 :     VSILFILE *fp = VSIFOpenL(osPath.c_str(), "wt");
     116        1576 :     if (nullptr == fp)
     117             :     {
     118          14 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
     119             :                  "File %s cannot be opened for writing", osPath.c_str());
     120          14 :         return false;
     121             :     }
     122             : 
     123        3124 :     const char *pabyData = json_object_to_json_string_ext(
     124        1562 :         TO_JSONOBJ(m_poRootJsonObject), JSON_C_TO_STRING_PRETTY);
     125        1562 :     bool bRet = VSIFWriteL(pabyData, strlen(pabyData), 1, fp) == 1;
     126             : 
     127        1562 :     bRet = VSIFCloseL(fp) == 0 && bRet;
     128             : 
     129        1562 :     return bRet;
     130             : }
     131             : 
     132             : /**
     133             :  * Return the json document as a serialized string.
     134             :  * @return         serialized document.
     135             :  *
     136             :  */
     137       10016 : std::string CPLJSONDocument::SaveAsString() const
     138             : {
     139       10016 :     return json_object_to_json_string_ext(TO_JSONOBJ(m_poRootJsonObject),
     140       10016 :                                           JSON_C_TO_STRING_PRETTY);
     141             : }
     142             : 
     143             : /**
     144             :  * Get json document root object
     145             :  * @return CPLJSONObject class instance
     146             :  *
     147             :  * @since GDAL 3.1
     148             :  */
     149          93 : const CPLJSONObject CPLJSONDocument::GetRoot() const
     150             : {
     151          93 :     return const_cast<CPLJSONDocument *>(this)->GetRoot();
     152             : }
     153             : 
     154             : /**
     155             :  * Get json document root object
     156             :  * @return CPLJSONObject class instance
     157             :  *
     158             :  */
     159       32271 : CPLJSONObject CPLJSONDocument::GetRoot()
     160             : {
     161       32271 :     if (nullptr == m_poRootJsonObject)
     162             :     {
     163        1867 :         m_poRootJsonObject = json_object_new_object();
     164             :     }
     165             : 
     166       32271 :     if (json_object_get_type(TO_JSONOBJ(m_poRootJsonObject)) == json_type_array)
     167             :     {
     168        7028 :         return CPLJSONArray("", m_poRootJsonObject);
     169             :     }
     170             :     else
     171             :     {
     172       28757 :         return CPLJSONObject("", m_poRootJsonObject);
     173             :     }
     174             : }
     175             : 
     176             : /**
     177             :  * Set json document root object
     178             :  * @param oRoot CPLJSONObject root object
     179             :  *
     180             :  * @since GDAL 3.4
     181             :  */
     182        9658 : void CPLJSONDocument::SetRoot(const CPLJSONObject &oRoot)
     183             : {
     184        9658 :     if (m_poRootJsonObject)
     185           0 :         json_object_put(TO_JSONOBJ(m_poRootJsonObject));
     186        9658 :     m_poRootJsonObject = json_object_get(TO_JSONOBJ(oRoot.m_poJsonObject));
     187        9658 : }
     188             : 
     189             : /**
     190             :  * Load json document from file by provided path
     191             :  * @param  osPath Path to json file.
     192             :  * @return         true on success. If error occurred it can be received using
     193             :  * CPLGetLastErrorMsg method.
     194             :  *
     195             :  */
     196        7919 : bool CPLJSONDocument::Load(const std::string &osPath)
     197             : {
     198        7919 :     GByte *pabyOut = nullptr;
     199        7919 :     vsi_l_offset nSize = 0;
     200             : 
     201        7919 :     GIntBig nMaxSize = 0;
     202        7919 :     if (CPLParseMemorySize(CPLGetConfigOption("CPL_JSON_MAX_SIZE", "100MB"),
     203       15838 :                            &nMaxSize, nullptr) != CE_None ||
     204        7919 :         nMaxSize <= 0)
     205           0 :         return false;
     206             : 
     207        7919 :     if (!VSIIngestFile(nullptr, osPath.c_str(), &pabyOut, &nSize, nMaxSize))
     208             :     {
     209         755 :         CPLError(CE_Failure, CPLE_FileIO, "Load json file %s failed",
     210             :                  osPath.c_str());
     211         755 :         return false;
     212             :     }
     213             : 
     214        7164 :     bool bResult = LoadMemory(pabyOut, static_cast<int>(nSize));
     215        7164 :     VSIFree(pabyOut);
     216        7164 :     return bResult;
     217             : }
     218             : 
     219             : /**
     220             :  * Load json document from memory buffer.
     221             :  * @param  pabyData Buffer.data.
     222             :  * @param  nLength  Buffer size.
     223             :  * @return          true on success. If error occurred it can be received using
     224             :  * CPLGetLastErrorMsg method.
     225             :  *
     226             :  */
     227       23576 : bool CPLJSONDocument::LoadMemory(const GByte *pabyData, int nLength)
     228             : {
     229       23576 :     if (nullptr == pabyData)
     230             :     {
     231           1 :         return false;
     232             :     }
     233             : 
     234       23575 :     if (m_poRootJsonObject)
     235        9366 :         json_object_put(TO_JSONOBJ(m_poRootJsonObject));
     236             : 
     237       23575 :     if (nLength == 4 &&
     238           8 :         memcmp(reinterpret_cast<const char *>(pabyData), "true", nLength) == 0)
     239             :     {
     240           5 :         m_poRootJsonObject = json_object_new_boolean(true);
     241           5 :         return true;
     242             :     }
     243             : 
     244       23570 :     if (nLength == 5 &&
     245           6 :         memcmp(reinterpret_cast<const char *>(pabyData), "false", nLength) == 0)
     246             :     {
     247           3 :         m_poRootJsonObject = json_object_new_boolean(false);
     248           3 :         return true;
     249             :     }
     250             : 
     251       23567 :     json_tokener *jstok = json_tokener_new();
     252       23567 :     m_poRootJsonObject = json_tokener_parse_ex(
     253             :         jstok, reinterpret_cast<const char *>(pabyData), nLength);
     254       23567 :     bool bParsed = jstok->err == json_tokener_success;
     255       23567 :     if (!bParsed)
     256             :     {
     257          35 :         CPLError(CE_Failure, CPLE_AppDefined,
     258             :                  "JSON parsing error: %s (at offset %d)",
     259             :                  json_tokener_error_desc(jstok->err), jstok->char_offset);
     260          35 :         json_tokener_free(jstok);
     261          35 :         return false;
     262             :     }
     263       23532 :     json_tokener_free(jstok);
     264       23531 :     return bParsed;
     265             : }
     266             : 
     267             : /**
     268             :  * Load json document from memory buffer.
     269             :  * @param  osStr    String
     270             :  * @return          true on success. If error occurred it can be received using
     271             :  * CPLGetLastErrorMsg method.
     272             :  *
     273             :  */
     274       16307 : bool CPLJSONDocument::LoadMemory(const std::string &osStr)
     275             : {
     276       16307 :     if (osStr.empty())
     277           3 :         return false;
     278       16304 :     return LoadMemory(reinterpret_cast<const GByte *>(osStr.data()),
     279       32607 :                       static_cast<int>(osStr.size()));
     280             : }
     281             : 
     282             : /**
     283             :  * Load json document from file using small chunks of data.
     284             :  * @param  osPath      Path to json document file.
     285             :  * @param  nChunkSize   Chunk size.
     286             :  * @param  pfnProgress  a function to report progress of the json data loading.
     287             :  * @param  pProgressArg application data passed into progress function.
     288             :  * @return              true on success. If error occurred it can be received
     289             :  * using CPLGetLastErrorMsg method.
     290             :  *
     291             :  */
     292           3 : bool CPLJSONDocument::LoadChunks(const std::string &osPath, size_t nChunkSize,
     293             :                                  GDALProgressFunc pfnProgress,
     294             :                                  void *pProgressArg)
     295             : {
     296             :     VSIStatBufL sStatBuf;
     297           3 :     if (VSIStatL(osPath.c_str(), &sStatBuf) != 0)
     298             :     {
     299           2 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", osPath.c_str());
     300           2 :         return false;
     301             :     }
     302             : 
     303           1 :     VSILFILE *fp = VSIFOpenL(osPath.c_str(), "rb");
     304           1 :     if (fp == nullptr)
     305             :     {
     306           0 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", osPath.c_str());
     307           0 :         return false;
     308             :     }
     309             : 
     310           1 :     void *pBuffer = CPLMalloc(nChunkSize);
     311           1 :     json_tokener *tok = json_tokener_new();
     312           1 :     bool bSuccess = true;
     313           1 :     GUInt32 nFileSize = static_cast<GUInt32>(sStatBuf.st_size);
     314           1 :     double dfTotalRead = 0.0;
     315             : 
     316             :     while (true)
     317             :     {
     318           6 :         size_t nRead = VSIFReadL(pBuffer, 1, nChunkSize, fp);
     319           6 :         dfTotalRead += nRead;
     320             : 
     321           6 :         if (m_poRootJsonObject)
     322           1 :             json_object_put(TO_JSONOBJ(m_poRootJsonObject));
     323             : 
     324           6 :         m_poRootJsonObject = json_tokener_parse_ex(
     325             :             tok, static_cast<const char *>(pBuffer), static_cast<int>(nRead));
     326             : 
     327           6 :         enum json_tokener_error jerr = json_tokener_get_error(tok);
     328           6 :         if (jerr != json_tokener_continue && jerr != json_tokener_success)
     329             :         {
     330           0 :             CPLError(CE_Failure, CPLE_AppDefined, "JSON error: %s",
     331             :                      json_tokener_error_desc(jerr));
     332           0 :             bSuccess = false;
     333           0 :             break;
     334             :         }
     335             : 
     336           6 :         if (nRead < nChunkSize)
     337             :         {
     338           1 :             break;
     339             :         }
     340             : 
     341           5 :         if (nullptr != pfnProgress)
     342             :         {
     343           0 :             pfnProgress(dfTotalRead / nFileSize, "Loading ...", pProgressArg);
     344             :         }
     345           5 :     }
     346             : 
     347           1 :     json_tokener_free(tok);
     348           1 :     CPLFree(pBuffer);
     349           1 :     VSIFCloseL(fp);
     350             : 
     351           1 :     if (nullptr != pfnProgress)
     352             :     {
     353           0 :         pfnProgress(1.0, "Loading ...", pProgressArg);
     354             :     }
     355             : 
     356           1 :     return bSuccess;
     357             : }
     358             : 
     359             : /*! @cond Doxygen_Suppress */
     360             : #ifdef HAVE_CURL
     361             : 
     362             : typedef struct
     363             : {
     364             :     json_object *pObject;
     365             :     json_tokener *pTokener;
     366             : } JsonContext, *JsonContextL;
     367             : 
     368           0 : static size_t CPLJSONWriteFunction(void *pBuffer, size_t nSize, size_t nMemb,
     369             :                                    void *pUserData)
     370             : {
     371           0 :     size_t nLength = nSize * nMemb;
     372           0 :     JsonContextL ctx = static_cast<JsonContextL>(pUserData);
     373           0 :     if (ctx->pObject != nullptr)
     374             :     {
     375           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     376             :                  "A complete JSon object had already been parsed before new "
     377             :                  "content is appended to it");
     378           0 :         return 0;
     379             :     }
     380           0 :     ctx->pObject =
     381           0 :         json_tokener_parse_ex(ctx->pTokener, static_cast<const char *>(pBuffer),
     382             :                               static_cast<int>(nLength));
     383           0 :     switch (json_tokener_get_error(ctx->pTokener))
     384             :     {
     385           0 :         case json_tokener_continue:
     386             :         case json_tokener_success:
     387           0 :             return nLength;
     388           0 :         default:
     389           0 :             return 0; /* error: interrupt the transfer */
     390             :     }
     391             : }
     392             : 
     393             : #endif  // HAVE_CURL
     394             : /*! @endcond */
     395             : 
     396             : /**
     397             :  * Load json document from web.
     398             :  * @param  osUrl       Url to json document.
     399             :  * @param  papszOptions Option list as a NULL-terminated array of strings. May
     400             :  * be NULL. The available keys are same for CPLHTTPFetch method. Additional key
     401             :  * JSON_DEPTH define json parse depth. Default is 10.
     402             :  * @param  pfnProgress  a function to report progress of the json data loading.
     403             :  * @param  pProgressArg application data passed into progress function.
     404             :  * @return              true on success. If error occurred it can be received
     405             :  * using CPLGetLastErrorMsg method.
     406             :  *
     407             :  */
     408             : 
     409             : #ifdef HAVE_CURL
     410           2 : bool CPLJSONDocument::LoadUrl(const std::string &osUrl,
     411             :                               const char *const *papszOptions,
     412             :                               GDALProgressFunc pfnProgress, void *pProgressArg)
     413             : #else
     414             : bool CPLJSONDocument::LoadUrl(const std::string & /*osUrl*/,
     415             :                               const char *const * /*papszOptions*/,
     416             :                               GDALProgressFunc /*pfnProgress*/,
     417             :                               void * /*pProgressArg*/)
     418             : #endif  // HAVE_CURL
     419             : {
     420             : #ifdef HAVE_CURL
     421             :     int nDepth =
     422           2 :         atoi(CSLFetchNameValueDef(papszOptions, "JSON_DEPTH",
     423             :                                   "32"));  // Same as JSON_TOKENER_DEFAULT_DEPTH
     424           2 :     JsonContext ctx = {nullptr, json_tokener_new_ex(nDepth)};
     425             : 
     426           2 :     CPLHTTPFetchWriteFunc pWriteFunc = CPLJSONWriteFunction;
     427             :     CPLHTTPResult *psResult =
     428           2 :         CPLHTTPFetchEx(osUrl.c_str(), papszOptions, pfnProgress, pProgressArg,
     429             :                        pWriteFunc, &ctx);
     430             : 
     431           2 :     bool bResult =
     432           2 :         psResult->nStatus == 0 /*CURLE_OK*/ && psResult->pszErrBuf == nullptr;
     433             : 
     434           2 :     CPLHTTPDestroyResult(psResult);
     435             : 
     436             :     enum json_tokener_error jerr;
     437           2 :     if ((jerr = json_tokener_get_error(ctx.pTokener)) != json_tokener_success)
     438             :     {
     439           0 :         CPLError(CE_Failure, CPLE_AppDefined, "JSON error: %s\n",
     440             :                  json_tokener_error_desc(jerr));
     441           0 :         bResult = false;
     442             :     }
     443             :     else
     444             :     {
     445           2 :         if (m_poRootJsonObject)
     446           1 :             json_object_put(TO_JSONOBJ(m_poRootJsonObject));
     447             : 
     448           2 :         m_poRootJsonObject = ctx.pObject;
     449             :     }
     450           2 :     json_tokener_free(ctx.pTokener);
     451             : 
     452           2 :     return bResult;
     453             : #else
     454             :     CPLError(CE_Failure, CPLE_NotSupported,
     455             :              "LoadUrl() not supported in a build without Curl");
     456             :     return false;
     457             : #endif
     458             : }
     459             : 
     460             : //------------------------------------------------------------------------------
     461             : // JSONObject
     462             : //------------------------------------------------------------------------------
     463             : /*! @cond Doxygen_Suppress */
     464      251508 : CPLJSONObject::CPLJSONObject() : m_poJsonObject(json_object_new_object())
     465             : {
     466      251502 : }
     467             : 
     468           1 : CPLJSONObject::CPLJSONObject(std::nullptr_t) : m_poJsonObject(nullptr)
     469             : {
     470           1 : }
     471             : 
     472        4358 : CPLJSONObject::CPLJSONObject(const std::string &osVal)
     473        4358 :     : m_poJsonObject(json_object_new_string(osVal.c_str()))
     474             : {
     475        4358 : }
     476             : 
     477           1 : CPLJSONObject::CPLJSONObject(const char *pszValue)
     478           1 :     : m_poJsonObject(json_object_new_string(pszValue))
     479             : {
     480           1 : }
     481             : 
     482           1 : CPLJSONObject::CPLJSONObject(bool bVal)
     483           1 :     : m_poJsonObject(json_object_new_boolean(bVal))
     484             : {
     485           1 : }
     486             : 
     487        2981 : CPLJSONObject::CPLJSONObject(int nVal)
     488        2981 :     : m_poJsonObject(json_object_new_int(nVal))
     489             : {
     490        2981 : }
     491             : 
     492           1 : CPLJSONObject::CPLJSONObject(int64_t nVal)
     493           1 :     : m_poJsonObject(json_object_new_int64(nVal))
     494             : {
     495           1 : }
     496             : 
     497           1 : CPLJSONObject::CPLJSONObject(uint64_t nVal)
     498           1 :     : m_poJsonObject(json_object_new_uint64(nVal))
     499             : {
     500           1 : }
     501             : 
     502        1784 : CPLJSONObject::CPLJSONObject(double dfVal)
     503        1784 :     : m_poJsonObject(json_object_new_double(dfVal))
     504             : {
     505        1784 : }
     506             : 
     507         835 : CPLJSONObject::CPLJSONObject(const std::string &osName,
     508         835 :                              const CPLJSONObject &oParent)
     509         835 :     : m_poJsonObject(json_object_get(json_object_new_object())), m_osKey(osName)
     510             : {
     511         835 :     json_object_object_add(TO_JSONOBJ(oParent.m_poJsonObject), osName.c_str(),
     512         835 :                            TO_JSONOBJ(m_poJsonObject));
     513         835 : }
     514             : 
     515     1709040 : CPLJSONObject::CPLJSONObject(const std::string &osName,
     516     1709040 :                              JSONObjectH poJsonObject)
     517     1709040 :     : m_poJsonObject(json_object_get(TO_JSONOBJ(poJsonObject))), m_osKey(osName)
     518             : {
     519     1709020 : }
     520             : 
     521        9270 : CPLJSONObject CPLJSONObject::Clone() const
     522             : {
     523        9270 :     CPLJSONObject oRet;
     524        9270 :     if (IsValid())
     525             :     {
     526       17050 :         CPLJSONDocument oTmpDoc;
     527        8525 :         oTmpDoc.SetRoot(*this);
     528        8525 :         std::string osStr = oTmpDoc.SaveAsString();
     529        8525 :         CPL_IGNORE_RET_VAL(oTmpDoc.LoadMemory(osStr));
     530        8525 :         oRet = oTmpDoc.GetRoot();
     531             :     }
     532        9270 :     return oRet;
     533             : }
     534             : 
     535     3649600 : CPLJSONObject::~CPLJSONObject()
     536             : {
     537             :     // Should delete m_poJsonObject only if CPLJSONObject has no parent
     538     3649600 :     if (m_poJsonObject)
     539             :     {
     540     3013190 :         json_object_put(TO_JSONOBJ(m_poJsonObject));
     541     3013190 :         m_poJsonObject = nullptr;
     542             :     }
     543     3649590 : }
     544             : 
     545     1277360 : CPLJSONObject::CPLJSONObject(const CPLJSONObject &other)
     546     1277360 :     : m_poJsonObject(json_object_get(TO_JSONOBJ(other.m_poJsonObject))),
     547     1277330 :       m_osKey(other.m_osKey), m_osKeyForSet(other.m_osKeyForSet)
     548             : {
     549     1277360 : }
     550             : 
     551      401740 : CPLJSONObject::CPLJSONObject(CPLJSONObject &&other)
     552      401740 :     : m_poJsonObject(other.m_poJsonObject), m_osKey(std::move(other.m_osKey)),
     553      401740 :       m_osKeyForSet(std::move(other.m_osKeyForSet))
     554             : {
     555      401735 :     other.m_poJsonObject = nullptr;
     556      401735 : }
     557             : 
     558      124258 : CPLJSONObject &CPLJSONObject::operator=(const CPLJSONObject &other)
     559             : {
     560      124258 :     if (this == &other)
     561           1 :         return *this;
     562             : 
     563      124257 :     if (!m_osKeyForSet.empty())
     564             :     {
     565         360 :         std::string osKeyForSet = m_osKeyForSet;
     566         180 :         m_osKeyForSet.clear();
     567         180 :         Set(osKeyForSet, other);
     568             :     }
     569             :     else
     570             :     {
     571      124077 :         m_osKey = other.m_osKey;
     572      124077 :         if (m_poJsonObject)
     573      122974 :             json_object_put(TO_JSONOBJ(m_poJsonObject));
     574      124077 :         m_poJsonObject = json_object_get(TO_JSONOBJ(other.m_poJsonObject));
     575             :     }
     576      124257 :     return *this;
     577             : }
     578             : 
     579       39668 : CPLJSONObject &CPLJSONObject::operator=(CPLJSONObject &&other)
     580             : {
     581       39668 :     if (this == &other)
     582           0 :         return *this;
     583             : 
     584       39668 :     if (!m_osKeyForSet.empty())
     585             :     {
     586         997 :         if (other.m_poJsonObject)
     587             :         {
     588         997 :             json_object_object_add(TO_JSONOBJ(GetInternalHandle()),
     589             :                                    m_osKeyForSet.c_str(),
     590         997 :                                    TO_JSONOBJ(other.m_poJsonObject));
     591         997 :             other.m_poJsonObject = nullptr;
     592             :         }
     593         997 :         other.m_osKey = INVALID_OBJ_KEY;
     594         997 :         m_osKeyForSet.clear();
     595             :     }
     596             :     else
     597             :     {
     598       38671 :         m_osKey = std::move(other.m_osKey);
     599       38671 :         if (m_poJsonObject)
     600       33578 :             json_object_put(TO_JSONOBJ(m_poJsonObject));
     601       38671 :         m_poJsonObject = other.m_poJsonObject;
     602       38671 :         other.m_poJsonObject = nullptr;
     603             :     }
     604       39668 :     return *this;
     605             : }
     606             : 
     607         487 : CPLJSONObject &CPLJSONObject::operator=(CPLJSONArray &&other)
     608             : {
     609         487 :     return operator=(static_cast<CPLJSONObject &&>(other));
     610             : }
     611             : 
     612             : /*! @endcond */
     613             : 
     614             : /**
     615             :  * Add new key - value pair to json object.
     616             :  * @param osName Key name.
     617             :  * @param osValue String value.
     618             :  *
     619             :  */
     620       30780 : void CPLJSONObject::Add(const std::string &osName, const std::string &osValue)
     621             : {
     622       61560 :     std::string objectName;
     623       30780 :     if (m_osKey == INVALID_OBJ_KEY)
     624           0 :         m_osKey.clear();
     625       61560 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     626       30780 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     627             :                                 object.m_poJsonObject)) == json_type_object)
     628             :     {
     629       30780 :         json_object *poVal = json_object_new_string(osValue.c_str());
     630       30780 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     631             :                                objectName.c_str(), poVal);
     632             :     }
     633       30780 : }
     634             : 
     635             : /** Add new key - value pair to json object.
     636             :  *
     637             :  * @param osName Key name.
     638             :  * @param svValue String value.
     639             :  * @since 3.13
     640             :  */
     641          16 : void CPLJSONObject::Add(const std::string &osName, std::string_view svValue)
     642             : {
     643          16 :     std::string objectName;
     644          16 :     if (m_osKey == INVALID_OBJ_KEY)
     645           0 :         m_osKey.clear();
     646          16 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     647          16 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     648             :                                 object.m_poJsonObject)) == json_type_object)
     649             :     {
     650          16 :         if (svValue.size() > static_cast<size_t>(INT_MAX - 1))
     651             :         {
     652           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Too long string view");
     653           0 :             return;
     654             :         }
     655          16 :         json_object *poVal = json_object_new_string_len(
     656          16 :             svValue.data(), static_cast<int>(svValue.size()));
     657          16 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     658             :                                objectName.c_str(), poVal);
     659             :     }
     660             : }
     661             : 
     662             : /**
     663             :  * Add new key - value pair to json object.
     664             :  * @param osName Key name.
     665             :  * @param pszValue String value.
     666             :  *
     667             :  */
     668       25428 : void CPLJSONObject::Add(const std::string &osName, const char *pszValue)
     669             : {
     670       25428 :     if (nullptr == pszValue)
     671             :     {
     672           2 :         return;
     673             :     }
     674       25426 :     if (m_osKey == INVALID_OBJ_KEY)
     675           0 :         m_osKey.clear();
     676       50852 :     std::string objectName;
     677       50852 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     678       25426 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     679             :                                 object.m_poJsonObject)) == json_type_object)
     680             :     {
     681       25426 :         json_object *poVal = json_object_new_string(pszValue);
     682       25426 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     683             :                                objectName.c_str(), poVal);
     684             :     }
     685             : }
     686             : 
     687             : // defined in ogr/ogrsf_frmts/geojson/ogrgeojsonwriter.cpp
     688             : CPL_C_START
     689             : /* %.XXXg formatting */
     690             : json_object CPL_DLL *
     691             : json_object_new_double_with_significant_figures(double dfVal,
     692             :                                                 int nSignificantFigures);
     693             : CPL_C_END
     694             : 
     695             : /**
     696             :  * Add new key - value pair to json object.
     697             :  * @param osName  Key name.
     698             :  * @param dfValue Double value.
     699             :  *
     700             :  */
     701       10419 : void CPLJSONObject::Add(const std::string &osName, double dfValue)
     702             : {
     703       20838 :     std::string objectName;
     704       10419 :     if (m_osKey == INVALID_OBJ_KEY)
     705           0 :         m_osKey.clear();
     706       20838 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     707       10419 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     708             :                                 object.m_poJsonObject)) == json_type_object)
     709             :     {
     710             :         json_object *poVal =
     711       10419 :             json_object_new_double_with_significant_figures(dfValue, -1);
     712       10419 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     713             :                                objectName.c_str(), poVal);
     714             :     }
     715       10419 : }
     716             : 
     717             : /**
     718             :  * Add new key - value pair to json object.
     719             :  * @param osName  Key name.
     720             :  * @param nValue Integer value.
     721             :  *
     722             :  */
     723       14974 : void CPLJSONObject::Add(const std::string &osName, int nValue)
     724             : {
     725       29948 :     std::string objectName;
     726       14974 :     if (m_osKey == INVALID_OBJ_KEY)
     727           0 :         m_osKey.clear();
     728       29948 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     729       14974 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     730             :                                 object.m_poJsonObject)) == json_type_object)
     731             :     {
     732       14974 :         json_object *poVal = json_object_new_int(nValue);
     733       14974 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     734             :                                objectName.c_str(), poVal);
     735             :     }
     736       14974 : }
     737             : 
     738             : /**
     739             :  * Add new key - value pair to json object.
     740             :  * @param osName  Key name.
     741             :  * @param nValue Long value.
     742             :  *
     743             :  */
     744        5780 : void CPLJSONObject::Add(const std::string &osName, GInt64 nValue)
     745             : {
     746       11560 :     std::string objectName;
     747        5780 :     if (m_osKey == INVALID_OBJ_KEY)
     748           0 :         m_osKey.clear();
     749       11560 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     750        5780 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     751             :                                 object.m_poJsonObject)) == json_type_object)
     752             :     {
     753             :         json_object *poVal =
     754        5780 :             json_object_new_int64(static_cast<int64_t>(nValue));
     755        5780 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     756             :                                objectName.c_str(), poVal);
     757             :     }
     758        5780 : }
     759             : 
     760             : /**
     761             :  * Add new key - value pair to json object.
     762             :  * @param osName  Key name.
     763             :  * @param nValue uint64_t value.
     764             :  *
     765             :  * @since GDAL 3.8
     766             :  */
     767         841 : void CPLJSONObject::Add(const std::string &osName, uint64_t nValue)
     768             : {
     769        1682 :     std::string objectName;
     770         841 :     if (m_osKey == INVALID_OBJ_KEY)
     771           0 :         m_osKey.clear();
     772        1682 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     773         841 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     774             :                                 object.m_poJsonObject)) == json_type_object)
     775             :     {
     776         841 :         json_object *poVal = json_object_new_uint64(nValue);
     777         841 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     778             :                                objectName.c_str(), poVal);
     779             :     }
     780         841 : }
     781             : 
     782             : /**
     783             :  * Add new key - value pair to json object.
     784             :  * @param osName  Key name.
     785             :  * @param oValue   Array value.
     786             :  *
     787             :  */
     788       12755 : void CPLJSONObject::Add(const std::string &osName, const CPLJSONArray &oValue)
     789             : {
     790       25510 :     std::string objectName;
     791       12755 :     if (m_osKey == INVALID_OBJ_KEY)
     792           0 :         m_osKey.clear();
     793       25510 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     794       12755 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     795             :                                 object.m_poJsonObject)) == json_type_object)
     796             :     {
     797       25510 :         json_object_object_add(
     798       12755 :             TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
     799       12755 :             json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
     800             :     }
     801       12755 : }
     802             : 
     803             : /**
     804             :  * Add new key - value pair to json object.
     805             :  * @param osName  Key name.
     806             :  * @param oValue   Json object value.
     807             :  *
     808             :  */
     809       14071 : void CPLJSONObject::Add(const std::string &osName, const CPLJSONObject &oValue)
     810             : {
     811       14071 :     std::string objectName;
     812       14071 :     if (m_osKey == INVALID_OBJ_KEY)
     813           0 :         m_osKey.clear();
     814       14071 :     if (osName.empty())
     815             :     {
     816          40 :         json_object_object_add(
     817          20 :             TO_JSONOBJ(GetInternalHandle()), "",
     818          20 :             json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
     819          20 :         return;
     820             :     }
     821       28102 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     822       14051 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     823             :                                 object.m_poJsonObject)) == json_type_object)
     824             :     {
     825       28102 :         json_object_object_add(
     826       14051 :             TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
     827       14051 :             json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
     828             :     }
     829             : }
     830             : 
     831             : /**
     832             :  * Add new key - value pair to json object.
     833             :  * @param osName  Key name (do not split it on '/')
     834             :  * @param oValue   Json object value.
     835             :  *
     836             :  * @since GDAL 3.2
     837             :  */
     838       13766 : void CPLJSONObject::AddNoSplitName(const std::string &osName,
     839             :                                    const CPLJSONObject &oValue)
     840             : {
     841       13766 :     if (m_osKey == INVALID_OBJ_KEY)
     842           0 :         m_osKey.clear();
     843       27532 :     if (IsValid() &&
     844       13766 :         json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_object)
     845             :     {
     846       27532 :         json_object_object_add(
     847       13766 :             TO_JSONOBJ(GetInternalHandle()), osName.c_str(),
     848       13766 :             json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
     849             :     }
     850       13766 : }
     851             : 
     852             : /**
     853             :  * Add new key - value pair to json object.
     854             :  * @param osName  Key name.
     855             :  * @param bValue   Boolean value.
     856             :  *
     857             :  */
     858       13208 : void CPLJSONObject::Add(const std::string &osName, bool bValue)
     859             : {
     860       26416 :     std::string objectName;
     861       13208 :     if (m_osKey == INVALID_OBJ_KEY)
     862           0 :         m_osKey.clear();
     863       26416 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     864       13208 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     865             :                                 object.m_poJsonObject)) == json_type_object)
     866             :     {
     867       13208 :         json_object *poVal = json_object_new_boolean(bValue);
     868       13208 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     869             :                                objectName.c_str(), poVal);
     870             :     }
     871       13208 : }
     872             : 
     873             : /**
     874             :  * Add new key - null pair to json object.
     875             :  * @param osName  Key name.
     876             :  *
     877             :  */
     878       11680 : void CPLJSONObject::AddNull(const std::string &osName)
     879             : {
     880       23360 :     std::string objectName;
     881       11680 :     if (m_osKey == INVALID_OBJ_KEY)
     882           0 :         m_osKey.clear();
     883       23360 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     884       11680 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     885             :                                 object.m_poJsonObject)) == json_type_object)
     886             :     {
     887       11680 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     888             :                                objectName.c_str(), nullptr);
     889             :     }
     890       11680 : }
     891             : 
     892             : /**
     893             :  * Change value by key.
     894             :  * @param osName  Key name.
     895             :  *
     896             :  */
     897          18 : void CPLJSONObject::SetNull(const std::string &osName)
     898             : {
     899          18 :     Delete(osName);
     900          18 :     AddNull(osName);
     901          18 : }
     902             : 
     903             : /**
     904             :  * Get value by key.
     905             :  * @param  osName Key name.
     906             :  * @return         Json array object.
     907             :  *
     908             :  */
     909      140826 : CPLJSONArray CPLJSONObject::GetArray(const std::string &osName) const
     910             : {
     911      281652 :     std::string objectName;
     912      281652 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     913      140826 :     if (object.IsValid())
     914             :     {
     915      140826 :         json_object *poVal = nullptr;
     916      140826 :         if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
     917      140826 :                                       objectName.c_str(), &poVal))
     918             :         {
     919       77890 :             if (poVal && json_object_get_type(poVal) == json_type_array)
     920             :             {
     921       77847 :                 return CPLJSONArray(objectName, poVal);
     922             :             }
     923             :         }
     924             :     }
     925       62979 :     return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
     926             : }
     927             : 
     928             : /**
     929             :  * Get value by key.
     930             :  * @param  osName Key name.
     931             :  * @return         Json object.
     932             :  *
     933             :  */
     934      876497 : CPLJSONObject CPLJSONObject::GetObj(const std::string &osName) const
     935             : {
     936     1752980 :     std::string objectName;
     937     1752970 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     938      876492 :     if (object.IsValid())
     939             :     {
     940      875450 :         json_object *poVal = nullptr;
     941      875450 :         if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
     942      875471 :                                       objectName.c_str(), &poVal))
     943             :         {
     944      801858 :             return CPLJSONObject(objectName, poVal);
     945             :         }
     946             :     }
     947       74633 :     return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
     948             : }
     949             : 
     950             : /**
     951             :  * Get value by key (without splitting on /).
     952             :  * @param  osName Key name.
     953             :  * @return         Json object.
     954             :  * @since 3.13
     955             :  *
     956             :  */
     957       10361 : CPLJSONObject CPLJSONObject::GetObjNoSplitName(const std::string &osName) const
     958             : {
     959       10361 :     json_object *poVal = nullptr;
     960             : 
     961             :     // Typically for keys that contain / character
     962       10361 :     if (json_object_object_get_ex(TO_JSONOBJ(GetInternalHandle()),
     963       10361 :                                   osName.c_str(), &poVal))
     964             :     {
     965          10 :         return CPLJSONObject(osName, poVal);
     966             :     }
     967       10351 :     return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
     968             : }
     969             : 
     970             : /**
     971             :  * Get value by key.
     972             :  * @param  osName Key name.
     973             :  * @return         Json object.
     974             :  *
     975             :  */
     976      127932 : CPLJSONObject CPLJSONObject::operator[](const std::string &osName) const
     977             : {
     978      127932 :     return GetObj(osName);
     979             : }
     980             : 
     981             : /** Change value by key.
     982             :  *
     983             :  * e.g.: ``oObj["type"] = "MyType"``
     984             :  *
     985             :  * @since 3.12
     986             :  */
     987       29729 : CPLJSONObject CPLJSONObject::operator[](const std::string &osName)
     988             : {
     989       59458 :     auto oObj = GetObj(osName);
     990       29729 :     if (oObj.IsValid())
     991        6846 :         return oObj;
     992       45766 :     CPLJSONObject oClone(*this);
     993       22883 :     oClone.m_osKey = INVALID_OBJ_KEY;
     994       22883 :     oClone.m_osKeyForSet = osName;
     995       22883 :     return oClone;
     996             : }
     997             : 
     998             : /**
     999             :  * Delete json object by key.
    1000             :  * @param  osName Key name.
    1001             :  *
    1002             :  */
    1003       14576 : void CPLJSONObject::Delete(const std::string &osName)
    1004             : {
    1005       29152 :     std::string objectName;
    1006       14576 :     if (m_osKey == INVALID_OBJ_KEY)
    1007        3014 :         m_osKey.clear();
    1008       29152 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
    1009       14576 :     if (object.IsValid())
    1010             :     {
    1011       14576 :         json_object_object_del(TO_JSONOBJ(object.GetInternalHandle()),
    1012             :                                objectName.c_str());
    1013             :     }
    1014       14576 : }
    1015             : 
    1016             : /**
    1017             :  * Delete json object by key (without splitting on /)
    1018             :  * @param  osName Key name.
    1019             :  *
    1020             :  * @since GDAL 3.4
    1021             :  */
    1022         932 : void CPLJSONObject::DeleteNoSplitName(const std::string &osName)
    1023             : {
    1024         932 :     if (m_osKey == INVALID_OBJ_KEY)
    1025           0 :         m_osKey.clear();
    1026         932 :     if (m_poJsonObject)
    1027             :     {
    1028         932 :         json_object_object_del(TO_JSONOBJ(m_poJsonObject), osName.c_str());
    1029             :     }
    1030         932 : }
    1031             : 
    1032             : /**
    1033             :  * Get value by key.
    1034             :  * @param  osName    Key name.
    1035             :  * @param  osDefault Default value.
    1036             :  * @return            String value.
    1037             :  *
    1038             :  */
    1039      330965 : std::string CPLJSONObject::GetString(const std::string &osName,
    1040             :                                      const std::string &osDefault) const
    1041             : {
    1042      330965 :     if (!m_osKeyForSet.empty())
    1043           0 :         return osDefault;
    1044      661912 :     CPLJSONObject object = GetObj(osName);
    1045      330956 :     return object.ToString(osDefault);
    1046             : }
    1047             : 
    1048             : /**
    1049             :  * Get value.
    1050             :  * @param  osDefault Default value.
    1051             :  * @return            String value.
    1052             :  *
    1053             :  */
    1054      510404 : std::string CPLJSONObject::ToString(const std::string &osDefault) const
    1055             : {
    1056      510404 :     if (!m_osKeyForSet.empty())
    1057         252 :         return osDefault;
    1058      510150 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1059             :             json_type_string*/ )
    1060             :     {
    1061             :         const char *pszString =
    1062      489326 :             json_object_get_string(TO_JSONOBJ(m_poJsonObject));
    1063      489324 :         if (nullptr != pszString)
    1064             :         {
    1065      489325 :             return pszString;
    1066             :         }
    1067             :     }
    1068       20823 :     return osDefault;
    1069             : }
    1070             : 
    1071             : /**
    1072             :  * Get value by key.
    1073             :  * @param  osName    Key name.
    1074             :  * @param  dfDefault  Default value.
    1075             :  * @return            Double value.
    1076             :  *
    1077             :  */
    1078       62879 : double CPLJSONObject::GetDouble(const std::string &osName,
    1079             :                                 double dfDefault) const
    1080             : {
    1081       62879 :     if (!m_osKeyForSet.empty())
    1082           0 :         return dfDefault;
    1083      125758 :     CPLJSONObject object = GetObj(osName);
    1084       62879 :     return object.ToDouble(dfDefault);
    1085             : }
    1086             : 
    1087             : /**
    1088             :  * Get value
    1089             :  * @param  dfDefault  Default value.
    1090             :  * @return            Double value.
    1091             :  *
    1092             :  */
    1093      198262 : double CPLJSONObject::ToDouble(double dfDefault) const
    1094             : {
    1095      198262 :     if (!m_osKeyForSet.empty())
    1096           0 :         return dfDefault;
    1097      198262 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1098             :             json_type_double*/ )
    1099      197544 :         return json_object_get_double(TO_JSONOBJ(m_poJsonObject));
    1100         718 :     return dfDefault;
    1101             : }
    1102             : 
    1103             : /**
    1104             :  * Get value by key.
    1105             :  * @param  osName    Key name.
    1106             :  * @param  nDefault   Default value.
    1107             :  * @return            Integer value.
    1108             :  *
    1109             :  */
    1110      251441 : int CPLJSONObject::GetInteger(const std::string &osName, int nDefault) const
    1111             : {
    1112      251441 :     if (!m_osKeyForSet.empty())
    1113           0 :         return nDefault;
    1114      502882 :     CPLJSONObject object = GetObj(osName);
    1115      251441 :     return object.ToInteger(nDefault);
    1116             : }
    1117             : 
    1118             : /**
    1119             :  * Get value.
    1120             :  * @param  nDefault   Default value.
    1121             :  * @return            Integer value.
    1122             :  *
    1123             :  */
    1124      254444 : int CPLJSONObject::ToInteger(int nDefault) const
    1125             : {
    1126      254444 :     if (!m_osKeyForSet.empty())
    1127           0 :         return nDefault;
    1128      254444 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1129             :             json_type_int*/ )
    1130      253474 :         return json_object_get_int(TO_JSONOBJ(m_poJsonObject));
    1131         970 :     return nDefault;
    1132             : }
    1133             : 
    1134             : /**
    1135             :  * Get value by key.
    1136             :  * @param  osName    Key name.
    1137             :  * @param  nDefault   Default value.
    1138             :  * @return            Long value.
    1139             :  *
    1140             :  */
    1141         126 : GInt64 CPLJSONObject::GetLong(const std::string &osName, GInt64 nDefault) const
    1142             : {
    1143         126 :     if (!m_osKeyForSet.empty())
    1144           0 :         return nDefault;
    1145         252 :     CPLJSONObject object = GetObj(osName);
    1146         126 :     return object.ToLong(nDefault);
    1147             : }
    1148             : 
    1149             : /**
    1150             :  * Get value.
    1151             :  * @param  nDefault   Default value.
    1152             :  * @return            Long value.
    1153             :  *
    1154             :  */
    1155        9202 : GInt64 CPLJSONObject::ToLong(GInt64 nDefault) const
    1156             : {
    1157        9202 :     if (!m_osKeyForSet.empty())
    1158           0 :         return nDefault;
    1159        9202 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1160             :             json_type_int*/ )
    1161             :         return static_cast<GInt64>(
    1162        9129 :             json_object_get_int64(TO_JSONOBJ(m_poJsonObject)));
    1163          73 :     return nDefault;
    1164             : }
    1165             : 
    1166             : /**
    1167             :  * Get value by key.
    1168             :  * @param  osName    Key name.
    1169             :  * @param  nDefault   Default value.
    1170             :  * @return            uint64_t value.
    1171             :  *
    1172             :  */
    1173           0 : uint64_t CPLJSONObject::GetUInt64(const std::string &osName,
    1174             :                                   uint64_t nDefault) const
    1175             : {
    1176           0 :     if (!m_osKeyForSet.empty())
    1177           0 :         return nDefault;
    1178           0 :     CPLJSONObject object = GetObj(osName);
    1179           0 :     return object.ToUInt64(nDefault);
    1180             : }
    1181             : 
    1182             : /**
    1183             :  * Get value.
    1184             :  * @param  nDefault   Default value.
    1185             :  * @return            uint64_t value.
    1186             :  *
    1187             :  */
    1188           6 : uint64_t CPLJSONObject::ToUInt64(uint64_t nDefault) const
    1189             : {
    1190           6 :     if (!m_osKeyForSet.empty())
    1191           0 :         return nDefault;
    1192           6 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1193             :             json_type_int*/ )
    1194             :     {
    1195             : #if (!defined(JSON_C_VERSION_NUM)) || (JSON_C_VERSION_NUM < JSON_C_VER_014)
    1196             :         // We can't do much better without json_object_get_uint64
    1197             :         const double v = json_object_get_double(TO_JSONOBJ(m_poJsonObject));
    1198             :         if (v > 0)
    1199             :         {
    1200             :             return static_cast<uint64_t>(
    1201             :                 json_object_get_int64(TO_JSONOBJ(m_poJsonObject)));
    1202             :         }
    1203             : #else
    1204           6 :         return json_object_get_uint64(TO_JSONOBJ(m_poJsonObject));
    1205             : #endif
    1206             :     }
    1207           0 :     return nDefault;
    1208             : }
    1209             : 
    1210             : /**
    1211             :  * Get value by key.
    1212             :  * @param  osName    Key name.
    1213             :  * @param  bDefault   Default value.
    1214             :  * @return            Boolean value.
    1215             :  *
    1216             :  */
    1217        5184 : bool CPLJSONObject::GetBool(const std::string &osName, bool bDefault) const
    1218             : {
    1219        5184 :     if (!m_osKeyForSet.empty())
    1220           0 :         return bDefault;
    1221       10368 :     CPLJSONObject object = GetObj(osName);
    1222        5184 :     return object.ToBool(bDefault);
    1223             : }
    1224             : 
    1225             : /**
    1226             :  * \brief Get json object children.
    1227             :  *
    1228             :  * This function is useful when keys is not know and need to
    1229             :  * iterate over json object items and get keys and values.
    1230             :  *
    1231             :  * @return Array of CPLJSONObject class instance.
    1232             :  *
    1233             :  */
    1234       23828 : std::vector<CPLJSONObject> CPLJSONObject::GetChildren() const
    1235             : {
    1236       23828 :     std::vector<CPLJSONObject> aoChildren;
    1237       23819 :     if (!m_osKeyForSet.empty())
    1238           0 :         return aoChildren;
    1239       47636 :     if (nullptr == m_poJsonObject ||
    1240       23819 :         json_object_get_type(TO_JSONOBJ(m_poJsonObject)) != json_type_object)
    1241             :     {
    1242           1 :         return aoChildren;
    1243             :     }
    1244             : 
    1245             :     json_object_iter it;
    1246       23816 :     it.key = nullptr;
    1247       23816 :     it.val = nullptr;
    1248       23816 :     it.entry = nullptr;
    1249             :     // cppcheck-suppress cstyleCast
    1250       96003 :     json_object_object_foreachC(TO_JSONOBJ(m_poJsonObject), it)
    1251             :     {
    1252       72193 :         aoChildren.push_back(CPLJSONObject(it.key, it.val));
    1253             :     }
    1254             : 
    1255       23815 :     return aoChildren;
    1256             : }
    1257             : 
    1258             : /**
    1259             :  * Get value.
    1260             :  * @param  bDefault   Default value.
    1261             :  * @return            Boolean value.
    1262             :  *
    1263             :  */
    1264        5731 : bool CPLJSONObject::ToBool(bool bDefault) const
    1265             : {
    1266        5731 :     if (!m_osKeyForSet.empty())
    1267           0 :         return bDefault;
    1268        5731 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1269             :             json_type_boolean*/ )
    1270        4948 :         return json_object_get_boolean(TO_JSONOBJ(m_poJsonObject)) == 1;
    1271         783 :     return bDefault;
    1272             : }
    1273             : 
    1274             : /**
    1275             :  * Get value.
    1276             :  * @return            Array
    1277             :  *
    1278             :  */
    1279       28500 : CPLJSONArray CPLJSONObject::ToArray() const
    1280             : {
    1281       55753 :     if (m_osKeyForSet.empty() && m_poJsonObject &&
    1282       27253 :         json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_array)
    1283       27248 :         return CPLJSONArray("", TO_JSONOBJ(m_poJsonObject));
    1284        1252 :     return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
    1285             : }
    1286             : 
    1287             : /**
    1288             :  * Stringify object to json format.
    1289             :  * @param  eFormat Format type,
    1290             :  * @return         A string in JSON format.
    1291             :  *
    1292             :  */
    1293       29205 : std::string CPLJSONObject::Format(PrettyFormat eFormat) const
    1294             : {
    1295       29205 :     if (m_poJsonObject)
    1296             :     {
    1297       29205 :         const char *pszFormatString = nullptr;
    1298       29205 :         switch (eFormat)
    1299             :         {
    1300           1 :             case PrettyFormat::Spaced:
    1301           2 :                 pszFormatString = json_object_to_json_string_ext(
    1302           1 :                     TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_SPACED);
    1303           1 :                 break;
    1304         322 :             case PrettyFormat::Pretty:
    1305         644 :                 pszFormatString = json_object_to_json_string_ext(
    1306         322 :                     TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PRETTY);
    1307         322 :                 break;
    1308       28882 :             default:
    1309       28882 :                 pszFormatString = json_object_to_json_string_ext(
    1310       28882 :                     TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PLAIN);
    1311             :         }
    1312       29205 :         if (nullptr != pszFormatString)
    1313             :         {
    1314       29205 :             return pszFormatString;
    1315             :         }
    1316             :     }
    1317           0 :     return "";
    1318             : }
    1319             : 
    1320             : /*! @cond Doxygen_Suppress */
    1321     1171830 : CPLJSONObject CPLJSONObject::GetObjectByPath(const std::string &osPath,
    1322             :                                              std::string &osName) const
    1323             : {
    1324     1171830 :     json_object *poVal = nullptr;
    1325             : 
    1326             :     // Typically for keys that contain / character
    1327     1171830 :     if (json_object_object_get_ex(TO_JSONOBJ(GetInternalHandle()),
    1328     1171810 :                                   osPath.c_str(), &poVal))
    1329             :     {
    1330      880230 :         osName = osPath;
    1331      880236 :         return *this;
    1332             :     }
    1333             : 
    1334             :     CPLStringList pathPortions(
    1335      583168 :         CSLTokenizeString2(osPath.c_str(), JSON_PATH_DELIMITER, 0));
    1336      291584 :     int portionsCount = pathPortions.size();
    1337      291584 :     if (portionsCount > 100)
    1338             :     {
    1339           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Too many components in path");
    1340           0 :         return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
    1341             :     }
    1342      291584 :     if (0 == portionsCount)
    1343           0 :         return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
    1344      583168 :     CPLJSONObject object = *this;
    1345      293753 :     for (int i = 0; i < portionsCount - 1; ++i)
    1346             :     {
    1347             :         // TODO: check array index in path - i.e.
    1348             :         // settings/catalog/root/id:1/name if EQUALN(pathPortions[i+1], "id:",
    1349             :         // 3) -> getArray
    1350        2169 :         if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
    1351        4338 :                                       pathPortions[i], &poVal))
    1352             :         {
    1353        1334 :             object = CPLJSONObject(pathPortions[i], poVal);
    1354             :         }
    1355             :         else
    1356             :         {
    1357         835 :             if (json_object_get_type(TO_JSONOBJ(object.m_poJsonObject)) !=
    1358             :                 json_type_object)
    1359             :             {
    1360           0 :                 return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
    1361             :             }
    1362         835 :             object = CPLJSONObject(pathPortions[i], object);
    1363             :         }
    1364             :     }
    1365             : 
    1366             :     //    // Check if such object already  exists
    1367             :     //    if(json_object_object_get_ex(object.m_jsonObject,
    1368             :     //                                 pathPortions[portionsCount - 1], &poVal))
    1369             :     //        return JSONObject(nullptr);
    1370             :     //
    1371      291584 :     osName = pathPortions[portionsCount - 1];
    1372      291584 :     return object;
    1373             : }
    1374             : 
    1375             : /*! @endcond */
    1376             : 
    1377             : /**
    1378             :  * Get json object type.
    1379             :  * @return Json object type.
    1380             :  *
    1381             :  */
    1382      191868 : CPLJSONObject::Type CPLJSONObject::GetType() const
    1383             : {
    1384      191868 :     if (!m_osKeyForSet.empty())
    1385       13541 :         return CPLJSONObject::Type::Unknown;
    1386             : 
    1387      178317 :     if (nullptr == m_poJsonObject)
    1388             :     {
    1389       12747 :         if (m_osKey == INVALID_OBJ_KEY)
    1390        8341 :             return CPLJSONObject::Type::Unknown;
    1391        4406 :         return CPLJSONObject::Type::Null;
    1392             :     }
    1393      165570 :     auto jsonObj(TO_JSONOBJ(m_poJsonObject));
    1394      165570 :     switch (json_object_get_type(jsonObj))
    1395             :     {
    1396         555 :         case json_type_boolean:
    1397         555 :             return CPLJSONObject::Type::Boolean;
    1398        4848 :         case json_type_double:
    1399        4848 :             return CPLJSONObject::Type::Double;
    1400       43649 :         case json_type_int:
    1401             :         {
    1402       43649 :             if (CPL_INT64_FITS_ON_INT32(json_object_get_int64(jsonObj)))
    1403       43453 :                 return CPLJSONObject::Type::Integer;
    1404             :             else
    1405         201 :                 return CPLJSONObject::Type::Long;
    1406             :         }
    1407       34877 :         case json_type_object:
    1408       34877 :             return CPLJSONObject::Type::Object;
    1409       20529 :         case json_type_array:
    1410       20529 :             return CPLJSONObject::Type::Array;
    1411       61116 :         case json_type_string:
    1412       61116 :             return CPLJSONObject::Type::String;
    1413           0 :         default:
    1414           0 :             break;
    1415             :     }
    1416           0 :     return CPLJSONObject::Type::Unknown;
    1417             : }
    1418             : 
    1419             : /**
    1420             :  * Check if json object valid.
    1421             :  * @return true if json object valid.
    1422             :  *
    1423             :  */
    1424     1446000 : bool CPLJSONObject::IsValid() const
    1425             : {
    1426     1446000 :     return m_osKeyForSet.empty() && m_osKey != INVALID_OBJ_KEY;
    1427             : }
    1428             : 
    1429             : /**
    1430             :  * Decrement reference counter and make pointer NULL.
    1431             :  * A json object will become invalid.
    1432             :  *
    1433             :  */
    1434       47908 : void CPLJSONObject::Deinit()
    1435             : {
    1436       47908 :     if (m_poJsonObject)
    1437             :     {
    1438       45580 :         json_object_put(TO_JSONOBJ(m_poJsonObject));
    1439       45570 :         m_poJsonObject = nullptr;
    1440             :     }
    1441       47898 :     m_osKey = INVALID_OBJ_KEY;
    1442       47900 : }
    1443             : 
    1444             : //------------------------------------------------------------------------------
    1445             : // JSONArray
    1446             : //------------------------------------------------------------------------------
    1447             : /*! @cond Doxygen_Suppress */
    1448       49413 : CPLJSONArray::CPLJSONArray()
    1449             : {
    1450       49413 :     json_object_put(TO_JSONOBJ(m_poJsonObject));
    1451       49413 :     m_poJsonObject = json_object_new_array();
    1452       49413 : }
    1453             : 
    1454           1 : CPLJSONArray::CPLJSONArray(const std::string &osName)
    1455           1 :     : CPLJSONObject(osName, json_object_new_array())
    1456             : {
    1457           1 :     json_object_put(TO_JSONOBJ(m_poJsonObject));
    1458           1 : }
    1459             : 
    1460      172840 : CPLJSONArray::CPLJSONArray(const std::string &osName, JSONObjectH poJsonObject)
    1461      172840 :     : CPLJSONObject(osName, poJsonObject)
    1462             : {
    1463      172840 : }
    1464             : 
    1465          12 : CPLJSONArray::CPLJSONArray(const CPLJSONObject &other) : CPLJSONObject(other)
    1466             : {
    1467          12 : }
    1468             : 
    1469             : /*! @endcond */
    1470             : 
    1471             : /**
    1472             :  * Get array size.
    1473             :  * @return Array size.
    1474             :  *
    1475             :  */
    1476      412631 : int CPLJSONArray::Size() const
    1477             : {
    1478      412631 :     if (m_poJsonObject)
    1479             :         return static_cast<int>(
    1480      410090 :             json_object_array_length(TO_JSONOBJ(m_poJsonObject)));
    1481        2541 :     return 0;
    1482             : }
    1483             : 
    1484             : /**
    1485             :  * Add null object to array.
    1486             :  *
    1487             :  * @since GDAL 3.8
    1488             :  */
    1489        2459 : void CPLJSONArray::AddNull()
    1490             : {
    1491        2459 :     if (m_poJsonObject)
    1492        2459 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject), nullptr);
    1493        2459 : }
    1494             : 
    1495             : /**
    1496             :  * Add json object to array.
    1497             :  * @param oValue Json array.
    1498             :  *
    1499             :  */
    1500       13292 : void CPLJSONArray::Add(const CPLJSONObject &oValue)
    1501             : {
    1502       13292 :     if (m_poJsonObject && oValue.m_poJsonObject)
    1503       26584 :         json_object_array_add(
    1504       13292 :             TO_JSONOBJ(m_poJsonObject),
    1505       13292 :             json_object_get(TO_JSONOBJ(oValue.m_poJsonObject)));
    1506       13292 : }
    1507             : 
    1508             : /**
    1509             :  * Add value to array
    1510             :  * @param osValue Value to add.
    1511             :  *
    1512             :  */
    1513       12938 : void CPLJSONArray::Add(const std::string &osValue)
    1514             : {
    1515       12938 :     if (m_poJsonObject)
    1516       12938 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1517             :                               json_object_new_string(osValue.c_str()));
    1518       12938 : }
    1519             : 
    1520             : /**
    1521             :  * Add value to array
    1522             :  * @param svValue Value to add.
    1523             :  * @since 3.13
    1524             :  *
    1525             :  */
    1526          17 : void CPLJSONArray::Add(std::string_view svValue)
    1527             : {
    1528          17 :     if (svValue.size() > static_cast<size_t>(INT_MAX - 1))
    1529             :     {
    1530           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Too long string view");
    1531           0 :         return;
    1532             :     }
    1533          17 :     if (m_poJsonObject)
    1534             :     {
    1535          17 :         json_object_array_add(
    1536          17 :             TO_JSONOBJ(m_poJsonObject),
    1537             :             json_object_new_string_len(svValue.data(),
    1538          17 :                                        static_cast<int>(svValue.size())));
    1539             :     }
    1540             : }
    1541             : 
    1542             : /**
    1543             :  * Add value to array
    1544             :  * @param pszValue Value to add.
    1545             :  *
    1546             :  */
    1547        6830 : void CPLJSONArray::Add(const char *pszValue)
    1548             : {
    1549        6830 :     if (nullptr == pszValue)
    1550           0 :         return;
    1551        6830 :     if (m_poJsonObject)
    1552        6830 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1553             :                               json_object_new_string(pszValue));
    1554             : }
    1555             : 
    1556             : /**
    1557             :  * Add value to array
    1558             :  * @param dfValue Value to add.
    1559             :  *
    1560             :  */
    1561        4743 : void CPLJSONArray::Add(double dfValue)
    1562             : {
    1563        4743 :     if (m_poJsonObject)
    1564        4743 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1565             :                               json_object_new_double(dfValue));
    1566        4743 : }
    1567             : 
    1568             : /**
    1569             :  * Add value to array
    1570             :  * @param nValue Value to add.
    1571             :  *
    1572             :  */
    1573         767 : void CPLJSONArray::Add(int nValue)
    1574             : {
    1575         767 :     if (m_poJsonObject)
    1576         767 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1577             :                               json_object_new_int(nValue));
    1578         767 : }
    1579             : 
    1580             : /**
    1581             :  * Add value to array
    1582             :  * @param nValue Value to add.
    1583             :  *
    1584             :  */
    1585        2347 : void CPLJSONArray::Add(GInt64 nValue)
    1586             : {
    1587        2347 :     if (m_poJsonObject)
    1588        2347 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1589             :                               json_object_new_int64(nValue));
    1590        2347 : }
    1591             : 
    1592             : /**
    1593             :  * Add value to array
    1594             :  * @param nValue Value to add.
    1595             :  *
    1596             :  * @since GDAL 3.8
    1597             :  */
    1598          91 : void CPLJSONArray::Add(uint64_t nValue)
    1599             : {
    1600          91 :     if (m_poJsonObject)
    1601             :     {
    1602          91 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1603             :                               json_object_new_uint64(nValue));
    1604             :     }
    1605          91 : }
    1606             : 
    1607             : /**
    1608             :  * Add value to array
    1609             :  * @param bValue Value to add.
    1610             :  *
    1611             :  */
    1612          38 : void CPLJSONArray::Add(bool bValue)
    1613             : {
    1614          38 :     if (m_poJsonObject)
    1615          38 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1616             :                               json_object_new_boolean(bValue));
    1617          38 : }
    1618             : 
    1619             : /**
    1620             :  * Get array item by index.
    1621             :  * @param  nIndex Item index.
    1622             :  * @return        Json object.
    1623             :  *
    1624             :  */
    1625        3568 : CPLJSONObject CPLJSONArray::operator[](int nIndex)
    1626             : {
    1627             :     return CPLJSONObject(
    1628             :         CPLSPrintf("id:%d", nIndex),
    1629        3568 :         json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
    1630             : }
    1631             : 
    1632             : /**
    1633             :  * Get array const item by index.
    1634             :  * @param  nIndex Item index.
    1635             :  * @return        Json object.
    1636             :  *
    1637             :  */
    1638      543461 : const CPLJSONObject CPLJSONArray::operator[](int nIndex) const
    1639             : {
    1640             :     return CPLJSONObject(
    1641             :         CPLSPrintf("id:%d", nIndex),
    1642      543461 :         json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
    1643             : }
    1644             : 
    1645             : /**
    1646             :  * Get array item by index.
    1647             :  * @param  nIndex Item index.
    1648             :  * @return        Json object.
    1649             :  *
    1650             :  */
    1651           0 : CPLJSONObject CPLJSONArray::operator[](size_t nIndex)
    1652             : {
    1653             :     return CPLJSONObject(CPLSPrintf("id:%d", static_cast<int>(nIndex)),
    1654           0 :                          json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject),
    1655           0 :                                                    static_cast<int>(nIndex)));
    1656             : }
    1657             : 
    1658             : /**
    1659             :  * Get array const item by index.
    1660             :  * @param  nIndex Item index.
    1661             :  * @return        Json object.
    1662             :  *
    1663             :  */
    1664          34 : const CPLJSONObject CPLJSONArray::operator[](size_t nIndex) const
    1665             : {
    1666             :     return CPLJSONObject(CPLSPrintf("id:%d", static_cast<int>(nIndex)),
    1667          34 :                          json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject),
    1668          34 :                                                    static_cast<int>(nIndex)));
    1669             : }
    1670             : 
    1671             : /************************************************************************/
    1672             : /*                        CPLParseKeyValueJson()                        */
    1673             : /************************************************************************/
    1674             : 
    1675             : /** Return a string list of key/value pairs extracted from a JSON doc.
    1676             : 
    1677             :     We are expecting simple documents with key:value pairs, like the
    1678             :     following with no hierarchy or complex structure.
    1679             :     \verbatim
    1680             :     {
    1681             :       "Code" : "Success",
    1682             :       "LastUpdated" : "2017-07-03T16:20:17Z",
    1683             :       "Type" : "AWS-HMAC",
    1684             :       "AccessKeyId" : "bla",
    1685             :       "SecretAccessKey" : "bla",
    1686             :       "Token" : "bla",
    1687             :       "Expiration" : "2017-07-03T22:42:58Z"
    1688             :     }
    1689             :     \endverbatim
    1690             :     @since GDAL 3.7
    1691             :  */
    1692          64 : CPLStringList CPLParseKeyValueJson(const char *pszJson)
    1693             : {
    1694         128 :     CPLJSONDocument oDoc;
    1695          64 :     CPLStringList oNameValue;
    1696          64 :     if (pszJson != nullptr && oDoc.LoadMemory(pszJson))
    1697             :     {
    1698         211 :         for (const auto &obj : oDoc.GetRoot().GetChildren())
    1699             :         {
    1700         154 :             const auto eType = obj.GetType();
    1701         154 :             if (eType == CPLJSONObject::Type::String ||
    1702           0 :                 eType == CPLJSONObject::Type::Integer ||
    1703             :                 eType == CPLJSONObject::Type::Double)
    1704             :             {
    1705         308 :                 oNameValue.SetNameValue(obj.GetName().c_str(),
    1706         462 :                                         obj.ToString().c_str());
    1707             :             }
    1708             :         }
    1709             :     }
    1710         128 :     return oNameValue;
    1711             : }

Generated by: LCOV version 1.14