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 11065 : template <class T> void Set(const std::string &osName, const T &val)
139 : {
140 11065 : Delete(osName);
141 11065 : Add(osName, val);
142 11065 : }
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 2030 : template <class T> inline CPLJSONObject &operator=(const T &val)
157 : {
158 2030 : CPLAssert(!m_osKeyForSet.empty());
159 2030 : std::string osKeyForSet = m_osKeyForSet;
160 2030 : m_osKeyForSet.clear();
161 2030 : Set(osKeyForSet, val);
162 4060 : 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 2204790 : JSONObjectH GetInternalHandle() const
172 : {
173 2204790 : 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 operator[](const std::string &osName) const;
199 : Type GetType() const;
200 :
201 : /*! @cond Doxygen_Suppress */
202 273053 : std::string GetName() const
203 : {
204 273053 : return m_osKey;
205 : }
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 576 : template <class T> static CPLJSONArray Build(std::initializer_list<T> list)
241 : {
242 576 : CPLJSONArray oArray;
243 2179 : for (const auto &val : list)
244 1603 : oArray.Add(val);
245 576 : return oArray;
246 : }
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 56644 : ConstIterator(const CPLJSONArray &oSelf, bool bStart)
265 56644 : : m_oSelf(oSelf), m_nIdx(bStart ? 0 : oSelf.Size())
266 : {
267 56644 : }
268 :
269 2689 : ConstIterator(const ConstIterator &) = default;
270 :
271 : ConstIterator &operator=(const ConstIterator &other)
272 : {
273 : if (this != &other)
274 : {
275 : CPLAssert(&m_oSelf == &(other.m_oSelf));
276 : m_nIdx = other.m_nIdx;
277 : m_oObj = other.m_oObj;
278 : }
279 : return *this;
280 : }
281 :
282 59333 : ~ConstIterator() = default;
283 :
284 104783 : CPLJSONObject &operator*() const
285 : {
286 104783 : m_oObj = m_oSelf[m_nIdx];
287 104783 : return m_oObj;
288 : }
289 :
290 97641 : ConstIterator &operator++()
291 : {
292 97641 : m_nIdx++;
293 97641 : return *this;
294 : }
295 :
296 : bool operator==(const ConstIterator &it) const
297 : {
298 : return m_nIdx == it.m_nIdx;
299 : }
300 :
301 126174 : bool operator!=(const ConstIterator &it) const
302 : {
303 126174 : return m_nIdx != it.m_nIdx;
304 : }
305 : };
306 :
307 : /*! @endcond */
308 : public:
309 : int Size() const;
310 :
311 : //! Return the size of the array
312 41 : inline size_t size() const
313 : {
314 41 : return static_cast<size_t>(Size());
315 : }
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 28111 : ConstIterator begin() const
340 : {
341 28111 : return ConstIterator(*this, true);
342 : }
343 :
344 : /** Iterator to after last element */
345 28533 : ConstIterator end() const
346 : {
347 28533 : return ConstIterator(*this, false);
348 : }
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 289 : inline CPLJSONObject &CPLJSONObject::operator=(std::initializer_list<T> list)
389 : {
390 289 : return operator=(CPLJSONArray::Build(list));
391 : }
392 :
393 : /*! @endcond */
394 :
395 : CPLStringList CPLParseKeyValueJson(const char *pszJson);
396 :
397 : #endif // CPL_JSON_H_INCLUDED
|