Coverage Report

Created: 2025-08-28 06:57

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