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

Generated by: LCOV version 1.14