Coverage Report

Created: 2025-11-16 06:25

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