Coverage Report

Created: 2026-08-11 08:26

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