Coverage Report

Created: 2026-07-25 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/port/cpl_json.h
Line
Count
Source
1
/******************************************************************************
2
 * Project:  Common Portability Library
3
 * Purpose:  Function wrapper for libjson-c access.
4
 * Author:   Dmitry Baryshnikov, dmitry.baryshnikov@nextgis.com
5
 *
6
 ******************************************************************************
7
 * Copyright (c) 2017-2018 NextGIS, <info@nextgis.com>
8
 *
9
 * SPDX-License-Identifier: MIT
10
 ****************************************************************************/
11
12
#ifndef CPL_JSON_H_INCLUDED
13
#define CPL_JSON_H_INCLUDED
14
15
#include "cpl_progress.h"
16
#include "cpl_string.h"
17
18
#include <cstdint>
19
#include <initializer_list>
20
#include <iterator>
21
#include <string>
22
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
23
#include <string_view>
24
#endif
25
#include <vector>
26
27
/**
28
 * \file cpl_json.h
29
 *
30
 * Interface for read and write JSON documents
31
 */
32
33
/*! @cond Doxygen_Suppress */
34
typedef void *JSONObjectH;
35
36
class CPLJSONObject;
37
class CPLJSONArray;
38
39
class CPLJSONObjectProxy
40
{
41
    CPLJSONObject &oObj;
42
    const std::string osName;
43
44
  public:
45
    explicit inline CPLJSONObjectProxy(CPLJSONObject &oObjIn,
46
                                       const std::string &osNameIn)
47
        : oObj(oObjIn), osName(osNameIn)
48
0
    {
49
0
    }
50
51
    template <class T> inline CPLJSONObjectProxy &operator=(const T &val);
52
};
53
54
/*! @endcond */
55
56
/**
57
 * @brief The CPLJSONArray class holds JSON object from CPLJSONDocument
58
 */
59
class CPL_DLL CPLJSONObject
60
{
61
    friend class CPLJSONArray;
62
    friend class CPLJSONDocument;
63
64
  public:
65
    /**
66
     * Json object types
67
     */
68
    enum class Type
69
    {
70
        Unknown,
71
        Null,
72
        Object,
73
        Array,
74
        Boolean,
75
        String,
76
        Integer,
77
        Long,
78
        Double
79
    };
80
81
    /**
82
     * Json object format to string options
83
     */
84
    enum class PrettyFormat
85
    {
86
        Plain,   ///< No extra whitespace or formatting applied
87
        Spaced,  ///< Minimal whitespace inserted
88
        Pretty   ///< Formatted output
89
    };
90
91
  public:
92
    /*! @cond Doxygen_Suppress */
93
    CPLJSONObject();
94
    explicit CPLJSONObject(const std::string &osName,
95
                           const CPLJSONObject &oParent);
96
    explicit CPLJSONObject(std::nullptr_t);
97
    explicit CPLJSONObject(const std::string &osVal);
98
    explicit CPLJSONObject(const char *pszValue);
99
    explicit CPLJSONObject(bool bVal);
100
    explicit CPLJSONObject(int nVal);
101
    explicit CPLJSONObject(int64_t nVal);
102
    explicit CPLJSONObject(uint64_t nVal);
103
    explicit CPLJSONObject(double dfVal);
104
    ~CPLJSONObject();
105
    CPLJSONObject(const CPLJSONObject &other);
106
    CPLJSONObject(CPLJSONObject &&other);
107
    CPLJSONObject &operator=(const CPLJSONObject &other);
108
    CPLJSONObject &operator=(CPLJSONObject &&other);
109
    CPLJSONObject &operator=(CPLJSONArray &&other);
110
111
    // This method is not thread-safe
112
    CPLJSONObject Clone() const;
113
114
  private:
115
    explicit CPLJSONObject(const std::string &osName, JSONObjectH poJsonObject);
116
    /*! @endcond */
117
118
  public:
119
    // setters
120
    void Add(const std::string &osName, const std::string &osValue);
121
#if defined(DOXYGEN_SKIP) || __cplusplus >= 201703L ||                         \
122
    (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
123
124
    void Add(const std::string &osName, std::string_view svValue);
125
#endif
126
    void Add(const std::string &osName, const char *pszValue);
127
    void Add(const std::string &osName, double dfValue);
128
    void Add(const std::string &osName, int nValue);
129
    void Add(const std::string &osName, GInt64 nValue);
130
    void Add(const std::string &osName, uint64_t nValue);
131
    void Add(const std::string &osName, const CPLJSONArray &oValue);
132
    void Add(const std::string &osName, const CPLJSONObject &oValue);
133
    void AddNoSplitName(const std::string &osName, const CPLJSONObject &oValue);
134
    void Add(const std::string &osName, bool bValue);
135
    void AddNull(const std::string &osName);
136
137
    /** Change value by key */
138
    template <class T> void Set(const std::string &osName, const T &val)
139
0
    {
140
0
        Delete(osName);
141
0
        Add(osName, val);
142
0
    }
Unexecuted instantiation: void CPLJSONObject::Set<char const*>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const* const&)
Unexecuted instantiation: void CPLJSONObject::Set<char [7]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [7])
Unexecuted instantiation: void CPLJSONObject::Set<CPLString>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, CPLString const&)
Unexecuted instantiation: void CPLJSONObject::Set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: void CPLJSONObject::Set<CPLJSONObject>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, CPLJSONObject const&)
Unexecuted instantiation: void CPLJSONObject::Set<char [18]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [18])
Unexecuted instantiation: void CPLJSONObject::Set<char [16]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [16])
Unexecuted instantiation: void CPLJSONObject::Set<char [15]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [15])
Unexecuted instantiation: void CPLJSONObject::Set<double>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, double const&)
Unexecuted instantiation: void CPLJSONObject::Set<int>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int const&)
Unexecuted instantiation: void CPLJSONObject::Set<CPLJSONArray>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, CPLJSONArray const&)
Unexecuted instantiation: void CPLJSONObject::Set<char [6]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [6])
Unexecuted instantiation: void CPLJSONObject::Set<char [8]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [8])
Unexecuted instantiation: void CPLJSONObject::Set<char [13]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [13])
Unexecuted instantiation: void CPLJSONObject::Set<char [57]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [57])
Unexecuted instantiation: void CPLJSONObject::Set<char [32]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [32])
Unexecuted instantiation: void CPLJSONObject::Set<char [10]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [10])
Unexecuted instantiation: void CPLJSONObject::Set<char [11]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [11])
Unexecuted instantiation: void CPLJSONObject::Set<char*>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char* const&)
Unexecuted instantiation: void CPLJSONObject::Set<bool>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool const&)
Unexecuted instantiation: void CPLJSONObject::Set<long long>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, long long const&)
Unexecuted instantiation: void CPLJSONObject::Set<char [5]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [5])
143
144
    void SetNull(const std::string &osName);
145
146
    CPLJSONObject operator[](const std::string &osName);
147
148
/*! @cond Doxygen_Suppress */
149
150
// GCC 9.4 seems to be confused by the template and doesn't realize it
151
// returns *this
152
#ifdef __GNUC__
153
#pragma GCC diagnostic push
154
#pragma GCC diagnostic ignored "-Weffc++"
155
#endif
156
    template <class T> inline CPLJSONObject &operator=(const T &val)
157
0
    {
158
0
        CPLAssert(!m_osKeyForSet.empty());
159
0
        std::string osKeyForSet = m_osKeyForSet;
160
0
        m_osKeyForSet.clear();
161
0
        Set(osKeyForSet, val);
162
0
        return *this;
163
0
    }
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<char [7]>(char const (&) [7])
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<char const*>(char const* const&)
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<CPLString>(CPLString const&)
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<char [18]>(char const (&) [18])
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<char [16]>(char const (&) [16])
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<char [15]>(char const (&) [15])
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<double>(double const&)
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<int>(int const&)
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<CPLJSONArray>(CPLJSONArray const&)
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<char [6]>(char const (&) [6])
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<char [8]>(char const (&) [8])
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<char [13]>(char const (&) [13])
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<char [57]>(char const (&) [57])
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<char [32]>(char const (&) [32])
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<char [10]>(char const (&) [10])
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<char [11]>(char const (&) [11])
164
#ifdef __GNUC__
165
#pragma GCC diagnostic pop
166
#endif
167
168
    template <class T>
169
    inline CPLJSONObject &operator=(std::initializer_list<T> list);
170
171
    JSONObjectH GetInternalHandle() const
172
0
    {
173
0
        return m_poJsonObject;
174
0
    }
175
176
    /*! @endcond */
177
178
    // getters
179
    std::string GetString(const std::string &osName,
180
                          const std::string &osDefault = "") const;
181
    double GetDouble(const std::string &osName, double dfDefault = 0.0) const;
182
    int GetInteger(const std::string &osName, int nDefault = 0) const;
183
    GInt64 GetLong(const std::string &osName, GInt64 nDefault = 0) const;
184
    uint64_t GetUInt64(const std::string &osName, uint64_t nDefault = 0) const;
185
    bool GetBool(const std::string &osName, bool bDefault = false) const;
186
    std::string ToString(const std::string &osDefault = "") const;
187
    double ToDouble(double dfDefault = 0.0) const;
188
    int ToInteger(int nDefault = 0) const;
189
    GInt64 ToLong(GInt64 nDefault = 0) const;
190
    uint64_t ToUInt64(uint64_t nDefault = 0) const;
191
    bool ToBool(bool bDefault = false) const;
192
    CPLJSONArray ToArray() const;
193
    std::string Format(PrettyFormat eFormat) const;
194
195
    //
196
    void Delete(const std::string &osName);
197
    void DeleteNoSplitName(const std::string &osName);
198
    CPLJSONArray GetArray(const std::string &osName) const;
199
    CPLJSONObject GetObj(const std::string &osName) const;
200
    CPLJSONObject GetObjNoSplitName(const std::string &osName) const;
201
    CPLJSONObject operator[](const std::string &osName) const;
202
    Type GetType() const;
203
204
    /*! @cond Doxygen_Suppress */
205
    std::string GetName() const
206
0
    {
207
0
        return m_osKey;
208
0
    }
209
210
    /*! @endcond */
211
212
    std::vector<CPLJSONObject> GetChildren() const;
213
    bool IsValid() const;
214
    void Deinit();
215
216
  protected:
217
    /*! @cond Doxygen_Suppress */
218
    CPLJSONObject GetObjectByPath(const std::string &osPath,
219
                                  std::string &osName) const;
220
    /*! @endcond */
221
222
  private:
223
    JSONObjectH m_poJsonObject = nullptr;
224
    std::string m_osKey{};
225
    std::string m_osKeyForSet{};
226
};
227
228
/**
229
 * @brief The JSONArray class JSON array from JSONDocument
230
 */
231
class CPL_DLL CPLJSONArray : public CPLJSONObject
232
{
233
    friend class CPLJSONObject;
234
    friend class CPLJSONDocument;
235
236
  public:
237
    /*! @cond Doxygen_Suppress */
238
    CPLJSONArray();
239
    explicit CPLJSONArray(const std::string &osName);
240
    explicit CPLJSONArray(const CPLJSONObject &other);
241
242
    /** Constructor from a list of initial values */
243
    template <class T> static CPLJSONArray Build(std::initializer_list<T> list)
244
0
    {
245
0
        CPLJSONArray oArray;
246
0
        for (const auto &val : list)
247
0
            oArray.Add(val);
248
0
        return oArray;
249
0
    }
Unexecuted instantiation: CPLJSONArray CPLJSONArray::Build<double>(std::initializer_list<double>)
Unexecuted instantiation: CPLJSONArray CPLJSONArray::Build<CPLJSONArray>(std::initializer_list<CPLJSONArray>)
Unexecuted instantiation: CPLJSONArray CPLJSONArray::Build<int>(std::initializer_list<int>)
250
251
  private:
252
    explicit CPLJSONArray(const std::string &osName, JSONObjectH poJsonObject);
253
254
    class CPL_DLL ConstIterator
255
    {
256
        const CPLJSONArray &m_oSelf;
257
        int m_nIdx;
258
        mutable CPLJSONObject m_oObj{};
259
260
      public:
261
        using iterator_category = std::input_iterator_tag;
262
        using value_type = CPLJSONObject;
263
        using difference_type = std::ptrdiff_t;
264
        using pointer = CPLJSONObject *;
265
        using reference = CPLJSONObject &;
266
267
        ConstIterator(const CPLJSONArray &oSelf, bool bStart)
268
0
            : m_oSelf(oSelf), m_nIdx(bStart ? 0 : oSelf.Size())
269
0
        {
270
0
        }
271
272
        ConstIterator(const ConstIterator &) = default;
273
274
        ConstIterator &operator=(const ConstIterator &other)
275
0
        {
276
0
            if (this != &other)
277
0
            {
278
0
                CPLAssert(&m_oSelf == &(other.m_oSelf));
279
0
                m_nIdx = other.m_nIdx;
280
0
                m_oObj = other.m_oObj;
281
0
            }
282
0
            return *this;
283
0
        }
284
285
0
        ~ConstIterator() = default;
286
287
        CPLJSONObject &operator*() const
288
0
        {
289
0
            m_oObj = m_oSelf[m_nIdx];
290
0
            return m_oObj;
291
0
        }
292
293
        ConstIterator &operator++()
294
0
        {
295
0
            m_nIdx++;
296
0
            return *this;
297
0
        }
298
299
        bool operator==(const ConstIterator &it) const
300
0
        {
301
0
            return m_nIdx == it.m_nIdx;
302
0
        }
303
304
        bool operator!=(const ConstIterator &it) const
305
0
        {
306
0
            return m_nIdx != it.m_nIdx;
307
0
        }
308
    };
309
310
    /*! @endcond */
311
  public:
312
    int Size() const;
313
314
    //! Return the size of the array
315
    inline size_t size() const
316
0
    {
317
0
        return static_cast<size_t>(Size());
318
0
    }
319
320
    void AddNull();
321
    void Add(const CPLJSONObject &oValue);
322
    void Add(const std::string &osValue);
323
#if defined(DOXYGEN_SKIP) || __cplusplus >= 201703L ||                         \
324
    (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
325
326
    void Add(std::string_view svValue);
327
#endif
328
    void Add(const char *pszValue);
329
    void Add(double dfValue);
330
    void Add(int nValue);
331
    void Add(GInt64 nValue);
332
    void Add(uint64_t nValue);
333
    void Add(bool bValue);
334
335
    CPLJSONObject operator[](int nIndex);
336
    const CPLJSONObject operator[](int nIndex) const;
337
338
    CPLJSONObject operator[](size_t nIndex);
339
    const CPLJSONObject operator[](size_t nIndex) const;
340
341
    /** Iterator to first element */
342
    ConstIterator begin() const
343
0
    {
344
0
        return ConstIterator(*this, true);
345
0
    }
346
347
    /** Iterator to after last element */
348
    ConstIterator end() const
349
0
    {
350
0
        return ConstIterator(*this, false);
351
0
    }
352
};
353
354
/**
355
 * @brief The CPLJSONDocument class Wrapper class around json-c library
356
 */
357
class CPL_DLL CPLJSONDocument
358
{
359
  public:
360
    /*! @cond Doxygen_Suppress */
361
    CPLJSONDocument();
362
    ~CPLJSONDocument();
363
    CPLJSONDocument(const CPLJSONDocument &other);
364
    CPLJSONDocument &operator=(const CPLJSONDocument &other);
365
    CPLJSONDocument(CPLJSONDocument &&other);
366
    CPLJSONDocument &operator=(CPLJSONDocument &&other);
367
    /*! @endcond */
368
369
    bool Save(const std::string &osPath) const;
370
    std::string SaveAsString() const;
371
372
    CPLJSONObject GetRoot();
373
    const CPLJSONObject GetRoot() const;
374
    void SetRoot(const CPLJSONObject &oRoot);
375
    bool Load(const std::string &osPath);
376
    bool LoadMemory(const std::string &osStr);
377
    bool LoadMemory(const GByte *pabyData, int nLength = -1);
378
    bool LoadChunks(const std::string &osPath, size_t nChunkSize = 16384,
379
                    GDALProgressFunc pfnProgress = nullptr,
380
                    void *pProgressArg = nullptr);
381
    bool LoadUrl(const std::string &osUrl, const char *const *papszOptions,
382
                 GDALProgressFunc pfnProgress = nullptr,
383
                 void *pProgressArg = nullptr);
384
385
  private:
386
    mutable JSONObjectH m_poRootJsonObject;
387
};
388
389
/*! @cond Doxygen_Suppress */
390
template <class T>
391
inline CPLJSONObject &CPLJSONObject::operator=(std::initializer_list<T> list)
392
0
{
393
0
    return operator=(CPLJSONArray::Build(list));
394
0
}
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<double>(std::initializer_list<double>)
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<CPLJSONArray>(std::initializer_list<CPLJSONArray>)
Unexecuted instantiation: CPLJSONObject& CPLJSONObject::operator=<int>(std::initializer_list<int>)
395
396
/*! @endcond */
397
398
CPLStringList CPLParseKeyValueJson(const char *pszJson);
399
400
#endif  // CPL_JSON_H_INCLUDED