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