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