Coverage Report

Created: 2025-06-09 08:44

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