Coverage Report

Created: 2026-02-14 06:52

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