Line data Source code
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 : {
46 : }
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 10900 : template <class T> void Set(const std::string &osName, const T &val)
131 : {
132 10900 : Delete(osName);
133 10900 : Add(osName, val);
134 10900 : }
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 2030 : template <class T> inline CPLJSONObject &operator=(const T &val)
149 : {
150 2030 : CPLAssert(!m_osKeyForSet.empty());
151 2030 : std::string osKeyForSet = m_osKeyForSet;
152 2030 : m_osKeyForSet.clear();
153 2030 : Set(osKeyForSet, val);
154 4060 : return *this;
155 : }
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 2187520 : JSONObjectH GetInternalHandle() const
164 : {
165 2187520 : return m_poJsonObject;
166 : }
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 271964 : std::string GetName() const
195 : {
196 271964 : return m_osKey;
197 : }
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 576 : template <class T> static CPLJSONArray Build(std::initializer_list<T> list)
233 : {
234 576 : CPLJSONArray oArray;
235 2179 : for (const auto &val : list)
236 1603 : oArray.Add(val);
237 576 : return oArray;
238 : }
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 55322 : ConstIterator(const CPLJSONArray &oSelf, bool bStart)
257 55322 : : m_oSelf(oSelf), m_nIdx(bStart ? 0 : oSelf.Size())
258 : {
259 55322 : }
260 :
261 2221 : ConstIterator(const ConstIterator &) = default;
262 :
263 : ConstIterator &operator=(const ConstIterator &other)
264 : {
265 : if (this != &other)
266 : {
267 : CPLAssert(&m_oSelf == &(other.m_oSelf));
268 : m_nIdx = other.m_nIdx;
269 : m_oObj = other.m_oObj;
270 : }
271 : return *this;
272 : }
273 :
274 57543 : ~ConstIterator() = default;
275 :
276 104101 : CPLJSONObject &operator*() const
277 : {
278 104101 : m_oObj = m_oSelf[m_nIdx];
279 104101 : return m_oObj;
280 : }
281 :
282 96984 : ConstIterator &operator++()
283 : {
284 96984 : m_nIdx++;
285 96984 : return *this;
286 : }
287 :
288 : bool operator==(const ConstIterator &it) const
289 : {
290 : return m_nIdx == it.m_nIdx;
291 : }
292 :
293 124817 : bool operator!=(const ConstIterator &it) const
294 : {
295 124817 : return m_nIdx != it.m_nIdx;
296 : }
297 : };
298 :
299 : /*! @endcond */
300 : public:
301 : int Size() const;
302 :
303 : //! Return the size of the array
304 41 : inline size_t size() const
305 : {
306 41 : return static_cast<size_t>(Size());
307 : }
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 27489 : ConstIterator begin() const
327 : {
328 27489 : return ConstIterator(*this, true);
329 : }
330 :
331 : /** Iterator to after last element */
332 27833 : ConstIterator end() const
333 : {
334 27833 : return ConstIterator(*this, false);
335 : }
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 289 : inline CPLJSONObject &CPLJSONObject::operator=(std::initializer_list<T> list)
376 : {
377 289 : return operator=(CPLJSONArray::Build(list));
378 : }
379 :
380 : /*! @endcond */
381 :
382 : CPLStringList CPLParseKeyValueJson(const char *pszJson);
383 :
384 : #endif // CPL_JSON_H_INCLUDED
|