Coverage Report

Created: 2026-04-01 06:20

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
    bool GetBool(const std::string &osName, bool bDefault = false) const;
185
    std::string ToString(const std::string &osDefault = "") const;
186
    double ToDouble(double dfDefault = 0.0) const;
187
    int ToInteger(int nDefault = 0) const;
188
    GInt64 ToLong(GInt64 nDefault = 0) const;
189
    bool ToBool(bool bDefault = false) const;
190
    CPLJSONArray ToArray() const;
191
    std::string Format(PrettyFormat eFormat) const;
192
193
    //
194
    void Delete(const std::string &osName);
195
    void DeleteNoSplitName(const std::string &osName);
196
    CPLJSONArray GetArray(const std::string &osName) const;
197
    CPLJSONObject GetObj(const std::string &osName) const;
198
    CPLJSONObject operator[](const std::string &osName) const;
199
    Type GetType() const;
200
201
    /*! @cond Doxygen_Suppress */
202
    std::string GetName() const
203
0
    {
204
0
        return m_osKey;
205
0
    }
206
207
    /*! @endcond */
208
209
    std::vector<CPLJSONObject> GetChildren() const;
210
    bool IsValid() const;
211
    void Deinit();
212
213
  protected:
214
    /*! @cond Doxygen_Suppress */
215
    CPLJSONObject GetObjectByPath(const std::string &osPath,
216
                                  std::string &osName) const;
217
    /*! @endcond */
218
219
  private:
220
    JSONObjectH m_poJsonObject = nullptr;
221
    std::string m_osKey{};
222
    std::string m_osKeyForSet{};
223
};
224
225
/**
226
 * @brief The JSONArray class JSON array from JSONDocument
227
 */
228
class CPL_DLL CPLJSONArray : public CPLJSONObject
229
{
230
    friend class CPLJSONObject;
231
    friend class CPLJSONDocument;
232
233
  public:
234
    /*! @cond Doxygen_Suppress */
235
    CPLJSONArray();
236
    explicit CPLJSONArray(const std::string &osName);
237
    explicit CPLJSONArray(const CPLJSONObject &other);
238
239
    /** Constructor from a list of initial values */
240
    template <class T> static CPLJSONArray Build(std::initializer_list<T> list)
241
0
    {
242
0
        CPLJSONArray oArray;
243
0
        for (const auto &val : list)
244
0
            oArray.Add(val);
245
0
        return oArray;
246
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>)
247
248
  private:
249
    explicit CPLJSONArray(const std::string &osName, JSONObjectH poJsonObject);
250
251
    class CPL_DLL ConstIterator
252
    {
253
        const CPLJSONArray &m_oSelf;
254
        int m_nIdx;
255
        mutable CPLJSONObject m_oObj{};
256
257
      public:
258
        using iterator_category = std::input_iterator_tag;
259
        using value_type = CPLJSONObject;
260
        using difference_type = std::ptrdiff_t;
261
        using pointer = CPLJSONObject *;
262
        using reference = CPLJSONObject &;
263
264
        ConstIterator(const CPLJSONArray &oSelf, bool bStart)
265
0
            : m_oSelf(oSelf), m_nIdx(bStart ? 0 : oSelf.Size())
266
0
        {
267
0
        }
268
269
        ConstIterator(const ConstIterator &) = default;
270
271
        ConstIterator &operator=(const ConstIterator &other)
272
0
        {
273
0
            if (this != &other)
274
0
            {
275
0
                CPLAssert(&m_oSelf == &(other.m_oSelf));
276
0
                m_nIdx = other.m_nIdx;
277
0
                m_oObj = other.m_oObj;
278
0
            }
279
0
            return *this;
280
0
        }
281
282
0
        ~ConstIterator() = default;
283
284
        CPLJSONObject &operator*() const
285
0
        {
286
0
            m_oObj = m_oSelf[m_nIdx];
287
0
            return m_oObj;
288
0
        }
289
290
        ConstIterator &operator++()
291
0
        {
292
0
            m_nIdx++;
293
0
            return *this;
294
0
        }
295
296
        bool operator==(const ConstIterator &it) const
297
0
        {
298
0
            return m_nIdx == it.m_nIdx;
299
0
        }
300
301
        bool operator!=(const ConstIterator &it) const
302
0
        {
303
0
            return m_nIdx != it.m_nIdx;
304
0
        }
305
    };
306
307
    /*! @endcond */
308
  public:
309
    int Size() const;
310
311
    //! Return the size of the array
312
    inline size_t size() const
313
0
    {
314
0
        return static_cast<size_t>(Size());
315
0
    }
316
317
    void AddNull();
318
    void Add(const CPLJSONObject &oValue);
319
    void Add(const std::string &osValue);
320
#if defined(DOXYGEN_SKIP) || __cplusplus >= 201703L ||                         \
321
    (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
322
323
    void Add(std::string_view svValue);
324
#endif
325
    void Add(const char *pszValue);
326
    void Add(double dfValue);
327
    void Add(int nValue);
328
    void Add(GInt64 nValue);
329
    void Add(uint64_t nValue);
330
    void Add(bool bValue);
331
332
    CPLJSONObject operator[](int nIndex);
333
    const CPLJSONObject operator[](int nIndex) const;
334
335
    CPLJSONObject operator[](size_t nIndex);
336
    const CPLJSONObject operator[](size_t nIndex) const;
337
338
    /** Iterator to first element */
339
    ConstIterator begin() const
340
0
    {
341
0
        return ConstIterator(*this, true);
342
0
    }
343
344
    /** Iterator to after last element */
345
    ConstIterator end() const
346
0
    {
347
0
        return ConstIterator(*this, false);
348
0
    }
349
};
350
351
/**
352
 * @brief The CPLJSONDocument class Wrapper class around json-c library
353
 */
354
class CPL_DLL CPLJSONDocument
355
{
356
  public:
357
    /*! @cond Doxygen_Suppress */
358
    CPLJSONDocument();
359
    ~CPLJSONDocument();
360
    CPLJSONDocument(const CPLJSONDocument &other);
361
    CPLJSONDocument &operator=(const CPLJSONDocument &other);
362
    CPLJSONDocument(CPLJSONDocument &&other);
363
    CPLJSONDocument &operator=(CPLJSONDocument &&other);
364
    /*! @endcond */
365
366
    bool Save(const std::string &osPath) const;
367
    std::string SaveAsString() const;
368
369
    CPLJSONObject GetRoot();
370
    const CPLJSONObject GetRoot() const;
371
    void SetRoot(const CPLJSONObject &oRoot);
372
    bool Load(const std::string &osPath);
373
    bool LoadMemory(const std::string &osStr);
374
    bool LoadMemory(const GByte *pabyData, int nLength = -1);
375
    bool LoadChunks(const std::string &osPath, size_t nChunkSize = 16384,
376
                    GDALProgressFunc pfnProgress = nullptr,
377
                    void *pProgressArg = nullptr);
378
    bool LoadUrl(const std::string &osUrl, const char *const *papszOptions,
379
                 GDALProgressFunc pfnProgress = nullptr,
380
                 void *pProgressArg = nullptr);
381
382
  private:
383
    mutable JSONObjectH m_poRootJsonObject;
384
};
385
386
/*! @cond Doxygen_Suppress */
387
template <class T>
388
inline CPLJSONObject &CPLJSONObject::operator=(std::initializer_list<T> list)
389
0
{
390
0
    return operator=(CPLJSONArray::Build(list));
391
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>)
392
393
/*! @endcond */
394
395
CPLStringList CPLParseKeyValueJson(const char *pszJson);
396
397
#endif  // CPL_JSON_H_INCLUDED