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