LCOV - code coverage report
Current view: top level - port - cpl_json.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 553 602 91.9 %
Date: 2025-05-24 03:54:53 Functions: 91 92 98.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Project:  Common Portability Library
       3             :  * Purpose:  Function wrapper for libjson-c access.
       4             :  * Author:   Dmitry Baryshnikov, dmitry.baryshnikov@nextgis.com
       5             :  *
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2017-2018 NextGIS, <info@nextgis.com>
       8             :  *
       9             :  * 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       15519 : CPLJSONDocument::CPLJSONDocument() : m_poRootJsonObject(nullptr)
      59             : {
      60       15519 : }
      61             : 
      62       31052 : CPLJSONDocument::~CPLJSONDocument()
      63             : {
      64       15526 :     if (m_poRootJsonObject)
      65       11425 :         json_object_put(TO_JSONOBJ(m_poRootJsonObject));
      66       15526 : }
      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         118 : CPLJSONDocument &CPLJSONDocument::operator=(CPLJSONDocument &&other)
      92             : {
      93         118 :     if (this == &other)
      94           0 :         return *this;
      95             : 
      96         118 :     if (m_poRootJsonObject)
      97          21 :         json_object_put(TO_JSONOBJ(m_poRootJsonObject));
      98         118 :     m_poRootJsonObject = other.m_poRootJsonObject;
      99         118 :     other.m_poRootJsonObject = nullptr;
     100             : 
     101         118 :     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        1270 : bool CPLJSONDocument::Save(const std::string &osPath) const
     115             : {
     116        1270 :     VSILFILE *fp = VSIFOpenL(osPath.c_str(), "wt");
     117        1270 :     if (nullptr == fp)
     118             :     {
     119           2 :         CPLError(CE_Failure, CPLE_NoWriteAccess, "Open file %s to write failed",
     120             :                  osPath.c_str());
     121           2 :         return false;
     122             :     }
     123             : 
     124        2536 :     const char *pabyData = json_object_to_json_string_ext(
     125        1268 :         TO_JSONOBJ(m_poRootJsonObject), JSON_C_TO_STRING_PRETTY);
     126        1268 :     VSIFWriteL(pabyData, 1, strlen(pabyData), fp);
     127             : 
     128        1268 :     VSIFCloseL(fp);
     129             : 
     130        1268 :     return true;
     131             : }
     132             : 
     133             : /**
     134             :  * Return the json document as a serialized string.
     135             :  * @return         serialized document.
     136             :  *
     137             :  * @since GDAL 2.3
     138             :  */
     139        1945 : std::string CPLJSONDocument::SaveAsString() const
     140             : {
     141        1945 :     return json_object_to_json_string_ext(TO_JSONOBJ(m_poRootJsonObject),
     142        1945 :                                           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       17413 : CPLJSONObject CPLJSONDocument::GetRoot()
     163             : {
     164       17413 :     if (nullptr == m_poRootJsonObject)
     165             :     {
     166        1313 :         m_poRootJsonObject = json_object_new_object();
     167             :     }
     168             : 
     169       17413 :     if (json_object_get_type(TO_JSONOBJ(m_poRootJsonObject)) == json_type_array)
     170             :     {
     171         640 :         return CPLJSONArray("", m_poRootJsonObject);
     172             :     }
     173             :     else
     174             :     {
     175       17093 :         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        2070 : void CPLJSONDocument::SetRoot(const CPLJSONObject &oRoot)
     186             : {
     187        2070 :     if (m_poRootJsonObject)
     188           0 :         json_object_put(TO_JSONOBJ(m_poRootJsonObject));
     189        2070 :     m_poRootJsonObject = json_object_get(TO_JSONOBJ(oRoot.m_poJsonObject));
     190        2070 : }
     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        5680 : bool CPLJSONDocument::Load(const std::string &osPath)
     201             : {
     202        5680 :     GByte *pabyOut = nullptr;
     203        5680 :     vsi_l_offset nSize = 0;
     204             : 
     205        5680 :     GIntBig nMaxSize = 0;
     206        5680 :     if (CPLParseMemorySize(CPLGetConfigOption("CPL_JSON_MAX_SIZE", "100MB"),
     207       11360 :                            &nMaxSize, nullptr) != CE_None ||
     208        5680 :         nMaxSize <= 0)
     209           0 :         return false;
     210             : 
     211        5680 :     if (!VSIIngestFile(nullptr, osPath.c_str(), &pabyOut, &nSize, nMaxSize))
     212             :     {
     213         809 :         CPLError(CE_Failure, CPLE_FileIO, "Load json file %s failed",
     214             :                  osPath.c_str());
     215         809 :         return false;
     216             :     }
     217             : 
     218        4871 :     bool bResult = LoadMemory(pabyOut, static_cast<int>(nSize));
     219        4871 :     VSIFree(pabyOut);
     220        4871 :     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        9637 : bool CPLJSONDocument::LoadMemory(const GByte *pabyData, int nLength)
     233             : {
     234        9637 :     if (nullptr == pabyData)
     235             :     {
     236           1 :         return false;
     237             :     }
     238             : 
     239        9636 :     if (m_poRootJsonObject)
     240        1554 :         json_object_put(TO_JSONOBJ(m_poRootJsonObject));
     241             : 
     242        9636 :     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        9631 :     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        9628 :     json_tokener *jstok = json_tokener_new();
     257        9628 :     m_poRootJsonObject = json_tokener_parse_ex(
     258             :         jstok, reinterpret_cast<const char *>(pabyData), nLength);
     259        9628 :     bool bParsed = jstok->err == json_tokener_success;
     260        9628 :     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        9605 :     json_tokener_free(jstok);
     269        9605 :     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        4665 : bool CPLJSONDocument::LoadMemory(const std::string &osStr)
     281             : {
     282        4665 :     if (osStr.empty())
     283           3 :         return false;
     284        4662 :     return LoadMemory(reinterpret_cast<const GByte *>(osStr.data()),
     285        9324 :                       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      140028 : CPLJSONObject::CPLJSONObject() : m_poJsonObject(json_object_new_object())
     473             : {
     474      140028 : }
     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         817 : CPLJSONObject::CPLJSONObject(const std::string &osName,
     516         817 :                              const CPLJSONObject &oParent)
     517         817 :     : m_poJsonObject(json_object_get(json_object_new_object())), m_osKey(osName)
     518             : {
     519         817 :     json_object_object_add(TO_JSONOBJ(oParent.m_poJsonObject), osName.c_str(),
     520         817 :                            TO_JSONOBJ(m_poJsonObject));
     521         817 : }
     522             : 
     523     1263060 : CPLJSONObject::CPLJSONObject(const std::string &osName,
     524     1263060 :                              JSONObjectH poJsonObject)
     525     1263060 :     : m_poJsonObject(json_object_get(TO_JSONOBJ(poJsonObject))), m_osKey(osName)
     526             : {
     527     1263060 : }
     528             : 
     529         792 : CPLJSONObject CPLJSONObject::Clone() const
     530             : {
     531         792 :     CPLJSONObject oRet;
     532         792 :     if (IsValid())
     533             :     {
     534        1566 :         CPLJSONDocument oTmpDoc;
     535         783 :         oTmpDoc.SetRoot(*this);
     536         783 :         std::string osStr = oTmpDoc.SaveAsString();
     537         783 :         CPL_IGNORE_RET_VAL(oTmpDoc.LoadMemory(osStr));
     538         783 :         oRet = oTmpDoc.GetRoot();
     539             :     }
     540         792 :     return oRet;
     541             : }
     542             : 
     543     2602280 : CPLJSONObject::~CPLJSONObject()
     544             : {
     545             :     // Should delete m_poJsonObject only if CPLJSONObject has no parent
     546     2602280 :     if (m_poJsonObject)
     547             :     {
     548     2219900 :         json_object_put(TO_JSONOBJ(m_poJsonObject));
     549     2219900 :         m_poJsonObject = nullptr;
     550             :     }
     551     2602280 : }
     552             : 
     553      929814 : CPLJSONObject::CPLJSONObject(const CPLJSONObject &other)
     554      929814 :     : m_poJsonObject(json_object_get(TO_JSONOBJ(other.m_poJsonObject))),
     555      929814 :       m_osKey(other.m_osKey)
     556             : {
     557      929814 : }
     558             : 
     559      268549 : CPLJSONObject::CPLJSONObject(CPLJSONObject &&other)
     560      268549 :     : m_poJsonObject(other.m_poJsonObject), m_osKey(std::move(other.m_osKey))
     561             : {
     562      268549 :     other.m_poJsonObject = nullptr;
     563      268549 : }
     564             : 
     565       93860 : CPLJSONObject &CPLJSONObject::operator=(const CPLJSONObject &other)
     566             : {
     567       93860 :     if (this == &other)
     568           1 :         return *this;
     569             : 
     570       93859 :     m_osKey = other.m_osKey;
     571       93859 :     if (m_poJsonObject)
     572       93053 :         json_object_put(TO_JSONOBJ(m_poJsonObject));
     573       93859 :     m_poJsonObject = json_object_get(TO_JSONOBJ(other.m_poJsonObject));
     574       93859 :     return *this;
     575             : }
     576             : 
     577       12236 : CPLJSONObject &CPLJSONObject::operator=(CPLJSONObject &&other)
     578             : {
     579       12236 :     if (this == &other)
     580           0 :         return *this;
     581             : 
     582       12236 :     m_osKey = std::move(other.m_osKey);
     583       12236 :     if (m_poJsonObject)
     584        7041 :         json_object_put(TO_JSONOBJ(m_poJsonObject));
     585       12236 :     m_poJsonObject = other.m_poJsonObject;
     586       12236 :     other.m_poJsonObject = nullptr;
     587       12236 :     return *this;
     588             : }
     589             : 
     590             : /*! @endcond */
     591             : 
     592             : /**
     593             :  * Add new key - value pair to json object.
     594             :  * @param osName Key name.
     595             :  * @param osValue String value.
     596             :  *
     597             :  * @since GDAL 2.3
     598             :  */
     599       21145 : void CPLJSONObject::Add(const std::string &osName, const std::string &osValue)
     600             : {
     601       42290 :     std::string objectName;
     602       21145 :     if (m_osKey == INVALID_OBJ_KEY)
     603           0 :         m_osKey.clear();
     604       42290 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     605       21145 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     606             :                                 object.m_poJsonObject)) == json_type_object)
     607             :     {
     608       21145 :         json_object *poVal = json_object_new_string(osValue.c_str());
     609       21145 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     610             :                                objectName.c_str(), poVal);
     611             :     }
     612       21145 : }
     613             : 
     614             : /**
     615             :  * Add new key - value pair to json object.
     616             :  * @param osName Key name.
     617             :  * @param pszValue String value.
     618             :  *
     619             :  * @since GDAL 2.3
     620             :  */
     621       17002 : void CPLJSONObject::Add(const std::string &osName, const char *pszValue)
     622             : {
     623       17002 :     if (nullptr == pszValue)
     624             :     {
     625           1 :         return;
     626             :     }
     627       17001 :     if (m_osKey == INVALID_OBJ_KEY)
     628           0 :         m_osKey.clear();
     629       34002 :     std::string objectName;
     630       34002 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     631       17001 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     632             :                                 object.m_poJsonObject)) == json_type_object)
     633             :     {
     634       17001 :         json_object *poVal = json_object_new_string(pszValue);
     635       17001 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     636             :                                objectName.c_str(), poVal);
     637             :     }
     638             : }
     639             : 
     640             : // defined in ogr/ogrsf_frmts/geojson/ogrgeojsonwriter.cpp
     641             : CPL_C_START
     642             : /* %.XXXg formatting */
     643             : json_object CPL_DLL *
     644             : json_object_new_double_with_significant_figures(double dfVal,
     645             :                                                 int nSignificantFigures);
     646             : CPL_C_END
     647             : 
     648             : /**
     649             :  * Add new key - value pair to json object.
     650             :  * @param osName  Key name.
     651             :  * @param dfValue Double value.
     652             :  *
     653             :  * @since GDAL 2.3
     654             :  */
     655       11148 : void CPLJSONObject::Add(const std::string &osName, double dfValue)
     656             : {
     657       22296 :     std::string objectName;
     658       11148 :     if (m_osKey == INVALID_OBJ_KEY)
     659           0 :         m_osKey.clear();
     660       22296 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     661       11148 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     662             :                                 object.m_poJsonObject)) == json_type_object)
     663             :     {
     664             :         json_object *poVal =
     665       11148 :             json_object_new_double_with_significant_figures(dfValue, -1);
     666       11148 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     667             :                                objectName.c_str(), poVal);
     668             :     }
     669       11148 : }
     670             : 
     671             : /**
     672             :  * Add new key - value pair to json object.
     673             :  * @param osName  Key name.
     674             :  * @param nValue Integer value.
     675             :  *
     676             :  * @since GDAL 2.3
     677             :  */
     678       15301 : void CPLJSONObject::Add(const std::string &osName, int nValue)
     679             : {
     680       30602 :     std::string objectName;
     681       15301 :     if (m_osKey == INVALID_OBJ_KEY)
     682           0 :         m_osKey.clear();
     683       30602 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     684       15301 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     685             :                                 object.m_poJsonObject)) == json_type_object)
     686             :     {
     687       15301 :         json_object *poVal = json_object_new_int(nValue);
     688       15301 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     689             :                                objectName.c_str(), poVal);
     690             :     }
     691       15301 : }
     692             : 
     693             : /**
     694             :  * Add new key - value pair to json object.
     695             :  * @param osName  Key name.
     696             :  * @param nValue Long value.
     697             :  *
     698             :  * @since GDAL 2.3
     699             :  */
     700        5646 : void CPLJSONObject::Add(const std::string &osName, GInt64 nValue)
     701             : {
     702       11292 :     std::string objectName;
     703        5646 :     if (m_osKey == INVALID_OBJ_KEY)
     704           0 :         m_osKey.clear();
     705       11292 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     706        5646 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     707             :                                 object.m_poJsonObject)) == json_type_object)
     708             :     {
     709             :         json_object *poVal =
     710        5646 :             json_object_new_int64(static_cast<int64_t>(nValue));
     711        5646 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     712             :                                objectName.c_str(), poVal);
     713             :     }
     714        5646 : }
     715             : 
     716             : /**
     717             :  * Add new key - value pair to json object.
     718             :  * @param osName  Key name.
     719             :  * @param nValue uint64_t value.
     720             :  *
     721             :  * @since GDAL 3.8
     722             :  */
     723         795 : void CPLJSONObject::Add(const std::string &osName, uint64_t nValue)
     724             : {
     725        1590 :     std::string objectName;
     726         795 :     if (m_osKey == INVALID_OBJ_KEY)
     727           0 :         m_osKey.clear();
     728        1590 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     729         795 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     730             :                                 object.m_poJsonObject)) == json_type_object)
     731             :     {
     732         795 :         json_object *poVal = json_object_new_uint64(nValue);
     733         795 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     734             :                                objectName.c_str(), poVal);
     735             :     }
     736         795 : }
     737             : 
     738             : /**
     739             :  * Add new key - value pair to json object.
     740             :  * @param osName  Key name.
     741             :  * @param oValue   Array value.
     742             :  *
     743             :  * @since GDAL 2.3
     744             :  */
     745        9103 : void CPLJSONObject::Add(const std::string &osName, const CPLJSONArray &oValue)
     746             : {
     747       18206 :     std::string objectName;
     748        9103 :     if (m_osKey == INVALID_OBJ_KEY)
     749           0 :         m_osKey.clear();
     750       18206 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     751        9103 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     752             :                                 object.m_poJsonObject)) == json_type_object)
     753             :     {
     754       18206 :         json_object_object_add(
     755        9103 :             TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
     756        9103 :             json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
     757             :     }
     758        9103 : }
     759             : 
     760             : /**
     761             :  * Add new key - value pair to json object.
     762             :  * @param osName  Key name.
     763             :  * @param oValue   Json object value.
     764             :  *
     765             :  * @since GDAL 2.3
     766             :  */
     767       13891 : void CPLJSONObject::Add(const std::string &osName, const CPLJSONObject &oValue)
     768             : {
     769       13891 :     std::string objectName;
     770       13891 :     if (m_osKey == INVALID_OBJ_KEY)
     771           0 :         m_osKey.clear();
     772       13891 :     if (osName.empty())
     773             :     {
     774          20 :         json_object_object_add(
     775          10 :             TO_JSONOBJ(GetInternalHandle()), "",
     776          10 :             json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
     777          10 :         return;
     778             :     }
     779       27762 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     780       13881 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     781             :                                 object.m_poJsonObject)) == json_type_object)
     782             :     {
     783       27762 :         json_object_object_add(
     784       13881 :             TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
     785       13881 :             json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
     786             :     }
     787             : }
     788             : 
     789             : /**
     790             :  * Add new key - value pair to json object.
     791             :  * @param osName  Key name (do not split it on '/')
     792             :  * @param oValue   Json object value.
     793             :  *
     794             :  * @since GDAL 3.2
     795             :  */
     796         856 : void CPLJSONObject::AddNoSplitName(const std::string &osName,
     797             :                                    const CPLJSONObject &oValue)
     798             : {
     799         856 :     if (m_osKey == INVALID_OBJ_KEY)
     800           0 :         m_osKey.clear();
     801        1712 :     if (IsValid() &&
     802         856 :         json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_object)
     803             :     {
     804        1712 :         json_object_object_add(
     805         856 :             TO_JSONOBJ(GetInternalHandle()), osName.c_str(),
     806         856 :             json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
     807             :     }
     808         856 : }
     809             : 
     810             : /**
     811             :  * Add new key - value pair to json object.
     812             :  * @param osName  Key name.
     813             :  * @param bValue   Boolean value.
     814             :  *
     815             :  * @since GDAL 2.3
     816             :  */
     817        5750 : void CPLJSONObject::Add(const std::string &osName, bool bValue)
     818             : {
     819       11500 :     std::string objectName;
     820        5750 :     if (m_osKey == INVALID_OBJ_KEY)
     821           0 :         m_osKey.clear();
     822       11500 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     823        5750 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     824             :                                 object.m_poJsonObject)) == json_type_object)
     825             :     {
     826        5750 :         json_object *poVal = json_object_new_boolean(bValue);
     827        5750 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     828             :                                objectName.c_str(), poVal);
     829             :     }
     830        5750 : }
     831             : 
     832             : /**
     833             :  * Add new key - null pair to json object.
     834             :  * @param osName  Key name.
     835             :  *
     836             :  * @since GDAL 2.3
     837             :  */
     838       11422 : void CPLJSONObject::AddNull(const std::string &osName)
     839             : {
     840       22844 :     std::string objectName;
     841       11422 :     if (m_osKey == INVALID_OBJ_KEY)
     842           0 :         m_osKey.clear();
     843       22844 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     844       11422 :     if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
     845             :                                 object.m_poJsonObject)) == json_type_object)
     846             :     {
     847       11422 :         json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
     848             :                                objectName.c_str(), nullptr);
     849             :     }
     850       11422 : }
     851             : 
     852             : /**
     853             :  * Change value by key.
     854             :  * @param osName  Key name.
     855             :  * @param osValue String value.
     856             :  *
     857             :  * @since GDAL 2.3
     858             :  */
     859         500 : void CPLJSONObject::Set(const std::string &osName, const std::string &osValue)
     860             : {
     861         500 :     Delete(osName);
     862         500 :     Add(osName, osValue);
     863         500 : }
     864             : 
     865             : /**
     866             :  * Change value by key.
     867             :  * @param osName  Key name.
     868             :  * @param pszValue String value.
     869             :  *
     870             :  * @since GDAL 2.3
     871             :  */
     872        5068 : void CPLJSONObject::Set(const std::string &osName, const char *pszValue)
     873             : {
     874        5068 :     if (nullptr == pszValue)
     875           1 :         return;
     876        5067 :     Delete(osName);
     877        5067 :     Add(osName, pszValue);
     878             : }
     879             : 
     880             : /**
     881             :  * Change value by key.
     882             :  * @param osName  Key name.
     883             :  * @param dfValue  Double value.
     884             :  *
     885             :  * @since GDAL 2.3
     886             :  */
     887         517 : void CPLJSONObject::Set(const std::string &osName, double dfValue)
     888             : {
     889         517 :     Delete(osName);
     890         517 :     Add(osName, dfValue);
     891         517 : }
     892             : 
     893             : /**
     894             :  * Change value by key.
     895             :  * @param osName  Key name.
     896             :  * @param nValue   Integer value.
     897             :  *
     898             :  * @since GDAL 2.3
     899             :  */
     900        1394 : void CPLJSONObject::Set(const std::string &osName, int nValue)
     901             : {
     902        1394 :     Delete(osName);
     903        1394 :     Add(osName, nValue);
     904        1394 : }
     905             : 
     906             : /**
     907             :  * Change value by key.
     908             :  * @param osName  Key name.
     909             :  * @param nValue   Long value.
     910             :  *
     911             :  * @since GDAL 2.3
     912             :  */
     913         227 : void CPLJSONObject::Set(const std::string &osName, GInt64 nValue)
     914             : {
     915         227 :     Delete(osName);
     916         227 :     Add(osName, nValue);
     917         227 : }
     918             : 
     919             : /**
     920             :  * Change value by key.
     921             :  * @param osName  Key name.
     922             :  * @param nValue   uint64_t value.
     923             :  *
     924             :  * @since GDAL 3.8
     925             :  */
     926          40 : void CPLJSONObject::Set(const std::string &osName, uint64_t nValue)
     927             : {
     928          40 :     Delete(osName);
     929          40 :     Add(osName, nValue);
     930          40 : }
     931             : 
     932             : /**
     933             :  * Change value by key.
     934             :  * @param osName  Key name.
     935             :  * @param bValue   Boolean value.
     936             :  *
     937             :  * @since GDAL 2.3
     938             :  */
     939         450 : void CPLJSONObject::Set(const std::string &osName, bool bValue)
     940             : {
     941         450 :     Delete(osName);
     942         450 :     Add(osName, bValue);
     943         450 : }
     944             : 
     945             : /**
     946             :  * Change value by key.
     947             :  * @param osName  Key name.
     948             :  *
     949             :  * @since GDAL 2.3
     950             :  */
     951          14 : void CPLJSONObject::SetNull(const std::string &osName)
     952             : {
     953          14 :     Delete(osName);
     954          14 :     AddNull(osName);
     955          14 : }
     956             : 
     957             : /**
     958             :  * Get value by key.
     959             :  * @param  osName Key name.
     960             :  * @return         Json array object.
     961             :  *
     962             :  * @since GDAL 2.3
     963             :  */
     964      102713 : CPLJSONArray CPLJSONObject::GetArray(const std::string &osName) const
     965             : {
     966      205426 :     std::string objectName;
     967      205426 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     968      102713 :     if (object.IsValid())
     969             :     {
     970      102713 :         json_object *poVal = nullptr;
     971      102713 :         if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
     972      102713 :                                       objectName.c_str(), &poVal))
     973             :         {
     974       57959 :             if (poVal && json_object_get_type(poVal) == json_type_array)
     975             :             {
     976       57917 :                 return CPLJSONArray(objectName, poVal);
     977             :             }
     978             :         }
     979             :     }
     980       44796 :     return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
     981             : }
     982             : 
     983             : /**
     984             :  * Get value by key.
     985             :  * @param  osName Key name.
     986             :  * @return         Json object.
     987             :  *
     988             :  * @since GDAL 2.3
     989             :  */
     990      661961 : CPLJSONObject CPLJSONObject::GetObj(const std::string &osName) const
     991             : {
     992     1323920 :     std::string objectName;
     993     1323920 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
     994      661961 :     if (object.IsValid())
     995             :     {
     996      661134 :         json_object *poVal = nullptr;
     997      661134 :         if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
     998      661134 :                                       objectName.c_str(), &poVal))
     999             :         {
    1000      611442 :             return CPLJSONObject(objectName, poVal);
    1001             :         }
    1002             :     }
    1003       50519 :     return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
    1004             : }
    1005             : 
    1006             : /**
    1007             :  * Get value by key.
    1008             :  * @param  osName Key name.
    1009             :  * @return         Json object.
    1010             :  *
    1011             :  * @since GDAL 2.3
    1012             :  */
    1013      105964 : CPLJSONObject CPLJSONObject::operator[](const std::string &osName) const
    1014             : {
    1015      105964 :     return GetObj(osName);
    1016             : }
    1017             : 
    1018             : /**
    1019             :  * Delete json object by key.
    1020             :  * @param  osName Key name.
    1021             :  *
    1022             :  * @since GDAL 2.3
    1023             :  */
    1024       10572 : void CPLJSONObject::Delete(const std::string &osName)
    1025             : {
    1026       21144 :     std::string objectName;
    1027       10572 :     if (m_osKey == INVALID_OBJ_KEY)
    1028           0 :         m_osKey.clear();
    1029       21144 :     CPLJSONObject object = GetObjectByPath(osName, objectName);
    1030       10572 :     if (object.IsValid())
    1031             :     {
    1032       10572 :         json_object_object_del(TO_JSONOBJ(object.GetInternalHandle()),
    1033             :                                objectName.c_str());
    1034             :     }
    1035       10572 : }
    1036             : 
    1037             : /**
    1038             :  * Delete json object by key (without splitting on /)
    1039             :  * @param  osName Key name.
    1040             :  *
    1041             :  * @since GDAL 3.4
    1042             :  */
    1043         869 : void CPLJSONObject::DeleteNoSplitName(const std::string &osName)
    1044             : {
    1045         869 :     if (m_osKey == INVALID_OBJ_KEY)
    1046           0 :         m_osKey.clear();
    1047         869 :     if (m_poJsonObject)
    1048             :     {
    1049         869 :         json_object_object_del(TO_JSONOBJ(m_poJsonObject), osName.c_str());
    1050             :     }
    1051         869 : }
    1052             : 
    1053             : /**
    1054             :  * Get value by key.
    1055             :  * @param  osName    Key name.
    1056             :  * @param  osDefault Default value.
    1057             :  * @return            String value.
    1058             :  *
    1059             :  * @since GDAL 2.3
    1060             :  */
    1061      287317 : std::string CPLJSONObject::GetString(const std::string &osName,
    1062             :                                      const std::string &osDefault) const
    1063             : {
    1064      574634 :     CPLJSONObject object = GetObj(osName);
    1065      574634 :     return object.ToString(osDefault);
    1066             : }
    1067             : 
    1068             : /**
    1069             :  * Get value.
    1070             :  * @param  osDefault Default value.
    1071             :  * @return            String value.
    1072             :  *
    1073             :  * @since GDAL 2.3
    1074             :  */
    1075      439623 : std::string CPLJSONObject::ToString(const std::string &osDefault) const
    1076             : {
    1077      439623 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1078             :             json_type_string*/ )
    1079             :     {
    1080             :         const char *pszString =
    1081      421819 :             json_object_get_string(TO_JSONOBJ(m_poJsonObject));
    1082      421819 :         if (nullptr != pszString)
    1083             :         {
    1084      421819 :             return pszString;
    1085             :         }
    1086             :     }
    1087       17804 :     return osDefault;
    1088             : }
    1089             : 
    1090             : /**
    1091             :  * Get value by key.
    1092             :  * @param  osName    Key name.
    1093             :  * @param  dfDefault  Default value.
    1094             :  * @return            Double value.
    1095             :  *
    1096             :  * @since GDAL 2.3
    1097             :  */
    1098       44758 : double CPLJSONObject::GetDouble(const std::string &osName,
    1099             :                                 double dfDefault) const
    1100             : {
    1101       89516 :     CPLJSONObject object = GetObj(osName);
    1102       89516 :     return object.ToDouble(dfDefault);
    1103             : }
    1104             : 
    1105             : /**
    1106             :  * Get value
    1107             :  * @param  dfDefault  Default value.
    1108             :  * @return            Double value.
    1109             :  *
    1110             :  * @since GDAL 2.3
    1111             :  */
    1112      140314 : double CPLJSONObject::ToDouble(double dfDefault) const
    1113             : {
    1114      140314 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1115             :             json_type_double*/ )
    1116      139658 :         return json_object_get_double(TO_JSONOBJ(m_poJsonObject));
    1117         656 :     return dfDefault;
    1118             : }
    1119             : 
    1120             : /**
    1121             :  * Get value by key.
    1122             :  * @param  osName    Key name.
    1123             :  * @param  nDefault   Default value.
    1124             :  * @return            Integer value.
    1125             :  *
    1126             :  * @since GDAL 2.3
    1127             :  */
    1128      177787 : int CPLJSONObject::GetInteger(const std::string &osName, int nDefault) const
    1129             : {
    1130      355574 :     CPLJSONObject object = GetObj(osName);
    1131      355574 :     return object.ToInteger(nDefault);
    1132             : }
    1133             : 
    1134             : /**
    1135             :  * Get value.
    1136             :  * @param  nDefault   Default value.
    1137             :  * @return            Integer value.
    1138             :  *
    1139             :  * @since GDAL 2.3
    1140             :  */
    1141      179549 : int CPLJSONObject::ToInteger(int nDefault) const
    1142             : {
    1143      179549 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1144             :             json_type_int*/ )
    1145      178688 :         return json_object_get_int(TO_JSONOBJ(m_poJsonObject));
    1146         861 :     return nDefault;
    1147             : }
    1148             : 
    1149             : /**
    1150             :  * Get value by key.
    1151             :  * @param  osName    Key name.
    1152             :  * @param  nDefault   Default value.
    1153             :  * @return            Long value.
    1154             :  *
    1155             :  * @since GDAL 2.3
    1156             :  */
    1157          92 : GInt64 CPLJSONObject::GetLong(const std::string &osName, GInt64 nDefault) const
    1158             : {
    1159         184 :     CPLJSONObject object = GetObj(osName);
    1160         184 :     return object.ToLong(nDefault);
    1161             : }
    1162             : 
    1163             : /**
    1164             :  * Get value.
    1165             :  * @param  nDefault   Default value.
    1166             :  * @return            Long value.
    1167             :  *
    1168             :  * @since GDAL 2.3
    1169             :  */
    1170        2791 : GInt64 CPLJSONObject::ToLong(GInt64 nDefault) const
    1171             : {
    1172        2791 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1173             :             json_type_int*/ )
    1174             :         return static_cast<GInt64>(
    1175        2751 :             json_object_get_int64(TO_JSONOBJ(m_poJsonObject)));
    1176          40 :     return nDefault;
    1177             : }
    1178             : 
    1179             : /**
    1180             :  * Get value by key.
    1181             :  * @param  osName    Key name.
    1182             :  * @param  bDefault   Default value.
    1183             :  * @return            Boolean value.
    1184             :  *
    1185             :  * @since GDAL 2.3
    1186             :  */
    1187          98 : bool CPLJSONObject::GetBool(const std::string &osName, bool bDefault) const
    1188             : {
    1189         196 :     CPLJSONObject object = GetObj(osName);
    1190         196 :     return object.ToBool(bDefault);
    1191             : }
    1192             : 
    1193             : /**
    1194             :  * \brief Get json object children.
    1195             :  *
    1196             :  * This function is useful when keys is not know and need to
    1197             :  * iterate over json object items and get keys and values.
    1198             :  *
    1199             :  * @return Array of CPLJSONObject class instance.
    1200             :  *
    1201             :  * @since GDAL 2.3
    1202             :  */
    1203       12481 : std::vector<CPLJSONObject> CPLJSONObject::GetChildren() const
    1204             : {
    1205       12481 :     std::vector<CPLJSONObject> aoChildren;
    1206       24962 :     if (nullptr == m_poJsonObject ||
    1207       12481 :         json_object_get_type(TO_JSONOBJ(m_poJsonObject)) != json_type_object)
    1208             :     {
    1209           1 :         return aoChildren;
    1210             :     }
    1211             : 
    1212             :     json_object_iter it;
    1213       12480 :     it.key = nullptr;
    1214       12480 :     it.val = nullptr;
    1215       12480 :     it.entry = nullptr;
    1216             :     // cppcheck-suppress cstyleCast
    1217       60322 :     json_object_object_foreachC(TO_JSONOBJ(m_poJsonObject), it)
    1218             :     {
    1219       47842 :         aoChildren.push_back(CPLJSONObject(it.key, it.val));
    1220             :     }
    1221             : 
    1222       12480 :     return aoChildren;
    1223             : }
    1224             : 
    1225             : /**
    1226             :  * Get value.
    1227             :  * @param  bDefault   Default value.
    1228             :  * @return            Boolean value.
    1229             :  *
    1230             :  * @since GDAL 2.3
    1231             :  */
    1232         114 : bool CPLJSONObject::ToBool(bool bDefault) const
    1233             : {
    1234         114 :     if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
    1235             :             json_type_boolean*/ )
    1236          36 :         return json_object_get_boolean(TO_JSONOBJ(m_poJsonObject)) == 1;
    1237          78 :     return bDefault;
    1238             : }
    1239             : 
    1240             : /**
    1241             :  * Get value.
    1242             :  * @return            Array
    1243             :  *
    1244             :  * @since GDAL 2.3
    1245             :  */
    1246        8523 : CPLJSONArray CPLJSONObject::ToArray() const
    1247             : {
    1248       16110 :     if (m_poJsonObject &&
    1249        7587 :         json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_array)
    1250        7583 :         return CPLJSONArray("", TO_JSONOBJ(m_poJsonObject));
    1251         940 :     return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
    1252             : }
    1253             : 
    1254             : /**
    1255             :  * Stringify object to json format.
    1256             :  * @param  eFormat Format type,
    1257             :  * @return         A string in JSON format.
    1258             :  *
    1259             :  * @since GDAL 2.3
    1260             :  */
    1261       28067 : std::string CPLJSONObject::Format(PrettyFormat eFormat) const
    1262             : {
    1263       28067 :     if (m_poJsonObject)
    1264             :     {
    1265       28067 :         const char *pszFormatString = nullptr;
    1266       28067 :         switch (eFormat)
    1267             :         {
    1268           1 :             case PrettyFormat::Spaced:
    1269           2 :                 pszFormatString = json_object_to_json_string_ext(
    1270           1 :                     TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_SPACED);
    1271           1 :                 break;
    1272         182 :             case PrettyFormat::Pretty:
    1273         364 :                 pszFormatString = json_object_to_json_string_ext(
    1274         182 :                     TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PRETTY);
    1275         182 :                 break;
    1276       27884 :             default:
    1277       27884 :                 pszFormatString = json_object_to_json_string_ext(
    1278       27884 :                     TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PLAIN);
    1279             :         }
    1280       28067 :         if (nullptr != pszFormatString)
    1281             :         {
    1282       28067 :             return pszFormatString;
    1283             :         }
    1284             :     }
    1285           0 :     return "";
    1286             : }
    1287             : 
    1288             : /*! @cond Doxygen_Suppress */
    1289      886438 : CPLJSONObject CPLJSONObject::GetObjectByPath(const std::string &osPath,
    1290             :                                              std::string &osName) const
    1291             : {
    1292      886438 :     json_object *poVal = nullptr;
    1293             : 
    1294             :     // Typically for keys that contain / character
    1295      886438 :     if (json_object_object_get_ex(TO_JSONOBJ(GetInternalHandle()),
    1296      886438 :                                   osPath.c_str(), &poVal))
    1297             :     {
    1298      669824 :         osName = osPath;
    1299      669824 :         return *this;
    1300             :     }
    1301             : 
    1302             :     CPLStringList pathPortions(
    1303      433228 :         CSLTokenizeString2(osPath.c_str(), JSON_PATH_DELIMITER, 0));
    1304      216614 :     int portionsCount = pathPortions.size();
    1305      216614 :     if (portionsCount > 100)
    1306             :     {
    1307           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Too many components in path");
    1308           0 :         return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
    1309             :     }
    1310      216614 :     if (0 == portionsCount)
    1311           0 :         return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
    1312      433228 :     CPLJSONObject object = *this;
    1313      218946 :     for (int i = 0; i < portionsCount - 1; ++i)
    1314             :     {
    1315             :         // TODO: check array index in path - i.e.
    1316             :         // settings/catalog/root/id:1/name if EQUALN(pathPortions[i+1], "id:",
    1317             :         // 3) -> getArray
    1318        2332 :         if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
    1319        4664 :                                       pathPortions[i], &poVal))
    1320             :         {
    1321        1515 :             object = CPLJSONObject(pathPortions[i], poVal);
    1322             :         }
    1323             :         else
    1324             :         {
    1325         817 :             if (json_object_get_type(TO_JSONOBJ(object.m_poJsonObject)) !=
    1326             :                 json_type_object)
    1327             :             {
    1328           0 :                 return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
    1329             :             }
    1330         817 :             object = CPLJSONObject(pathPortions[i], object);
    1331             :         }
    1332             :     }
    1333             : 
    1334             :     //    // Check if such object already  exists
    1335             :     //    if(json_object_object_get_ex(object.m_jsonObject,
    1336             :     //                                 pathPortions[portionsCount - 1], &poVal))
    1337             :     //        return JSONObject(nullptr);
    1338             :     //
    1339      216614 :     osName = pathPortions[portionsCount - 1];
    1340      216614 :     return object;
    1341             : }
    1342             : 
    1343             : /*! @endcond */
    1344             : 
    1345             : /**
    1346             :  * Get json object type.
    1347             :  * @return Json object type.
    1348             :  *
    1349             :  * @since GDAL 2.3
    1350             :  */
    1351       90530 : CPLJSONObject::Type CPLJSONObject::GetType() const
    1352             : {
    1353       90530 :     if (nullptr == m_poJsonObject)
    1354             :     {
    1355       13127 :         if (m_osKey == INVALID_OBJ_KEY)
    1356        9301 :             return CPLJSONObject::Type::Unknown;
    1357        3826 :         return CPLJSONObject::Type::Null;
    1358             :     }
    1359       77403 :     auto jsonObj(TO_JSONOBJ(m_poJsonObject));
    1360       77403 :     switch (json_object_get_type(jsonObj))
    1361             :     {
    1362          20 :         case json_type_boolean:
    1363          20 :             return CPLJSONObject::Type::Boolean;
    1364        2995 :         case json_type_double:
    1365        2995 :             return CPLJSONObject::Type::Double;
    1366       15438 :         case json_type_int:
    1367             :         {
    1368       15438 :             if (CPL_INT64_FITS_ON_INT32(json_object_get_int64(jsonObj)))
    1369       15320 :                 return CPLJSONObject::Type::Integer;
    1370             :             else
    1371         118 :                 return CPLJSONObject::Type::Long;
    1372             :         }
    1373        9854 :         case json_type_object:
    1374        9854 :             return CPLJSONObject::Type::Object;
    1375        5724 :         case json_type_array:
    1376        5724 :             return CPLJSONObject::Type::Array;
    1377       43372 :         case json_type_string:
    1378       43372 :             return CPLJSONObject::Type::String;
    1379           0 :         default:
    1380           0 :             break;
    1381             :     }
    1382           0 :     return CPLJSONObject::Type::Unknown;
    1383             : }
    1384             : 
    1385             : /**
    1386             :  * Check if json object valid.
    1387             :  * @return true if json object valid.
    1388             :  *
    1389             :  * @since GDAL 2.3
    1390             :  */
    1391     1030350 : bool CPLJSONObject::IsValid() const
    1392             : {
    1393     1030350 :     return m_osKey != INVALID_OBJ_KEY;
    1394             : }
    1395             : 
    1396             : /**
    1397             :  * Decrement reference counter and make pointer NULL.
    1398             :  * A json object will become invalid.
    1399             :  *
    1400             :  * @since GDAL 2.3
    1401             :  */
    1402        8794 : void CPLJSONObject::Deinit()
    1403             : {
    1404        8794 :     if (m_poJsonObject)
    1405             :     {
    1406        6595 :         json_object_put(TO_JSONOBJ(m_poJsonObject));
    1407        6595 :         m_poJsonObject = nullptr;
    1408             :     }
    1409        8794 :     m_osKey = INVALID_OBJ_KEY;
    1410        8794 : }
    1411             : 
    1412             : //------------------------------------------------------------------------------
    1413             : // JSONArray
    1414             : //------------------------------------------------------------------------------
    1415             : /*! @cond Doxygen_Suppress */
    1416       33150 : CPLJSONArray::CPLJSONArray()
    1417             : {
    1418       33150 :     json_object_put(TO_JSONOBJ(m_poJsonObject));
    1419       33150 :     m_poJsonObject = json_object_new_array();
    1420       33150 : }
    1421             : 
    1422           1 : CPLJSONArray::CPLJSONArray(const std::string &osName)
    1423           1 :     : CPLJSONObject(osName, json_object_new_array())
    1424             : {
    1425           1 :     json_object_put(TO_JSONOBJ(m_poJsonObject));
    1426           1 : }
    1427             : 
    1428      111556 : CPLJSONArray::CPLJSONArray(const std::string &osName, JSONObjectH poJsonObject)
    1429      111556 :     : CPLJSONObject(osName, poJsonObject)
    1430             : {
    1431      111556 : }
    1432             : 
    1433           9 : CPLJSONArray::CPLJSONArray(const CPLJSONObject &other) : CPLJSONObject(other)
    1434             : {
    1435           9 : }
    1436             : 
    1437             : /*! @endcond */
    1438             : 
    1439             : /**
    1440             :  * Get array size.
    1441             :  * @return Array size.
    1442             :  *
    1443             :  * @since GDAL 2.3
    1444             :  */
    1445      318938 : int CPLJSONArray::Size() const
    1446             : {
    1447      318938 :     if (m_poJsonObject)
    1448             :         return static_cast<int>(
    1449      316796 :             json_object_array_length(TO_JSONOBJ(m_poJsonObject)));
    1450        2142 :     return 0;
    1451             : }
    1452             : 
    1453             : /**
    1454             :  * Add null object to array.
    1455             :  *
    1456             :  * @since GDAL 3.8
    1457             :  */
    1458        2363 : void CPLJSONArray::AddNull()
    1459             : {
    1460        2363 :     if (m_poJsonObject)
    1461        2363 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject), nullptr);
    1462        2363 : }
    1463             : 
    1464             : /**
    1465             :  * Add json object to array.
    1466             :  * @param oValue Json array.
    1467             :  *
    1468             :  * @since GDAL 2.3
    1469             :  */
    1470        8645 : void CPLJSONArray::Add(const CPLJSONObject &oValue)
    1471             : {
    1472        8645 :     if (m_poJsonObject && oValue.m_poJsonObject)
    1473       17290 :         json_object_array_add(
    1474        8645 :             TO_JSONOBJ(m_poJsonObject),
    1475        8645 :             json_object_get(TO_JSONOBJ(oValue.m_poJsonObject)));
    1476        8645 : }
    1477             : 
    1478             : /**
    1479             :  * Add value to array
    1480             :  * @param osValue Value to add.
    1481             :  *
    1482             :  * @since GDAL 2.3
    1483             :  */
    1484        9036 : void CPLJSONArray::Add(const std::string &osValue)
    1485             : {
    1486        9036 :     if (m_poJsonObject)
    1487        9036 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1488             :                               json_object_new_string(osValue.c_str()));
    1489        9036 : }
    1490             : 
    1491             : /**
    1492             :  * Add value to array
    1493             :  * @param pszValue Value to add.
    1494             :  *
    1495             :  * @since GDAL 2.3
    1496             :  */
    1497        5391 : void CPLJSONArray::Add(const char *pszValue)
    1498             : {
    1499        5391 :     if (nullptr == pszValue)
    1500           0 :         return;
    1501        5391 :     if (m_poJsonObject)
    1502        5391 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1503             :                               json_object_new_string(pszValue));
    1504             : }
    1505             : 
    1506             : /**
    1507             :  * Add value to array
    1508             :  * @param dfValue Value to add.
    1509             :  *
    1510             :  * @since GDAL 2.3
    1511             :  */
    1512        2285 : void CPLJSONArray::Add(double dfValue)
    1513             : {
    1514        2285 :     if (m_poJsonObject)
    1515        2285 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1516             :                               json_object_new_double(dfValue));
    1517        2285 : }
    1518             : 
    1519             : /**
    1520             :  * Add value to array
    1521             :  * @param nValue Value to add.
    1522             :  *
    1523             :  * @since GDAL 2.3
    1524             :  */
    1525         339 : void CPLJSONArray::Add(int nValue)
    1526             : {
    1527         339 :     if (m_poJsonObject)
    1528         339 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1529             :                               json_object_new_int(nValue));
    1530         339 : }
    1531             : 
    1532             : /**
    1533             :  * Add value to array
    1534             :  * @param nValue Value to add.
    1535             :  *
    1536             :  * @since GDAL 2.3
    1537             :  */
    1538        1478 : void CPLJSONArray::Add(GInt64 nValue)
    1539             : {
    1540        1478 :     if (m_poJsonObject)
    1541        1478 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1542             :                               json_object_new_int64(nValue));
    1543        1478 : }
    1544             : 
    1545             : /**
    1546             :  * Add value to array
    1547             :  * @param nValue Value to add.
    1548             :  *
    1549             :  * @since GDAL 3.8
    1550             :  */
    1551          28 : void CPLJSONArray::Add(uint64_t nValue)
    1552             : {
    1553          28 :     if (m_poJsonObject)
    1554             :     {
    1555          28 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1556             :                               json_object_new_uint64(nValue));
    1557             :     }
    1558          28 : }
    1559             : 
    1560             : /**
    1561             :  * Add value to array
    1562             :  * @param bValue Value to add.
    1563             :  *
    1564             :  * @since GDAL 2.3
    1565             :  */
    1566          18 : void CPLJSONArray::Add(bool bValue)
    1567             : {
    1568          18 :     if (m_poJsonObject)
    1569          18 :         json_object_array_add(TO_JSONOBJ(m_poJsonObject),
    1570             :                               json_object_new_boolean(bValue));
    1571          18 : }
    1572             : 
    1573             : /**
    1574             :  * Get array item by index.
    1575             :  * @param  nIndex Item index.
    1576             :  * @return        Json object.
    1577             :  *
    1578             :  * @since GDAL 2.3
    1579             :  */
    1580        3114 : CPLJSONObject CPLJSONArray::operator[](int nIndex)
    1581             : {
    1582             :     return CPLJSONObject(
    1583             :         CPLSPrintf("id:%d", nIndex),
    1584        3114 :         json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
    1585             : }
    1586             : 
    1587             : /**
    1588             :  * Get array const item by index.
    1589             :  * @param  nIndex Item index.
    1590             :  * @return        Json object.
    1591             :  *
    1592             :  * @since GDAL 2.3
    1593             :  */
    1594      419982 : const CPLJSONObject CPLJSONArray::operator[](int nIndex) const
    1595             : {
    1596             :     return CPLJSONObject(
    1597             :         CPLSPrintf("id:%d", nIndex),
    1598      419982 :         json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
    1599             : }
    1600             : 
    1601             : /************************************************************************/
    1602             : /*                      CPLParseKeyValueJson()                          */
    1603             : /************************************************************************/
    1604             : 
    1605             : /** Return a string list of key/value pairs extracted from a JSON doc.
    1606             : 
    1607             :     We are expecting simple documents with key:value pairs, like the
    1608             :     following with no hierarchy or complex structure.
    1609             :     \verbatim
    1610             :     {
    1611             :       "Code" : "Success",
    1612             :       "LastUpdated" : "2017-07-03T16:20:17Z",
    1613             :       "Type" : "AWS-HMAC",
    1614             :       "AccessKeyId" : "bla",
    1615             :       "SecretAccessKey" : "bla",
    1616             :       "Token" : "bla",
    1617             :       "Expiration" : "2017-07-03T22:42:58Z"
    1618             :     }
    1619             :     \endverbatim
    1620             :     @since GDAL 3.7
    1621             :  */
    1622          37 : CPLStringList CPLParseKeyValueJson(const char *pszJson)
    1623             : {
    1624          74 :     CPLJSONDocument oDoc;
    1625          37 :     CPLStringList oNameValue;
    1626          37 :     if (pszJson != nullptr && oDoc.LoadMemory(pszJson))
    1627             :     {
    1628         134 :         for (const auto &obj : oDoc.GetRoot().GetChildren())
    1629             :         {
    1630          97 :             const auto eType = obj.GetType();
    1631          97 :             if (eType == CPLJSONObject::Type::String ||
    1632           0 :                 eType == CPLJSONObject::Type::Integer ||
    1633             :                 eType == CPLJSONObject::Type::Double)
    1634             :             {
    1635         194 :                 oNameValue.SetNameValue(obj.GetName().c_str(),
    1636         291 :                                         obj.ToString().c_str());
    1637             :             }
    1638             :         }
    1639             :     }
    1640          74 :     return oNameValue;
    1641             : }

Generated by: LCOV version 1.14