Coverage Report

Created: 2025-06-13 06:18

/src/gdal/port/cpl_json.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * Project:  Common Portability Library
3
 * Purpose:  Function wrapper for libjson-c access.
4
 * Author:   Dmitry Baryshnikov, dmitry.baryshnikov@nextgis.com
5
 *
6
 ******************************************************************************
7
 * Copyright (c) 2017-2018 NextGIS, <info@nextgis.com>
8
 *
9
 * SPDX-License-Identifier: MIT
10
 ****************************************************************************/
11
12
#include "cpl_json.h"
13
14
#include "cpl_error.h"
15
#include "cpl_json_header.h"
16
#include "cpl_vsi.h"
17
18
#include "cpl_http.h"
19
#include "cpl_multiproc.h"
20
21
0
#define TO_JSONOBJ(x) static_cast<json_object *>(x)
22
23
static const char *JSON_PATH_DELIMITER = "/";
24
25
static const char *INVALID_OBJ_KEY = "__INVALID_OBJ_KEY__";
26
27
#define JSON_C_VER_014 (14 << 8)
28
29
// json_object_new_uint64() was added in libjson-c 0.14
30
#if (!defined(JSON_C_VERSION_NUM)) || (JSON_C_VERSION_NUM < JSON_C_VER_014)
31
32
static int CPLJSON_json_object_new_uint64_formatter(struct json_object *jso,
33
                                                    struct printbuf *pb,
34
                                                    int /* level */,
35
                                                    int /* flags */)
36
{
37
    const char *pszStr = json_object_get_string(jso);
38
    return printbuf_memappend(pb, pszStr, static_cast<int>(strlen(pszStr)));
39
}
40
41
static json_object *CPLJSON_json_object_new_uint64(uint64_t nVal)
42
{
43
    json_object *jso = json_object_new_string(
44
        CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nVal)));
45
    json_object_set_serializer(jso, CPLJSON_json_object_new_uint64_formatter,
46
                               nullptr, nullptr);
47
    return jso;
48
}
49
50
#define json_object_new_uint64 CPLJSON_json_object_new_uint64
51
52
#endif
53
54
//------------------------------------------------------------------------------
55
// JSONDocument
56
//------------------------------------------------------------------------------
57
/*! @cond Doxygen_Suppress */
58
0
CPLJSONDocument::CPLJSONDocument() : m_poRootJsonObject(nullptr)
59
0
{
60
0
}
61
62
CPLJSONDocument::~CPLJSONDocument()
63
0
{
64
0
    if (m_poRootJsonObject)
65
0
        json_object_put(TO_JSONOBJ(m_poRootJsonObject));
66
0
}
67
68
CPLJSONDocument::CPLJSONDocument(const CPLJSONDocument &other)
69
0
    : m_poRootJsonObject(json_object_get(TO_JSONOBJ(other.m_poRootJsonObject)))
70
0
{
71
0
}
72
73
CPLJSONDocument &CPLJSONDocument::operator=(const CPLJSONDocument &other)
74
0
{
75
0
    if (this == &other)
76
0
        return *this;
77
78
0
    if (m_poRootJsonObject)
79
0
        json_object_put(TO_JSONOBJ(m_poRootJsonObject));
80
0
    m_poRootJsonObject = json_object_get(TO_JSONOBJ(other.m_poRootJsonObject));
81
82
0
    return *this;
83
0
}
84
85
CPLJSONDocument::CPLJSONDocument(CPLJSONDocument &&other)
86
0
    : m_poRootJsonObject(other.m_poRootJsonObject)
87
0
{
88
0
    other.m_poRootJsonObject = nullptr;
89
0
}
90
91
CPLJSONDocument &CPLJSONDocument::operator=(CPLJSONDocument &&other)
92
0
{
93
0
    if (this == &other)
94
0
        return *this;
95
96
0
    if (m_poRootJsonObject)
97
0
        json_object_put(TO_JSONOBJ(m_poRootJsonObject));
98
0
    m_poRootJsonObject = other.m_poRootJsonObject;
99
0
    other.m_poRootJsonObject = nullptr;
100
101
0
    return *this;
102
0
}
103
104
/*! @endcond */
105
106
/**
107
 * Save json document at specified path
108
 * @param  osPath Path to save json document
109
 * @return         true on success. If error occurred it can be received using
110
 * CPLGetLastErrorMsg method.
111
 *
112
 * @since GDAL 2.3
113
 */
114
bool CPLJSONDocument::Save(const std::string &osPath) const
115
0
{
116
0
    VSILFILE *fp = VSIFOpenL(osPath.c_str(), "wt");
117
0
    if (nullptr == fp)
118
0
    {
119
0
        CPLError(CE_Failure, CPLE_NoWriteAccess, "Open file %s to write failed",
120
0
                 osPath.c_str());
121
0
        return false;
122
0
    }
123
124
0
    const char *pabyData = json_object_to_json_string_ext(
125
0
        TO_JSONOBJ(m_poRootJsonObject), JSON_C_TO_STRING_PRETTY);
126
0
    VSIFWriteL(pabyData, 1, strlen(pabyData), fp);
127
128
0
    VSIFCloseL(fp);
129
130
0
    return true;
131
0
}
132
133
/**
134
 * Return the json document as a serialized string.
135
 * @return         serialized document.
136
 *
137
 * @since GDAL 2.3
138
 */
139
std::string CPLJSONDocument::SaveAsString() const
140
0
{
141
0
    return json_object_to_json_string_ext(TO_JSONOBJ(m_poRootJsonObject),
142
0
                                          JSON_C_TO_STRING_PRETTY);
143
0
}
144
145
/**
146
 * Get json document root object
147
 * @return CPLJSONObject class instance
148
 *
149
 * @since GDAL 3.1
150
 */
151
const CPLJSONObject CPLJSONDocument::GetRoot() const
152
0
{
153
0
    return const_cast<CPLJSONDocument *>(this)->GetRoot();
154
0
}
155
156
/**
157
 * Get json document root object
158
 * @return CPLJSONObject class instance
159
 *
160
 * @since GDAL 2.3
161
 */
162
CPLJSONObject CPLJSONDocument::GetRoot()
163
0
{
164
0
    if (nullptr == m_poRootJsonObject)
165
0
    {
166
0
        m_poRootJsonObject = json_object_new_object();
167
0
    }
168
169
0
    if (json_object_get_type(TO_JSONOBJ(m_poRootJsonObject)) == json_type_array)
170
0
    {
171
0
        return CPLJSONArray("", m_poRootJsonObject);
172
0
    }
173
0
    else
174
0
    {
175
0
        return CPLJSONObject("", m_poRootJsonObject);
176
0
    }
177
0
}
178
179
/**
180
 * Set json document root object
181
 * @param oRoot CPLJSONObject root object
182
 *
183
 * @since GDAL 3.4
184
 */
185
void CPLJSONDocument::SetRoot(const CPLJSONObject &oRoot)
186
0
{
187
0
    if (m_poRootJsonObject)
188
0
        json_object_put(TO_JSONOBJ(m_poRootJsonObject));
189
0
    m_poRootJsonObject = json_object_get(TO_JSONOBJ(oRoot.m_poJsonObject));
190
0
}
191
192
/**
193
 * Load json document from file by provided path
194
 * @param  osPath Path to json file.
195
 * @return         true on success. If error occurred it can be received using
196
 * CPLGetLastErrorMsg method.
197
 *
198
 * @since GDAL 2.3
199
 */
200
bool CPLJSONDocument::Load(const std::string &osPath)
201
0
{
202
0
    GByte *pabyOut = nullptr;
203
0
    vsi_l_offset nSize = 0;
204
205
0
    GIntBig nMaxSize = 0;
206
0
    if (CPLParseMemorySize(CPLGetConfigOption("CPL_JSON_MAX_SIZE", "100MB"),
207
0
                           &nMaxSize, nullptr) != CE_None ||
208
0
        nMaxSize <= 0)
209
0
        return false;
210
211
0
    if (!VSIIngestFile(nullptr, osPath.c_str(), &pabyOut, &nSize, nMaxSize))
212
0
    {
213
0
        CPLError(CE_Failure, CPLE_FileIO, "Load json file %s failed",
214
0
                 osPath.c_str());
215
0
        return false;
216
0
    }
217
218
0
    bool bResult = LoadMemory(pabyOut, static_cast<int>(nSize));
219
0
    VSIFree(pabyOut);
220
0
    return bResult;
221
0
}
222
223
/**
224
 * Load json document from memory buffer.
225
 * @param  pabyData Buffer.data.
226
 * @param  nLength  Buffer size.
227
 * @return          true on success. If error occurred it can be received using
228
 * CPLGetLastErrorMsg method.
229
 *
230
 * @since GDAL 2.3
231
 */
232
bool CPLJSONDocument::LoadMemory(const GByte *pabyData, int nLength)
233
0
{
234
0
    if (nullptr == pabyData)
235
0
    {
236
0
        return false;
237
0
    }
238
239
0
    if (m_poRootJsonObject)
240
0
        json_object_put(TO_JSONOBJ(m_poRootJsonObject));
241
242
0
    if (nLength == 4 &&
243
0
        memcmp(reinterpret_cast<const char *>(pabyData), "true", nLength) == 0)
244
0
    {
245
0
        m_poRootJsonObject = json_object_new_boolean(true);
246
0
        return true;
247
0
    }
248
249
0
    if (nLength == 5 &&
250
0
        memcmp(reinterpret_cast<const char *>(pabyData), "false", nLength) == 0)
251
0
    {
252
0
        m_poRootJsonObject = json_object_new_boolean(false);
253
0
        return true;
254
0
    }
255
256
0
    json_tokener *jstok = json_tokener_new();
257
0
    m_poRootJsonObject = json_tokener_parse_ex(
258
0
        jstok, reinterpret_cast<const char *>(pabyData), nLength);
259
0
    bool bParsed = jstok->err == json_tokener_success;
260
0
    if (!bParsed)
261
0
    {
262
0
        CPLError(CE_Failure, CPLE_AppDefined,
263
0
                 "JSON parsing error: %s (at offset %d)",
264
0
                 json_tokener_error_desc(jstok->err), jstok->char_offset);
265
0
        json_tokener_free(jstok);
266
0
        return false;
267
0
    }
268
0
    json_tokener_free(jstok);
269
0
    return bParsed;
270
0
}
271
272
/**
273
 * Load json document from memory buffer.
274
 * @param  osStr    String
275
 * @return          true on success. If error occurred it can be received using
276
 * CPLGetLastErrorMsg method.
277
 *
278
 * @since GDAL 2.3
279
 */
280
bool CPLJSONDocument::LoadMemory(const std::string &osStr)
281
0
{
282
0
    if (osStr.empty())
283
0
        return false;
284
0
    return LoadMemory(reinterpret_cast<const GByte *>(osStr.data()),
285
0
                      static_cast<int>(osStr.size()));
286
0
}
287
288
/**
289
 * Load json document from file using small chunks of data.
290
 * @param  osPath      Path to json document file.
291
 * @param  nChunkSize   Chunk size.
292
 * @param  pfnProgress  a function to report progress of the json data loading.
293
 * @param  pProgressArg application data passed into progress function.
294
 * @return              true on success. If error occurred it can be received
295
 * using CPLGetLastErrorMsg method.
296
 *
297
 * @since GDAL 2.3
298
 */
299
bool CPLJSONDocument::LoadChunks(const std::string &osPath, size_t nChunkSize,
300
                                 GDALProgressFunc pfnProgress,
301
                                 void *pProgressArg)
302
0
{
303
0
    VSIStatBufL sStatBuf;
304
0
    if (VSIStatL(osPath.c_str(), &sStatBuf) != 0)
305
0
    {
306
0
        CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", osPath.c_str());
307
0
        return false;
308
0
    }
309
310
0
    VSILFILE *fp = VSIFOpenL(osPath.c_str(), "rb");
311
0
    if (fp == nullptr)
312
0
    {
313
0
        CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", osPath.c_str());
314
0
        return false;
315
0
    }
316
317
0
    void *pBuffer = CPLMalloc(nChunkSize);
318
0
    json_tokener *tok = json_tokener_new();
319
0
    bool bSuccess = true;
320
0
    GUInt32 nFileSize = static_cast<GUInt32>(sStatBuf.st_size);
321
0
    double dfTotalRead = 0.0;
322
323
0
    while (true)
324
0
    {
325
0
        size_t nRead = VSIFReadL(pBuffer, 1, nChunkSize, fp);
326
0
        dfTotalRead += nRead;
327
328
0
        if (m_poRootJsonObject)
329
0
            json_object_put(TO_JSONOBJ(m_poRootJsonObject));
330
331
0
        m_poRootJsonObject = json_tokener_parse_ex(
332
0
            tok, static_cast<const char *>(pBuffer), static_cast<int>(nRead));
333
334
0
        enum json_tokener_error jerr = json_tokener_get_error(tok);
335
0
        if (jerr != json_tokener_continue && jerr != json_tokener_success)
336
0
        {
337
0
            CPLError(CE_Failure, CPLE_AppDefined, "JSON error: %s",
338
0
                     json_tokener_error_desc(jerr));
339
0
            bSuccess = false;
340
0
            break;
341
0
        }
342
343
0
        if (nRead < nChunkSize)
344
0
        {
345
0
            break;
346
0
        }
347
348
0
        if (nullptr != pfnProgress)
349
0
        {
350
0
            pfnProgress(dfTotalRead / nFileSize, "Loading ...", pProgressArg);
351
0
        }
352
0
    }
353
354
0
    json_tokener_free(tok);
355
0
    CPLFree(pBuffer);
356
0
    VSIFCloseL(fp);
357
358
0
    if (nullptr != pfnProgress)
359
0
    {
360
0
        pfnProgress(1.0, "Loading ...", pProgressArg);
361
0
    }
362
363
0
    return bSuccess;
364
0
}
365
366
/*! @cond Doxygen_Suppress */
367
#ifdef HAVE_CURL
368
369
typedef struct
370
{
371
    json_object *pObject;
372
    json_tokener *pTokener;
373
} JsonContext, *JsonContextL;
374
375
static size_t CPLJSONWriteFunction(void *pBuffer, size_t nSize, size_t nMemb,
376
                                   void *pUserData)
377
{
378
    size_t nLength = nSize * nMemb;
379
    JsonContextL ctx = static_cast<JsonContextL>(pUserData);
380
    if (ctx->pObject != nullptr)
381
    {
382
        CPLError(CE_Failure, CPLE_AppDefined,
383
                 "A complete JSon object had already been parsed before new "
384
                 "content is appended to it");
385
        return 0;
386
    }
387
    ctx->pObject =
388
        json_tokener_parse_ex(ctx->pTokener, static_cast<const char *>(pBuffer),
389
                              static_cast<int>(nLength));
390
    switch (json_tokener_get_error(ctx->pTokener))
391
    {
392
        case json_tokener_continue:
393
        case json_tokener_success:
394
            return nLength;
395
        default:
396
            return 0; /* error: interrupt the transfer */
397
    }
398
}
399
400
#endif  // HAVE_CURL
401
/*! @endcond */
402
403
/**
404
 * Load json document from web.
405
 * @param  osUrl       Url to json document.
406
 * @param  papszOptions Option list as a NULL-terminated array of strings. May
407
 * be NULL. The available keys are same for CPLHTTPFetch method. Additional key
408
 * JSON_DEPTH define json parse depth. Default is 10.
409
 * @param  pfnProgress  a function to report progress of the json data loading.
410
 * @param  pProgressArg application data passed into progress function.
411
 * @return              true on success. If error occurred it can be received
412
 * using CPLGetLastErrorMsg method.
413
 *
414
 * @since GDAL 2.3
415
 */
416
417
#ifdef HAVE_CURL
418
bool CPLJSONDocument::LoadUrl(const std::string &osUrl,
419
                              const char *const *papszOptions,
420
                              GDALProgressFunc pfnProgress, void *pProgressArg)
421
#else
422
bool CPLJSONDocument::LoadUrl(const std::string & /*osUrl*/,
423
                              const char *const * /*papszOptions*/,
424
                              GDALProgressFunc /*pfnProgress*/,
425
                              void * /*pProgressArg*/)
426
#endif  // HAVE_CURL
427
0
{
428
#ifdef HAVE_CURL
429
    int nDepth =
430
        atoi(CSLFetchNameValueDef(papszOptions, "JSON_DEPTH",
431
                                  "32"));  // Same as JSON_TOKENER_DEFAULT_DEPTH
432
    JsonContext ctx = {nullptr, json_tokener_new_ex(nDepth)};
433
434
    CPLHTTPFetchWriteFunc pWriteFunc = CPLJSONWriteFunction;
435
    CPLHTTPResult *psResult =
436
        CPLHTTPFetchEx(osUrl.c_str(), papszOptions, pfnProgress, pProgressArg,
437
                       pWriteFunc, &ctx);
438
439
    bool bResult =
440
        psResult->nStatus == 0 /*CURLE_OK*/ && psResult->pszErrBuf == nullptr;
441
442
    CPLHTTPDestroyResult(psResult);
443
444
    enum json_tokener_error jerr;
445
    if ((jerr = json_tokener_get_error(ctx.pTokener)) != json_tokener_success)
446
    {
447
        CPLError(CE_Failure, CPLE_AppDefined, "JSON error: %s\n",
448
                 json_tokener_error_desc(jerr));
449
        bResult = false;
450
    }
451
    else
452
    {
453
        if (m_poRootJsonObject)
454
            json_object_put(TO_JSONOBJ(m_poRootJsonObject));
455
456
        m_poRootJsonObject = ctx.pObject;
457
    }
458
    json_tokener_free(ctx.pTokener);
459
460
    return bResult;
461
#else
462
0
    CPLError(CE_Failure, CPLE_NotSupported,
463
0
             "LoadUrl() not supported in a build without Curl");
464
0
    return false;
465
0
#endif
466
0
}
467
468
//------------------------------------------------------------------------------
469
// JSONObject
470
//------------------------------------------------------------------------------
471
/*! @cond Doxygen_Suppress */
472
0
CPLJSONObject::CPLJSONObject() : m_poJsonObject(json_object_new_object())
473
0
{
474
0
}
475
476
0
CPLJSONObject::CPLJSONObject(std::nullptr_t) : m_poJsonObject(nullptr)
477
0
{
478
0
}
479
480
CPLJSONObject::CPLJSONObject(const std::string &osVal)
481
0
    : m_poJsonObject(json_object_new_string(osVal.c_str()))
482
0
{
483
0
}
484
485
CPLJSONObject::CPLJSONObject(const char *pszValue)
486
0
    : m_poJsonObject(json_object_new_string(pszValue))
487
0
{
488
0
}
489
490
CPLJSONObject::CPLJSONObject(bool bVal)
491
0
    : m_poJsonObject(json_object_new_boolean(bVal))
492
0
{
493
0
}
494
495
CPLJSONObject::CPLJSONObject(int nVal)
496
0
    : m_poJsonObject(json_object_new_int(nVal))
497
0
{
498
0
}
499
500
CPLJSONObject::CPLJSONObject(int64_t nVal)
501
0
    : m_poJsonObject(json_object_new_int64(nVal))
502
0
{
503
0
}
504
505
CPLJSONObject::CPLJSONObject(uint64_t nVal)
506
0
    : m_poJsonObject(json_object_new_uint64(nVal))
507
0
{
508
0
}
509
510
CPLJSONObject::CPLJSONObject(double dfVal)
511
0
    : m_poJsonObject(json_object_new_double(dfVal))
512
0
{
513
0
}
514
515
CPLJSONObject::CPLJSONObject(const std::string &osName,
516
                             const CPLJSONObject &oParent)
517
0
    : m_poJsonObject(json_object_get(json_object_new_object())), m_osKey(osName)
518
0
{
519
0
    json_object_object_add(TO_JSONOBJ(oParent.m_poJsonObject), osName.c_str(),
520
0
                           TO_JSONOBJ(m_poJsonObject));
521
0
}
522
523
CPLJSONObject::CPLJSONObject(const std::string &osName,
524
                             JSONObjectH poJsonObject)
525
0
    : m_poJsonObject(json_object_get(TO_JSONOBJ(poJsonObject))), m_osKey(osName)
526
0
{
527
0
}
528
529
CPLJSONObject CPLJSONObject::Clone() const
530
0
{
531
0
    CPLJSONObject oRet;
532
0
    if (IsValid())
533
0
    {
534
0
        CPLJSONDocument oTmpDoc;
535
0
        oTmpDoc.SetRoot(*this);
536
0
        std::string osStr = oTmpDoc.SaveAsString();
537
0
        CPL_IGNORE_RET_VAL(oTmpDoc.LoadMemory(osStr));
538
0
        oRet = oTmpDoc.GetRoot();
539
0
    }
540
0
    return oRet;
541
0
}
542
543
CPLJSONObject::~CPLJSONObject()
544
0
{
545
    // Should delete m_poJsonObject only if CPLJSONObject has no parent
546
0
    if (m_poJsonObject)
547
0
    {
548
0
        json_object_put(TO_JSONOBJ(m_poJsonObject));
549
0
        m_poJsonObject = nullptr;
550
0
    }
551
0
}
552
553
CPLJSONObject::CPLJSONObject(const CPLJSONObject &other)
554
0
    : m_poJsonObject(json_object_get(TO_JSONOBJ(other.m_poJsonObject))),
555
0
      m_osKey(other.m_osKey)
556
0
{
557
0
}
558
559
CPLJSONObject::CPLJSONObject(CPLJSONObject &&other)
560
0
    : m_poJsonObject(other.m_poJsonObject), m_osKey(std::move(other.m_osKey))
561
0
{
562
0
    other.m_poJsonObject = nullptr;
563
0
}
564
565
CPLJSONObject &CPLJSONObject::operator=(const CPLJSONObject &other)
566
0
{
567
0
    if (this == &other)
568
0
        return *this;
569
570
0
    m_osKey = other.m_osKey;
571
0
    if (m_poJsonObject)
572
0
        json_object_put(TO_JSONOBJ(m_poJsonObject));
573
0
    m_poJsonObject = json_object_get(TO_JSONOBJ(other.m_poJsonObject));
574
0
    return *this;
575
0
}
576
577
CPLJSONObject &CPLJSONObject::operator=(CPLJSONObject &&other)
578
0
{
579
0
    if (this == &other)
580
0
        return *this;
581
582
0
    m_osKey = std::move(other.m_osKey);
583
0
    if (m_poJsonObject)
584
0
        json_object_put(TO_JSONOBJ(m_poJsonObject));
585
0
    m_poJsonObject = other.m_poJsonObject;
586
0
    other.m_poJsonObject = nullptr;
587
0
    return *this;
588
0
}
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
0
{
601
0
    std::string objectName;
602
0
    if (m_osKey == INVALID_OBJ_KEY)
603
0
        m_osKey.clear();
604
0
    CPLJSONObject object = GetObjectByPath(osName, objectName);
605
0
    if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
606
0
                                object.m_poJsonObject)) == json_type_object)
607
0
    {
608
0
        json_object *poVal = json_object_new_string(osValue.c_str());
609
0
        json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
610
0
                               objectName.c_str(), poVal);
611
0
    }
612
0
}
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
0
{
623
0
    if (nullptr == pszValue)
624
0
    {
625
0
        return;
626
0
    }
627
0
    if (m_osKey == INVALID_OBJ_KEY)
628
0
        m_osKey.clear();
629
0
    std::string objectName;
630
0
    CPLJSONObject object = GetObjectByPath(osName, objectName);
631
0
    if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
632
0
                                object.m_poJsonObject)) == json_type_object)
633
0
    {
634
0
        json_object *poVal = json_object_new_string(pszValue);
635
0
        json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
636
0
                               objectName.c_str(), poVal);
637
0
    }
638
0
}
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
0
{
657
0
    std::string objectName;
658
0
    if (m_osKey == INVALID_OBJ_KEY)
659
0
        m_osKey.clear();
660
0
    CPLJSONObject object = GetObjectByPath(osName, objectName);
661
0
    if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
662
0
                                object.m_poJsonObject)) == json_type_object)
663
0
    {
664
0
        json_object *poVal =
665
0
            json_object_new_double_with_significant_figures(dfValue, -1);
666
0
        json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
667
0
                               objectName.c_str(), poVal);
668
0
    }
669
0
}
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
0
{
680
0
    std::string objectName;
681
0
    if (m_osKey == INVALID_OBJ_KEY)
682
0
        m_osKey.clear();
683
0
    CPLJSONObject object = GetObjectByPath(osName, objectName);
684
0
    if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
685
0
                                object.m_poJsonObject)) == json_type_object)
686
0
    {
687
0
        json_object *poVal = json_object_new_int(nValue);
688
0
        json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
689
0
                               objectName.c_str(), poVal);
690
0
    }
691
0
}
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
0
{
702
0
    std::string objectName;
703
0
    if (m_osKey == INVALID_OBJ_KEY)
704
0
        m_osKey.clear();
705
0
    CPLJSONObject object = GetObjectByPath(osName, objectName);
706
0
    if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
707
0
                                object.m_poJsonObject)) == json_type_object)
708
0
    {
709
0
        json_object *poVal =
710
0
            json_object_new_int64(static_cast<int64_t>(nValue));
711
0
        json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
712
0
                               objectName.c_str(), poVal);
713
0
    }
714
0
}
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
0
{
747
0
    std::string objectName;
748
0
    if (m_osKey == INVALID_OBJ_KEY)
749
0
        m_osKey.clear();
750
0
    CPLJSONObject object = GetObjectByPath(osName, objectName);
751
0
    if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
752
0
                                object.m_poJsonObject)) == json_type_object)
753
0
    {
754
0
        json_object_object_add(
755
0
            TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
756
0
            json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
757
0
    }
758
0
}
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
0
{
769
0
    std::string objectName;
770
0
    if (m_osKey == INVALID_OBJ_KEY)
771
0
        m_osKey.clear();
772
0
    if (osName.empty())
773
0
    {
774
0
        json_object_object_add(
775
0
            TO_JSONOBJ(GetInternalHandle()), "",
776
0
            json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
777
0
        return;
778
0
    }
779
0
    CPLJSONObject object = GetObjectByPath(osName, objectName);
780
0
    if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
781
0
                                object.m_poJsonObject)) == json_type_object)
782
0
    {
783
0
        json_object_object_add(
784
0
            TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
785
0
            json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
786
0
    }
787
0
}
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
0
{
799
0
    if (m_osKey == INVALID_OBJ_KEY)
800
0
        m_osKey.clear();
801
0
    if (IsValid() &&
802
0
        json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_object)
803
0
    {
804
0
        json_object_object_add(
805
0
            TO_JSONOBJ(GetInternalHandle()), osName.c_str(),
806
0
            json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
807
0
    }
808
0
}
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
0
{
840
0
    std::string objectName;
841
0
    if (m_osKey == INVALID_OBJ_KEY)
842
0
        m_osKey.clear();
843
0
    CPLJSONObject object = GetObjectByPath(osName, objectName);
844
0
    if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
845
0
                                object.m_poJsonObject)) == json_type_object)
846
0
    {
847
0
        json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
848
0
                               objectName.c_str(), nullptr);
849
0
    }
850
0
}
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
0
{
874
0
    if (nullptr == pszValue)
875
0
        return;
876
0
    Delete(osName);
877
0
    Add(osName, pszValue);
878
0
}
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
0
{
889
0
    Delete(osName);
890
0
    Add(osName, dfValue);
891
0
}
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
0
{
966
0
    std::string objectName;
967
0
    CPLJSONObject object = GetObjectByPath(osName, objectName);
968
0
    if (object.IsValid())
969
0
    {
970
0
        json_object *poVal = nullptr;
971
0
        if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
972
0
                                      objectName.c_str(), &poVal))
973
0
        {
974
0
            if (poVal && json_object_get_type(poVal) == json_type_array)
975
0
            {
976
0
                return CPLJSONArray(objectName, poVal);
977
0
            }
978
0
        }
979
0
    }
980
0
    return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
981
0
}
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
0
{
992
0
    std::string objectName;
993
0
    CPLJSONObject object = GetObjectByPath(osName, objectName);
994
0
    if (object.IsValid())
995
0
    {
996
0
        json_object *poVal = nullptr;
997
0
        if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
998
0
                                      objectName.c_str(), &poVal))
999
0
        {
1000
0
            return CPLJSONObject(objectName, poVal);
1001
0
        }
1002
0
    }
1003
0
    return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1004
0
}
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
0
{
1015
0
    return GetObj(osName);
1016
0
}
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
0
{
1026
0
    std::string objectName;
1027
0
    if (m_osKey == INVALID_OBJ_KEY)
1028
0
        m_osKey.clear();
1029
0
    CPLJSONObject object = GetObjectByPath(osName, objectName);
1030
0
    if (object.IsValid())
1031
0
    {
1032
0
        json_object_object_del(TO_JSONOBJ(object.GetInternalHandle()),
1033
0
                               objectName.c_str());
1034
0
    }
1035
0
}
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
0
{
1045
0
    if (m_osKey == INVALID_OBJ_KEY)
1046
0
        m_osKey.clear();
1047
0
    if (m_poJsonObject)
1048
0
    {
1049
0
        json_object_object_del(TO_JSONOBJ(m_poJsonObject), osName.c_str());
1050
0
    }
1051
0
}
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
0
{
1064
0
    CPLJSONObject object = GetObj(osName);
1065
0
    return object.ToString(osDefault);
1066
0
}
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
0
{
1077
0
    if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1078
0
            json_type_string*/ )
1079
0
    {
1080
0
        const char *pszString =
1081
0
            json_object_get_string(TO_JSONOBJ(m_poJsonObject));
1082
0
        if (nullptr != pszString)
1083
0
        {
1084
0
            return pszString;
1085
0
        }
1086
0
    }
1087
0
    return osDefault;
1088
0
}
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
0
{
1101
0
    CPLJSONObject object = GetObj(osName);
1102
0
    return object.ToDouble(dfDefault);
1103
0
}
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
0
{
1114
0
    if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1115
0
            json_type_double*/ )
1116
0
        return json_object_get_double(TO_JSONOBJ(m_poJsonObject));
1117
0
    return dfDefault;
1118
0
}
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
0
{
1130
0
    CPLJSONObject object = GetObj(osName);
1131
0
    return object.ToInteger(nDefault);
1132
0
}
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
0
{
1143
0
    if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1144
0
            json_type_int*/ )
1145
0
        return json_object_get_int(TO_JSONOBJ(m_poJsonObject));
1146
0
    return nDefault;
1147
0
}
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
0
{
1172
0
    if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1173
0
            json_type_int*/ )
1174
0
        return static_cast<GInt64>(
1175
0
            json_object_get_int64(TO_JSONOBJ(m_poJsonObject)));
1176
0
    return nDefault;
1177
0
}
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
0
{
1205
0
    std::vector<CPLJSONObject> aoChildren;
1206
0
    if (nullptr == m_poJsonObject ||
1207
0
        json_object_get_type(TO_JSONOBJ(m_poJsonObject)) != json_type_object)
1208
0
    {
1209
0
        return aoChildren;
1210
0
    }
1211
1212
0
    json_object_iter it;
1213
0
    it.key = nullptr;
1214
0
    it.val = nullptr;
1215
0
    it.entry = nullptr;
1216
    // cppcheck-suppress cstyleCast
1217
0
    json_object_object_foreachC(TO_JSONOBJ(m_poJsonObject), it)
1218
0
    {
1219
0
        aoChildren.push_back(CPLJSONObject(it.key, it.val));
1220
0
    }
1221
1222
0
    return aoChildren;
1223
0
}
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
0
{
1248
0
    if (m_poJsonObject &&
1249
0
        json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_array)
1250
0
        return CPLJSONArray("", TO_JSONOBJ(m_poJsonObject));
1251
0
    return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
1252
0
}
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
0
{
1263
0
    if (m_poJsonObject)
1264
0
    {
1265
0
        const char *pszFormatString = nullptr;
1266
0
        switch (eFormat)
1267
0
        {
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
0
            case PrettyFormat::Pretty:
1273
0
                pszFormatString = json_object_to_json_string_ext(
1274
0
                    TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PRETTY);
1275
0
                break;
1276
0
            default:
1277
0
                pszFormatString = json_object_to_json_string_ext(
1278
0
                    TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PLAIN);
1279
0
        }
1280
0
        if (nullptr != pszFormatString)
1281
0
        {
1282
0
            return pszFormatString;
1283
0
        }
1284
0
    }
1285
0
    return "";
1286
0
}
1287
1288
/*! @cond Doxygen_Suppress */
1289
CPLJSONObject CPLJSONObject::GetObjectByPath(const std::string &osPath,
1290
                                             std::string &osName) const
1291
0
{
1292
0
    json_object *poVal = nullptr;
1293
1294
    // Typically for keys that contain / character
1295
0
    if (json_object_object_get_ex(TO_JSONOBJ(GetInternalHandle()),
1296
0
                                  osPath.c_str(), &poVal))
1297
0
    {
1298
0
        osName = osPath;
1299
0
        return *this;
1300
0
    }
1301
1302
0
    CPLStringList pathPortions(
1303
0
        CSLTokenizeString2(osPath.c_str(), JSON_PATH_DELIMITER, 0));
1304
0
    int portionsCount = pathPortions.size();
1305
0
    if (portionsCount > 100)
1306
0
    {
1307
0
        CPLError(CE_Failure, CPLE_NotSupported, "Too many components in path");
1308
0
        return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1309
0
    }
1310
0
    if (0 == portionsCount)
1311
0
        return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1312
0
    CPLJSONObject object = *this;
1313
0
    for (int i = 0; i < portionsCount - 1; ++i)
1314
0
    {
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
0
        if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
1319
0
                                      pathPortions[i], &poVal))
1320
0
        {
1321
0
            object = CPLJSONObject(pathPortions[i], poVal);
1322
0
        }
1323
0
        else
1324
0
        {
1325
0
            if (json_object_get_type(TO_JSONOBJ(object.m_poJsonObject)) !=
1326
0
                json_type_object)
1327
0
            {
1328
0
                return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1329
0
            }
1330
0
            object = CPLJSONObject(pathPortions[i], object);
1331
0
        }
1332
0
    }
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
0
    osName = pathPortions[portionsCount - 1];
1340
0
    return object;
1341
0
}
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
0
{
1353
0
    if (nullptr == m_poJsonObject)
1354
0
    {
1355
0
        if (m_osKey == INVALID_OBJ_KEY)
1356
0
            return CPLJSONObject::Type::Unknown;
1357
0
        return CPLJSONObject::Type::Null;
1358
0
    }
1359
0
    auto jsonObj(TO_JSONOBJ(m_poJsonObject));
1360
0
    switch (json_object_get_type(jsonObj))
1361
0
    {
1362
0
        case json_type_boolean:
1363
0
            return CPLJSONObject::Type::Boolean;
1364
0
        case json_type_double:
1365
0
            return CPLJSONObject::Type::Double;
1366
0
        case json_type_int:
1367
0
        {
1368
0
            if (CPL_INT64_FITS_ON_INT32(json_object_get_int64(jsonObj)))
1369
0
                return CPLJSONObject::Type::Integer;
1370
0
            else
1371
0
                return CPLJSONObject::Type::Long;
1372
0
        }
1373
0
        case json_type_object:
1374
0
            return CPLJSONObject::Type::Object;
1375
0
        case json_type_array:
1376
0
            return CPLJSONObject::Type::Array;
1377
0
        case json_type_string:
1378
0
            return CPLJSONObject::Type::String;
1379
0
        default:
1380
0
            break;
1381
0
    }
1382
0
    return CPLJSONObject::Type::Unknown;
1383
0
}
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
0
{
1393
0
    return m_osKey != INVALID_OBJ_KEY;
1394
0
}
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
0
{
1404
0
    if (m_poJsonObject)
1405
0
    {
1406
0
        json_object_put(TO_JSONOBJ(m_poJsonObject));
1407
0
        m_poJsonObject = nullptr;
1408
0
    }
1409
0
    m_osKey = INVALID_OBJ_KEY;
1410
0
}
1411
1412
//------------------------------------------------------------------------------
1413
// JSONArray
1414
//------------------------------------------------------------------------------
1415
/*! @cond Doxygen_Suppress */
1416
CPLJSONArray::CPLJSONArray()
1417
0
{
1418
0
    json_object_put(TO_JSONOBJ(m_poJsonObject));
1419
0
    m_poJsonObject = json_object_new_array();
1420
0
}
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
0
    : CPLJSONObject(osName, poJsonObject)
1430
0
{
1431
0
}
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
0
{
1447
0
    if (m_poJsonObject)
1448
0
        return static_cast<int>(
1449
0
            json_object_array_length(TO_JSONOBJ(m_poJsonObject)));
1450
0
    return 0;
1451
0
}
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
0
{
1472
0
    if (m_poJsonObject && oValue.m_poJsonObject)
1473
0
        json_object_array_add(
1474
0
            TO_JSONOBJ(m_poJsonObject),
1475
0
            json_object_get(TO_JSONOBJ(oValue.m_poJsonObject)));
1476
0
}
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
0
{
1486
0
    if (m_poJsonObject)
1487
0
        json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1488
0
                              json_object_new_string(osValue.c_str()));
1489
0
}
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
0
{
1499
0
    if (nullptr == pszValue)
1500
0
        return;
1501
0
    if (m_poJsonObject)
1502
0
        json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1503
0
                              json_object_new_string(pszValue));
1504
0
}
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
0
{
1514
0
    if (m_poJsonObject)
1515
0
        json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1516
0
                              json_object_new_double(dfValue));
1517
0
}
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
0
{
1527
0
    if (m_poJsonObject)
1528
0
        json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1529
0
                              json_object_new_int(nValue));
1530
0
}
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
0
{
1540
0
    if (m_poJsonObject)
1541
0
        json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1542
0
                              json_object_new_int64(nValue));
1543
0
}
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
0
{
1582
0
    return CPLJSONObject(
1583
0
        CPLSPrintf("id:%d", nIndex),
1584
0
        json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
1585
0
}
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
0
{
1596
0
    return CPLJSONObject(
1597
0
        CPLSPrintf("id:%d", nIndex),
1598
0
        json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
1599
0
}
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
0
{
1624
0
    CPLJSONDocument oDoc;
1625
0
    CPLStringList oNameValue;
1626
0
    if (pszJson != nullptr && oDoc.LoadMemory(pszJson))
1627
0
    {
1628
0
        for (const auto &obj : oDoc.GetRoot().GetChildren())
1629
0
        {
1630
0
            const auto eType = obj.GetType();
1631
0
            if (eType == CPLJSONObject::Type::String ||
1632
0
                eType == CPLJSONObject::Type::Integer ||
1633
0
                eType == CPLJSONObject::Type::Double)
1634
0
            {
1635
0
                oNameValue.SetNameValue(obj.GetName().c_str(),
1636
0
                                        obj.ToString().c_str());
1637
0
            }
1638
0
        }
1639
0
    }
1640
0
    return oNameValue;
1641
0
}