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 : #include "cpl_json.h"
13 :
14 : #include "cpl_error.h"
15 : #include "cpl_json_header.h"
16 : #include "cpl_vsi.h"
17 :
18 : #include "cpl_http.h"
19 : #include "cpl_multiproc.h"
20 :
21 : #define TO_JSONOBJ(x) static_cast<json_object *>(x)
22 :
23 : static const char *JSON_PATH_DELIMITER = "/";
24 :
25 : static const char *INVALID_OBJ_KEY = "__INVALID_OBJ_KEY__";
26 :
27 : #define JSON_C_VER_014 (14 << 8)
28 :
29 : // json_object_new_uint64() was added in libjson-c 0.14
30 : #if (!defined(JSON_C_VERSION_NUM)) || (JSON_C_VERSION_NUM < JSON_C_VER_014)
31 :
32 : static int CPLJSON_json_object_new_uint64_formatter(struct json_object *jso,
33 : struct printbuf *pb,
34 : int /* level */,
35 : int /* flags */)
36 : {
37 : const char *pszStr = json_object_get_string(jso);
38 : return printbuf_memappend(pb, pszStr, static_cast<int>(strlen(pszStr)));
39 : }
40 :
41 : static json_object *CPLJSON_json_object_new_uint64(uint64_t nVal)
42 : {
43 : json_object *jso = json_object_new_string(
44 : CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nVal)));
45 : json_object_set_serializer(jso, CPLJSON_json_object_new_uint64_formatter,
46 : nullptr, nullptr);
47 : return jso;
48 : }
49 :
50 : #define json_object_new_uint64 CPLJSON_json_object_new_uint64
51 :
52 : #endif
53 :
54 : //------------------------------------------------------------------------------
55 : // JSONDocument
56 : //------------------------------------------------------------------------------
57 : /*! @cond Doxygen_Suppress */
58 16465 : CPLJSONDocument::CPLJSONDocument() : m_poRootJsonObject(nullptr)
59 : {
60 16465 : }
61 :
62 32944 : CPLJSONDocument::~CPLJSONDocument()
63 : {
64 16472 : if (m_poRootJsonObject)
65 11986 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
66 16472 : }
67 :
68 6 : CPLJSONDocument::CPLJSONDocument(const CPLJSONDocument &other)
69 6 : : m_poRootJsonObject(json_object_get(TO_JSONOBJ(other.m_poRootJsonObject)))
70 : {
71 6 : }
72 :
73 2 : CPLJSONDocument &CPLJSONDocument::operator=(const CPLJSONDocument &other)
74 : {
75 2 : if (this == &other)
76 1 : return *this;
77 :
78 1 : if (m_poRootJsonObject)
79 1 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
80 1 : m_poRootJsonObject = json_object_get(TO_JSONOBJ(other.m_poRootJsonObject));
81 :
82 1 : return *this;
83 : }
84 :
85 1 : CPLJSONDocument::CPLJSONDocument(CPLJSONDocument &&other)
86 1 : : m_poRootJsonObject(other.m_poRootJsonObject)
87 : {
88 1 : other.m_poRootJsonObject = nullptr;
89 1 : }
90 :
91 119 : CPLJSONDocument &CPLJSONDocument::operator=(CPLJSONDocument &&other)
92 : {
93 119 : if (this == &other)
94 0 : return *this;
95 :
96 119 : if (m_poRootJsonObject)
97 21 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
98 119 : m_poRootJsonObject = other.m_poRootJsonObject;
99 119 : other.m_poRootJsonObject = nullptr;
100 :
101 119 : return *this;
102 : }
103 :
104 : /*! @endcond */
105 :
106 : /**
107 : * Save json document at specified path
108 : * @param osPath Path to save json document
109 : * @return true on success. If error occurred it can be received using
110 : * CPLGetLastErrorMsg method.
111 : *
112 : * @since GDAL 2.3
113 : */
114 1357 : bool CPLJSONDocument::Save(const std::string &osPath) const
115 : {
116 1357 : VSILFILE *fp = VSIFOpenL(osPath.c_str(), "wt");
117 1357 : if (nullptr == fp)
118 : {
119 14 : CPLError(CE_Failure, CPLE_NoWriteAccess,
120 : "File %s cannot be opened for writing", osPath.c_str());
121 14 : return false;
122 : }
123 :
124 2686 : const char *pabyData = json_object_to_json_string_ext(
125 1343 : TO_JSONOBJ(m_poRootJsonObject), JSON_C_TO_STRING_PRETTY);
126 1343 : bool bRet = VSIFWriteL(pabyData, strlen(pabyData), 1, fp) == 1;
127 :
128 1343 : bRet = VSIFCloseL(fp) == 0 && bRet;
129 :
130 1343 : return bRet;
131 : }
132 :
133 : /**
134 : * Return the json document as a serialized string.
135 : * @return serialized document.
136 : *
137 : * @since GDAL 2.3
138 : */
139 2068 : std::string CPLJSONDocument::SaveAsString() const
140 : {
141 2068 : return json_object_to_json_string_ext(TO_JSONOBJ(m_poRootJsonObject),
142 2068 : JSON_C_TO_STRING_PRETTY);
143 : }
144 :
145 : /**
146 : * Get json document root object
147 : * @return CPLJSONObject class instance
148 : *
149 : * @since GDAL 3.1
150 : */
151 93 : const CPLJSONObject CPLJSONDocument::GetRoot() const
152 : {
153 93 : return const_cast<CPLJSONDocument *>(this)->GetRoot();
154 : }
155 :
156 : /**
157 : * Get json document root object
158 : * @return CPLJSONObject class instance
159 : *
160 : * @since GDAL 2.3
161 : */
162 18012 : CPLJSONObject CPLJSONDocument::GetRoot()
163 : {
164 18012 : if (nullptr == m_poRootJsonObject)
165 : {
166 1443 : m_poRootJsonObject = json_object_new_object();
167 : }
168 :
169 18012 : if (json_object_get_type(TO_JSONOBJ(m_poRootJsonObject)) == json_type_array)
170 : {
171 676 : return CPLJSONArray("", m_poRootJsonObject);
172 : }
173 : else
174 : {
175 17674 : return CPLJSONObject("", m_poRootJsonObject);
176 : }
177 : }
178 :
179 : /**
180 : * Set json document root object
181 : * @param oRoot CPLJSONObject root object
182 : *
183 : * @since GDAL 3.4
184 : */
185 2149 : void CPLJSONDocument::SetRoot(const CPLJSONObject &oRoot)
186 : {
187 2149 : if (m_poRootJsonObject)
188 0 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
189 2149 : m_poRootJsonObject = json_object_get(TO_JSONOBJ(oRoot.m_poJsonObject));
190 2149 : }
191 :
192 : /**
193 : * Load json document from file by provided path
194 : * @param osPath Path to json file.
195 : * @return true on success. If error occurred it can be received using
196 : * CPLGetLastErrorMsg method.
197 : *
198 : * @since GDAL 2.3
199 : */
200 5872 : bool CPLJSONDocument::Load(const std::string &osPath)
201 : {
202 5872 : GByte *pabyOut = nullptr;
203 5872 : vsi_l_offset nSize = 0;
204 :
205 5872 : GIntBig nMaxSize = 0;
206 5872 : if (CPLParseMemorySize(CPLGetConfigOption("CPL_JSON_MAX_SIZE", "100MB"),
207 11744 : &nMaxSize, nullptr) != CE_None ||
208 5872 : nMaxSize <= 0)
209 0 : return false;
210 :
211 5872 : if (!VSIIngestFile(nullptr, osPath.c_str(), &pabyOut, &nSize, nMaxSize))
212 : {
213 811 : CPLError(CE_Failure, CPLE_FileIO, "Load json file %s failed",
214 : osPath.c_str());
215 811 : return false;
216 : }
217 :
218 5061 : bool bResult = LoadMemory(pabyOut, static_cast<int>(nSize));
219 5061 : VSIFree(pabyOut);
220 5061 : return bResult;
221 : }
222 :
223 : /**
224 : * Load json document from memory buffer.
225 : * @param pabyData Buffer.data.
226 : * @param nLength Buffer size.
227 : * @return true on success. If error occurred it can be received using
228 : * CPLGetLastErrorMsg method.
229 : *
230 : * @since GDAL 2.3
231 : */
232 10009 : bool CPLJSONDocument::LoadMemory(const GByte *pabyData, int nLength)
233 : {
234 10009 : if (nullptr == pabyData)
235 : {
236 1 : return false;
237 : }
238 :
239 10008 : if (m_poRootJsonObject)
240 1574 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
241 :
242 10008 : if (nLength == 4 &&
243 8 : memcmp(reinterpret_cast<const char *>(pabyData), "true", nLength) == 0)
244 : {
245 5 : m_poRootJsonObject = json_object_new_boolean(true);
246 5 : return true;
247 : }
248 :
249 10003 : if (nLength == 5 &&
250 5 : memcmp(reinterpret_cast<const char *>(pabyData), "false", nLength) == 0)
251 : {
252 3 : m_poRootJsonObject = json_object_new_boolean(false);
253 3 : return true;
254 : }
255 :
256 10000 : json_tokener *jstok = json_tokener_new();
257 10000 : m_poRootJsonObject = json_tokener_parse_ex(
258 : jstok, reinterpret_cast<const char *>(pabyData), nLength);
259 10000 : bool bParsed = jstok->err == json_tokener_success;
260 10000 : if (!bParsed)
261 : {
262 23 : CPLError(CE_Failure, CPLE_AppDefined,
263 : "JSON parsing error: %s (at offset %d)",
264 : json_tokener_error_desc(jstok->err), jstok->char_offset);
265 23 : json_tokener_free(jstok);
266 23 : return false;
267 : }
268 9977 : json_tokener_free(jstok);
269 9977 : return bParsed;
270 : }
271 :
272 : /**
273 : * Load json document from memory buffer.
274 : * @param osStr String
275 : * @return true on success. If error occurred it can be received using
276 : * CPLGetLastErrorMsg method.
277 : *
278 : * @since GDAL 2.3
279 : */
280 4846 : bool CPLJSONDocument::LoadMemory(const std::string &osStr)
281 : {
282 4846 : if (osStr.empty())
283 3 : return false;
284 4843 : return LoadMemory(reinterpret_cast<const GByte *>(osStr.data()),
285 9686 : static_cast<int>(osStr.size()));
286 : }
287 :
288 : /**
289 : * Load json document from file using small chunks of data.
290 : * @param osPath Path to json document file.
291 : * @param nChunkSize Chunk size.
292 : * @param pfnProgress a function to report progress of the json data loading.
293 : * @param pProgressArg application data passed into progress function.
294 : * @return true on success. If error occurred it can be received
295 : * using CPLGetLastErrorMsg method.
296 : *
297 : * @since GDAL 2.3
298 : */
299 3 : bool CPLJSONDocument::LoadChunks(const std::string &osPath, size_t nChunkSize,
300 : GDALProgressFunc pfnProgress,
301 : void *pProgressArg)
302 : {
303 : VSIStatBufL sStatBuf;
304 3 : if (VSIStatL(osPath.c_str(), &sStatBuf) != 0)
305 : {
306 2 : CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", osPath.c_str());
307 2 : return false;
308 : }
309 :
310 1 : VSILFILE *fp = VSIFOpenL(osPath.c_str(), "rb");
311 1 : if (fp == nullptr)
312 : {
313 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", osPath.c_str());
314 0 : return false;
315 : }
316 :
317 1 : void *pBuffer = CPLMalloc(nChunkSize);
318 1 : json_tokener *tok = json_tokener_new();
319 1 : bool bSuccess = true;
320 1 : GUInt32 nFileSize = static_cast<GUInt32>(sStatBuf.st_size);
321 1 : double dfTotalRead = 0.0;
322 :
323 : while (true)
324 : {
325 6 : size_t nRead = VSIFReadL(pBuffer, 1, nChunkSize, fp);
326 6 : dfTotalRead += nRead;
327 :
328 6 : if (m_poRootJsonObject)
329 1 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
330 :
331 6 : m_poRootJsonObject = json_tokener_parse_ex(
332 : tok, static_cast<const char *>(pBuffer), static_cast<int>(nRead));
333 :
334 6 : enum json_tokener_error jerr = json_tokener_get_error(tok);
335 6 : if (jerr != json_tokener_continue && jerr != json_tokener_success)
336 : {
337 0 : CPLError(CE_Failure, CPLE_AppDefined, "JSON error: %s",
338 : json_tokener_error_desc(jerr));
339 0 : bSuccess = false;
340 0 : break;
341 : }
342 :
343 6 : if (nRead < nChunkSize)
344 : {
345 1 : break;
346 : }
347 :
348 5 : if (nullptr != pfnProgress)
349 : {
350 0 : pfnProgress(dfTotalRead / nFileSize, "Loading ...", pProgressArg);
351 : }
352 5 : }
353 :
354 1 : json_tokener_free(tok);
355 1 : CPLFree(pBuffer);
356 1 : VSIFCloseL(fp);
357 :
358 1 : if (nullptr != pfnProgress)
359 : {
360 0 : pfnProgress(1.0, "Loading ...", pProgressArg);
361 : }
362 :
363 1 : return bSuccess;
364 : }
365 :
366 : /*! @cond Doxygen_Suppress */
367 : #ifdef HAVE_CURL
368 :
369 : typedef struct
370 : {
371 : json_object *pObject;
372 : json_tokener *pTokener;
373 : } JsonContext, *JsonContextL;
374 :
375 0 : static size_t CPLJSONWriteFunction(void *pBuffer, size_t nSize, size_t nMemb,
376 : void *pUserData)
377 : {
378 0 : size_t nLength = nSize * nMemb;
379 0 : JsonContextL ctx = static_cast<JsonContextL>(pUserData);
380 0 : if (ctx->pObject != nullptr)
381 : {
382 0 : CPLError(CE_Failure, CPLE_AppDefined,
383 : "A complete JSon object had already been parsed before new "
384 : "content is appended to it");
385 0 : return 0;
386 : }
387 0 : ctx->pObject =
388 0 : json_tokener_parse_ex(ctx->pTokener, static_cast<const char *>(pBuffer),
389 : static_cast<int>(nLength));
390 0 : switch (json_tokener_get_error(ctx->pTokener))
391 : {
392 0 : case json_tokener_continue:
393 : case json_tokener_success:
394 0 : return nLength;
395 0 : default:
396 0 : return 0; /* error: interrupt the transfer */
397 : }
398 : }
399 :
400 : #endif // HAVE_CURL
401 : /*! @endcond */
402 :
403 : /**
404 : * Load json document from web.
405 : * @param osUrl Url to json document.
406 : * @param papszOptions Option list as a NULL-terminated array of strings. May
407 : * be NULL. The available keys are same for CPLHTTPFetch method. Additional key
408 : * JSON_DEPTH define json parse depth. Default is 10.
409 : * @param pfnProgress a function to report progress of the json data loading.
410 : * @param pProgressArg application data passed into progress function.
411 : * @return true on success. If error occurred it can be received
412 : * using CPLGetLastErrorMsg method.
413 : *
414 : * @since GDAL 2.3
415 : */
416 :
417 : #ifdef HAVE_CURL
418 2 : bool CPLJSONDocument::LoadUrl(const std::string &osUrl,
419 : const char *const *papszOptions,
420 : GDALProgressFunc pfnProgress, void *pProgressArg)
421 : #else
422 : bool CPLJSONDocument::LoadUrl(const std::string & /*osUrl*/,
423 : const char *const * /*papszOptions*/,
424 : GDALProgressFunc /*pfnProgress*/,
425 : void * /*pProgressArg*/)
426 : #endif // HAVE_CURL
427 : {
428 : #ifdef HAVE_CURL
429 : int nDepth =
430 2 : atoi(CSLFetchNameValueDef(papszOptions, "JSON_DEPTH",
431 : "32")); // Same as JSON_TOKENER_DEFAULT_DEPTH
432 2 : JsonContext ctx = {nullptr, json_tokener_new_ex(nDepth)};
433 :
434 2 : CPLHTTPFetchWriteFunc pWriteFunc = CPLJSONWriteFunction;
435 : CPLHTTPResult *psResult =
436 2 : CPLHTTPFetchEx(osUrl.c_str(), papszOptions, pfnProgress, pProgressArg,
437 : pWriteFunc, &ctx);
438 :
439 2 : bool bResult =
440 2 : psResult->nStatus == 0 /*CURLE_OK*/ && psResult->pszErrBuf == nullptr;
441 :
442 2 : CPLHTTPDestroyResult(psResult);
443 :
444 : enum json_tokener_error jerr;
445 2 : if ((jerr = json_tokener_get_error(ctx.pTokener)) != json_tokener_success)
446 : {
447 0 : CPLError(CE_Failure, CPLE_AppDefined, "JSON error: %s\n",
448 : json_tokener_error_desc(jerr));
449 0 : bResult = false;
450 : }
451 : else
452 : {
453 2 : if (m_poRootJsonObject)
454 1 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
455 :
456 2 : m_poRootJsonObject = ctx.pObject;
457 : }
458 2 : json_tokener_free(ctx.pTokener);
459 :
460 2 : return bResult;
461 : #else
462 : CPLError(CE_Failure, CPLE_NotSupported,
463 : "LoadUrl() not supported in a build without Curl");
464 : return false;
465 : #endif
466 : }
467 :
468 : //------------------------------------------------------------------------------
469 : // JSONObject
470 : //------------------------------------------------------------------------------
471 : /*! @cond Doxygen_Suppress */
472 146791 : CPLJSONObject::CPLJSONObject() : m_poJsonObject(json_object_new_object())
473 : {
474 146791 : }
475 :
476 1 : CPLJSONObject::CPLJSONObject(std::nullptr_t) : m_poJsonObject(nullptr)
477 : {
478 1 : }
479 :
480 1 : CPLJSONObject::CPLJSONObject(const std::string &osVal)
481 1 : : m_poJsonObject(json_object_new_string(osVal.c_str()))
482 : {
483 1 : }
484 :
485 1 : CPLJSONObject::CPLJSONObject(const char *pszValue)
486 1 : : m_poJsonObject(json_object_new_string(pszValue))
487 : {
488 1 : }
489 :
490 1 : CPLJSONObject::CPLJSONObject(bool bVal)
491 1 : : m_poJsonObject(json_object_new_boolean(bVal))
492 : {
493 1 : }
494 :
495 1 : CPLJSONObject::CPLJSONObject(int nVal)
496 1 : : m_poJsonObject(json_object_new_int(nVal))
497 : {
498 1 : }
499 :
500 1 : CPLJSONObject::CPLJSONObject(int64_t nVal)
501 1 : : m_poJsonObject(json_object_new_int64(nVal))
502 : {
503 1 : }
504 :
505 1 : CPLJSONObject::CPLJSONObject(uint64_t nVal)
506 1 : : m_poJsonObject(json_object_new_uint64(nVal))
507 : {
508 1 : }
509 :
510 1 : CPLJSONObject::CPLJSONObject(double dfVal)
511 1 : : m_poJsonObject(json_object_new_double(dfVal))
512 : {
513 1 : }
514 :
515 821 : CPLJSONObject::CPLJSONObject(const std::string &osName,
516 821 : const CPLJSONObject &oParent)
517 821 : : m_poJsonObject(json_object_get(json_object_new_object())), m_osKey(osName)
518 : {
519 821 : json_object_object_add(TO_JSONOBJ(oParent.m_poJsonObject), osName.c_str(),
520 821 : TO_JSONOBJ(m_poJsonObject));
521 821 : }
522 :
523 1304530 : CPLJSONObject::CPLJSONObject(const std::string &osName,
524 1304530 : JSONObjectH poJsonObject)
525 1304530 : : m_poJsonObject(json_object_get(TO_JSONOBJ(poJsonObject))), m_osKey(osName)
526 : {
527 1304530 : }
528 :
529 809 : CPLJSONObject CPLJSONObject::Clone() const
530 : {
531 809 : CPLJSONObject oRet;
532 809 : if (IsValid())
533 : {
534 1600 : CPLJSONDocument oTmpDoc;
535 800 : oTmpDoc.SetRoot(*this);
536 800 : std::string osStr = oTmpDoc.SaveAsString();
537 800 : CPL_IGNORE_RET_VAL(oTmpDoc.LoadMemory(osStr));
538 800 : oRet = oTmpDoc.GetRoot();
539 : }
540 809 : return oRet;
541 : }
542 :
543 2742240 : CPLJSONObject::~CPLJSONObject()
544 : {
545 : // Should delete m_poJsonObject only if CPLJSONObject has no parent
546 2742240 : if (m_poJsonObject)
547 : {
548 2315910 : json_object_put(TO_JSONOBJ(m_poJsonObject));
549 2315910 : m_poJsonObject = nullptr;
550 : }
551 2742240 : }
552 :
553 985488 : CPLJSONObject::CPLJSONObject(const CPLJSONObject &other)
554 985488 : : m_poJsonObject(json_object_get(TO_JSONOBJ(other.m_poJsonObject))),
555 985488 : m_osKey(other.m_osKey), m_osKeyForSet(other.m_osKeyForSet)
556 : {
557 985488 : }
558 :
559 304606 : CPLJSONObject::CPLJSONObject(CPLJSONObject &&other)
560 304606 : : m_poJsonObject(other.m_poJsonObject), m_osKey(std::move(other.m_osKey)),
561 304606 : m_osKeyForSet(std::move(other.m_osKeyForSet))
562 : {
563 304606 : other.m_poJsonObject = nullptr;
564 304606 : }
565 :
566 97286 : CPLJSONObject &CPLJSONObject::operator=(const CPLJSONObject &other)
567 : {
568 97286 : if (this == &other)
569 1 : return *this;
570 :
571 97285 : if (!m_osKeyForSet.empty())
572 : {
573 144 : std::string osKeyForSet = m_osKeyForSet;
574 72 : m_osKeyForSet.clear();
575 72 : Set(osKeyForSet, other);
576 : }
577 : else
578 : {
579 97213 : m_osKey = other.m_osKey;
580 97213 : if (m_poJsonObject)
581 96404 : json_object_put(TO_JSONOBJ(m_poJsonObject));
582 97213 : m_poJsonObject = json_object_get(TO_JSONOBJ(other.m_poJsonObject));
583 : }
584 97285 : return *this;
585 : }
586 :
587 12528 : CPLJSONObject &CPLJSONObject::operator=(CPLJSONObject &&other)
588 : {
589 12528 : if (this == &other)
590 0 : return *this;
591 :
592 12528 : if (!m_osKeyForSet.empty())
593 : {
594 431 : if (other.m_poJsonObject)
595 : {
596 431 : json_object_object_add(TO_JSONOBJ(GetInternalHandle()),
597 : m_osKeyForSet.c_str(),
598 431 : TO_JSONOBJ(other.m_poJsonObject));
599 431 : other.m_poJsonObject = nullptr;
600 : }
601 431 : other.m_osKey = INVALID_OBJ_KEY;
602 431 : m_osKeyForSet.clear();
603 : }
604 : else
605 : {
606 12097 : m_osKey = std::move(other.m_osKey);
607 12097 : if (m_poJsonObject)
608 7637 : json_object_put(TO_JSONOBJ(m_poJsonObject));
609 12097 : m_poJsonObject = other.m_poJsonObject;
610 12097 : other.m_poJsonObject = nullptr;
611 : }
612 12528 : return *this;
613 : }
614 :
615 222 : CPLJSONObject &CPLJSONObject::operator=(CPLJSONArray &&other)
616 : {
617 222 : return operator=(static_cast<CPLJSONObject &&>(other));
618 : }
619 :
620 : /*! @endcond */
621 :
622 : /**
623 : * Add new key - value pair to json object.
624 : * @param osName Key name.
625 : * @param osValue String value.
626 : *
627 : * @since GDAL 2.3
628 : */
629 25421 : void CPLJSONObject::Add(const std::string &osName, const std::string &osValue)
630 : {
631 50842 : std::string objectName;
632 25421 : if (m_osKey == INVALID_OBJ_KEY)
633 0 : m_osKey.clear();
634 50842 : CPLJSONObject object = GetObjectByPath(osName, objectName);
635 25421 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
636 : object.m_poJsonObject)) == json_type_object)
637 : {
638 25421 : json_object *poVal = json_object_new_string(osValue.c_str());
639 25421 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
640 : objectName.c_str(), poVal);
641 : }
642 25421 : }
643 :
644 : /**
645 : * Add new key - value pair to json object.
646 : * @param osName Key name.
647 : * @param pszValue String value.
648 : *
649 : * @since GDAL 2.3
650 : */
651 18566 : void CPLJSONObject::Add(const std::string &osName, const char *pszValue)
652 : {
653 18566 : if (nullptr == pszValue)
654 : {
655 2 : return;
656 : }
657 18564 : if (m_osKey == INVALID_OBJ_KEY)
658 0 : m_osKey.clear();
659 37128 : std::string objectName;
660 37128 : CPLJSONObject object = GetObjectByPath(osName, objectName);
661 18564 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
662 : object.m_poJsonObject)) == json_type_object)
663 : {
664 18564 : json_object *poVal = json_object_new_string(pszValue);
665 18564 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
666 : objectName.c_str(), poVal);
667 : }
668 : }
669 :
670 : // defined in ogr/ogrsf_frmts/geojson/ogrgeojsonwriter.cpp
671 : CPL_C_START
672 : /* %.XXXg formatting */
673 : json_object CPL_DLL *
674 : json_object_new_double_with_significant_figures(double dfVal,
675 : int nSignificantFigures);
676 : CPL_C_END
677 :
678 : /**
679 : * Add new key - value pair to json object.
680 : * @param osName Key name.
681 : * @param dfValue Double value.
682 : *
683 : * @since GDAL 2.3
684 : */
685 11437 : void CPLJSONObject::Add(const std::string &osName, double dfValue)
686 : {
687 22874 : std::string objectName;
688 11437 : if (m_osKey == INVALID_OBJ_KEY)
689 0 : m_osKey.clear();
690 22874 : CPLJSONObject object = GetObjectByPath(osName, objectName);
691 11437 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
692 : object.m_poJsonObject)) == json_type_object)
693 : {
694 : json_object *poVal =
695 11437 : json_object_new_double_with_significant_figures(dfValue, -1);
696 11437 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
697 : objectName.c_str(), poVal);
698 : }
699 11437 : }
700 :
701 : /**
702 : * Add new key - value pair to json object.
703 : * @param osName Key name.
704 : * @param nValue Integer value.
705 : *
706 : * @since GDAL 2.3
707 : */
708 16584 : void CPLJSONObject::Add(const std::string &osName, int nValue)
709 : {
710 33168 : std::string objectName;
711 16584 : if (m_osKey == INVALID_OBJ_KEY)
712 0 : m_osKey.clear();
713 33168 : CPLJSONObject object = GetObjectByPath(osName, objectName);
714 16584 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
715 : object.m_poJsonObject)) == json_type_object)
716 : {
717 16584 : json_object *poVal = json_object_new_int(nValue);
718 16584 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
719 : objectName.c_str(), poVal);
720 : }
721 16584 : }
722 :
723 : /**
724 : * Add new key - value pair to json object.
725 : * @param osName Key name.
726 : * @param nValue Long value.
727 : *
728 : * @since GDAL 2.3
729 : */
730 5667 : void CPLJSONObject::Add(const std::string &osName, GInt64 nValue)
731 : {
732 11334 : std::string objectName;
733 5667 : if (m_osKey == INVALID_OBJ_KEY)
734 0 : m_osKey.clear();
735 11334 : CPLJSONObject object = GetObjectByPath(osName, objectName);
736 5667 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
737 : object.m_poJsonObject)) == json_type_object)
738 : {
739 : json_object *poVal =
740 5667 : json_object_new_int64(static_cast<int64_t>(nValue));
741 5667 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
742 : objectName.c_str(), poVal);
743 : }
744 5667 : }
745 :
746 : /**
747 : * Add new key - value pair to json object.
748 : * @param osName Key name.
749 : * @param nValue uint64_t value.
750 : *
751 : * @since GDAL 3.8
752 : */
753 825 : void CPLJSONObject::Add(const std::string &osName, uint64_t nValue)
754 : {
755 1650 : std::string objectName;
756 825 : if (m_osKey == INVALID_OBJ_KEY)
757 0 : m_osKey.clear();
758 1650 : CPLJSONObject object = GetObjectByPath(osName, objectName);
759 825 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
760 : object.m_poJsonObject)) == json_type_object)
761 : {
762 825 : json_object *poVal = json_object_new_uint64(nValue);
763 825 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
764 : objectName.c_str(), poVal);
765 : }
766 825 : }
767 :
768 : /**
769 : * Add new key - value pair to json object.
770 : * @param osName Key name.
771 : * @param oValue Array value.
772 : *
773 : * @since GDAL 2.3
774 : */
775 10021 : void CPLJSONObject::Add(const std::string &osName, const CPLJSONArray &oValue)
776 : {
777 20042 : std::string objectName;
778 10021 : if (m_osKey == INVALID_OBJ_KEY)
779 0 : m_osKey.clear();
780 20042 : CPLJSONObject object = GetObjectByPath(osName, objectName);
781 10021 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
782 : object.m_poJsonObject)) == json_type_object)
783 : {
784 20042 : json_object_object_add(
785 10021 : TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
786 10021 : json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
787 : }
788 10021 : }
789 :
790 : /**
791 : * Add new key - value pair to json object.
792 : * @param osName Key name.
793 : * @param oValue Json object value.
794 : *
795 : * @since GDAL 2.3
796 : */
797 14105 : void CPLJSONObject::Add(const std::string &osName, const CPLJSONObject &oValue)
798 : {
799 14105 : std::string objectName;
800 14105 : if (m_osKey == INVALID_OBJ_KEY)
801 0 : m_osKey.clear();
802 14105 : if (osName.empty())
803 : {
804 28 : json_object_object_add(
805 14 : TO_JSONOBJ(GetInternalHandle()), "",
806 14 : json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
807 14 : return;
808 : }
809 28182 : CPLJSONObject object = GetObjectByPath(osName, objectName);
810 14091 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
811 : object.m_poJsonObject)) == json_type_object)
812 : {
813 28182 : json_object_object_add(
814 14091 : TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
815 14091 : json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
816 : }
817 : }
818 :
819 : /**
820 : * Add new key - value pair to json object.
821 : * @param osName Key name (do not split it on '/')
822 : * @param oValue Json object value.
823 : *
824 : * @since GDAL 3.2
825 : */
826 876 : void CPLJSONObject::AddNoSplitName(const std::string &osName,
827 : const CPLJSONObject &oValue)
828 : {
829 876 : if (m_osKey == INVALID_OBJ_KEY)
830 0 : m_osKey.clear();
831 1752 : if (IsValid() &&
832 876 : json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_object)
833 : {
834 1752 : json_object_object_add(
835 876 : TO_JSONOBJ(GetInternalHandle()), osName.c_str(),
836 876 : json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
837 : }
838 876 : }
839 :
840 : /**
841 : * Add new key - value pair to json object.
842 : * @param osName Key name.
843 : * @param bValue Boolean value.
844 : *
845 : * @since GDAL 2.3
846 : */
847 7731 : void CPLJSONObject::Add(const std::string &osName, bool bValue)
848 : {
849 15462 : std::string objectName;
850 7731 : if (m_osKey == INVALID_OBJ_KEY)
851 0 : m_osKey.clear();
852 15462 : CPLJSONObject object = GetObjectByPath(osName, objectName);
853 7731 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
854 : object.m_poJsonObject)) == json_type_object)
855 : {
856 7731 : json_object *poVal = json_object_new_boolean(bValue);
857 7731 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
858 : objectName.c_str(), poVal);
859 : }
860 7731 : }
861 :
862 : /**
863 : * Add new key - null pair to json object.
864 : * @param osName Key name.
865 : *
866 : * @since GDAL 2.3
867 : */
868 11403 : void CPLJSONObject::AddNull(const std::string &osName)
869 : {
870 22806 : std::string objectName;
871 11403 : if (m_osKey == INVALID_OBJ_KEY)
872 0 : m_osKey.clear();
873 22806 : CPLJSONObject object = GetObjectByPath(osName, objectName);
874 11403 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
875 : object.m_poJsonObject)) == json_type_object)
876 : {
877 11403 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
878 : objectName.c_str(), nullptr);
879 : }
880 11403 : }
881 :
882 : /**
883 : * Change value by key.
884 : * @param osName Key name.
885 : *
886 : * @since GDAL 2.3
887 : */
888 14 : void CPLJSONObject::SetNull(const std::string &osName)
889 : {
890 14 : Delete(osName);
891 14 : AddNull(osName);
892 14 : }
893 :
894 : /**
895 : * Get value by key.
896 : * @param osName Key name.
897 : * @return Json array object.
898 : *
899 : * @since GDAL 2.3
900 : */
901 109612 : CPLJSONArray CPLJSONObject::GetArray(const std::string &osName) const
902 : {
903 219224 : std::string objectName;
904 219224 : CPLJSONObject object = GetObjectByPath(osName, objectName);
905 109612 : if (object.IsValid())
906 : {
907 109612 : json_object *poVal = nullptr;
908 109612 : if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
909 109612 : objectName.c_str(), &poVal))
910 : {
911 61538 : if (poVal && json_object_get_type(poVal) == json_type_array)
912 : {
913 61495 : return CPLJSONArray(objectName, poVal);
914 : }
915 : }
916 : }
917 48117 : return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
918 : }
919 :
920 : /**
921 : * Get value by key.
922 : * @param osName Key name.
923 : * @return Json object.
924 : *
925 : * @since GDAL 2.3
926 : */
927 685552 : CPLJSONObject CPLJSONObject::GetObj(const std::string &osName) const
928 : {
929 1371100 : std::string objectName;
930 1371100 : CPLJSONObject object = GetObjectByPath(osName, objectName);
931 685552 : if (object.IsValid())
932 : {
933 684722 : json_object *poVal = nullptr;
934 684722 : if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
935 684722 : objectName.c_str(), &poVal))
936 : {
937 632349 : return CPLJSONObject(objectName, poVal);
938 : }
939 : }
940 53203 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
941 : }
942 :
943 : /**
944 : * Get value by key.
945 : * @param osName Key name.
946 : * @return Json object.
947 : *
948 : * @since GDAL 2.3
949 : */
950 90833 : CPLJSONObject CPLJSONObject::operator[](const std::string &osName) const
951 : {
952 90833 : return GetObj(osName);
953 : }
954 :
955 : /** Change value by key.
956 : *
957 : * e.g.: ``oObj["type"] = "MyType"``
958 : *
959 : * @since 3.12
960 : */
961 17110 : CPLJSONObject CPLJSONObject::operator[](const std::string &osName)
962 : {
963 34220 : auto oObj = GetObj(osName);
964 17110 : if (oObj.IsValid())
965 4004 : return oObj;
966 26212 : CPLJSONObject oClone(*this);
967 13106 : oClone.m_osKey = INVALID_OBJ_KEY;
968 13106 : oClone.m_osKeyForSet = osName;
969 13106 : return oClone;
970 : }
971 :
972 : /**
973 : * Delete json object by key.
974 : * @param osName Key name.
975 : *
976 : * @since GDAL 2.3
977 : */
978 11974 : void CPLJSONObject::Delete(const std::string &osName)
979 : {
980 23948 : std::string objectName;
981 11974 : if (m_osKey == INVALID_OBJ_KEY)
982 1366 : m_osKey.clear();
983 23948 : CPLJSONObject object = GetObjectByPath(osName, objectName);
984 11974 : if (object.IsValid())
985 : {
986 11974 : json_object_object_del(TO_JSONOBJ(object.GetInternalHandle()),
987 : objectName.c_str());
988 : }
989 11974 : }
990 :
991 : /**
992 : * Delete json object by key (without splitting on /)
993 : * @param osName Key name.
994 : *
995 : * @since GDAL 3.4
996 : */
997 889 : void CPLJSONObject::DeleteNoSplitName(const std::string &osName)
998 : {
999 889 : if (m_osKey == INVALID_OBJ_KEY)
1000 0 : m_osKey.clear();
1001 889 : if (m_poJsonObject)
1002 : {
1003 889 : json_object_object_del(TO_JSONOBJ(m_poJsonObject), osName.c_str());
1004 : }
1005 889 : }
1006 :
1007 : /**
1008 : * Get value by key.
1009 : * @param osName Key name.
1010 : * @param osDefault Default value.
1011 : * @return String value.
1012 : *
1013 : * @since GDAL 2.3
1014 : */
1015 291729 : std::string CPLJSONObject::GetString(const std::string &osName,
1016 : const std::string &osDefault) const
1017 : {
1018 291729 : if (!m_osKeyForSet.empty())
1019 0 : return osDefault;
1020 583458 : CPLJSONObject object = GetObj(osName);
1021 291729 : return object.ToString(osDefault);
1022 : }
1023 :
1024 : /**
1025 : * Get value.
1026 : * @param osDefault Default value.
1027 : * @return String value.
1028 : *
1029 : * @since GDAL 2.3
1030 : */
1031 444292 : std::string CPLJSONObject::ToString(const std::string &osDefault) const
1032 : {
1033 444292 : if (!m_osKeyForSet.empty())
1034 151 : return osDefault;
1035 444141 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1036 : json_type_string*/ )
1037 : {
1038 : const char *pszString =
1039 425999 : json_object_get_string(TO_JSONOBJ(m_poJsonObject));
1040 425999 : if (nullptr != pszString)
1041 : {
1042 425999 : return pszString;
1043 : }
1044 : }
1045 18142 : return osDefault;
1046 : }
1047 :
1048 : /**
1049 : * Get value by key.
1050 : * @param osName Key name.
1051 : * @param dfDefault Default value.
1052 : * @return Double value.
1053 : *
1054 : * @since GDAL 2.3
1055 : */
1056 48076 : double CPLJSONObject::GetDouble(const std::string &osName,
1057 : double dfDefault) const
1058 : {
1059 48076 : if (!m_osKeyForSet.empty())
1060 0 : return dfDefault;
1061 96152 : CPLJSONObject object = GetObj(osName);
1062 48076 : return object.ToDouble(dfDefault);
1063 : }
1064 :
1065 : /**
1066 : * Get value
1067 : * @param dfDefault Default value.
1068 : * @return Double value.
1069 : *
1070 : * @since GDAL 2.3
1071 : */
1072 150438 : double CPLJSONObject::ToDouble(double dfDefault) const
1073 : {
1074 150438 : if (!m_osKeyForSet.empty())
1075 0 : return dfDefault;
1076 150438 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1077 : json_type_double*/ )
1078 149777 : return json_object_get_double(TO_JSONOBJ(m_poJsonObject));
1079 661 : return dfDefault;
1080 : }
1081 :
1082 : /**
1083 : * Get value by key.
1084 : * @param osName Key name.
1085 : * @param nDefault Default value.
1086 : * @return Integer value.
1087 : *
1088 : * @since GDAL 2.3
1089 : */
1090 191053 : int CPLJSONObject::GetInteger(const std::string &osName, int nDefault) const
1091 : {
1092 191053 : if (!m_osKeyForSet.empty())
1093 0 : return nDefault;
1094 382106 : CPLJSONObject object = GetObj(osName);
1095 191053 : return object.ToInteger(nDefault);
1096 : }
1097 :
1098 : /**
1099 : * Get value.
1100 : * @param nDefault Default value.
1101 : * @return Integer value.
1102 : *
1103 : * @since GDAL 2.3
1104 : */
1105 192815 : int CPLJSONObject::ToInteger(int nDefault) const
1106 : {
1107 192815 : if (!m_osKeyForSet.empty())
1108 0 : return nDefault;
1109 192815 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1110 : json_type_int*/ )
1111 191952 : return json_object_get_int(TO_JSONOBJ(m_poJsonObject));
1112 863 : return nDefault;
1113 : }
1114 :
1115 : /**
1116 : * Get value by key.
1117 : * @param osName Key name.
1118 : * @param nDefault Default value.
1119 : * @return Long value.
1120 : *
1121 : * @since GDAL 2.3
1122 : */
1123 126 : GInt64 CPLJSONObject::GetLong(const std::string &osName, GInt64 nDefault) const
1124 : {
1125 126 : if (!m_osKeyForSet.empty())
1126 0 : return nDefault;
1127 252 : CPLJSONObject object = GetObj(osName);
1128 126 : return object.ToLong(nDefault);
1129 : }
1130 :
1131 : /**
1132 : * Get value.
1133 : * @param nDefault Default value.
1134 : * @return Long value.
1135 : *
1136 : * @since GDAL 2.3
1137 : */
1138 2841 : GInt64 CPLJSONObject::ToLong(GInt64 nDefault) const
1139 : {
1140 2841 : if (!m_osKeyForSet.empty())
1141 0 : return nDefault;
1142 2841 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1143 : json_type_int*/ )
1144 : return static_cast<GInt64>(
1145 2768 : json_object_get_int64(TO_JSONOBJ(m_poJsonObject)));
1146 73 : return nDefault;
1147 : }
1148 :
1149 : /**
1150 : * Get value by key.
1151 : * @param osName Key name.
1152 : * @param bDefault Default value.
1153 : * @return Boolean value.
1154 : *
1155 : * @since GDAL 2.3
1156 : */
1157 104 : bool CPLJSONObject::GetBool(const std::string &osName, bool bDefault) const
1158 : {
1159 104 : if (!m_osKeyForSet.empty())
1160 0 : return bDefault;
1161 208 : CPLJSONObject object = GetObj(osName);
1162 104 : return object.ToBool(bDefault);
1163 : }
1164 :
1165 : /**
1166 : * \brief Get json object children.
1167 : *
1168 : * This function is useful when keys is not know and need to
1169 : * iterate over json object items and get keys and values.
1170 : *
1171 : * @return Array of CPLJSONObject class instance.
1172 : *
1173 : * @since GDAL 2.3
1174 : */
1175 12539 : std::vector<CPLJSONObject> CPLJSONObject::GetChildren() const
1176 : {
1177 12539 : std::vector<CPLJSONObject> aoChildren;
1178 12539 : if (!m_osKeyForSet.empty())
1179 0 : return aoChildren;
1180 25078 : if (nullptr == m_poJsonObject ||
1181 12539 : json_object_get_type(TO_JSONOBJ(m_poJsonObject)) != json_type_object)
1182 : {
1183 1 : return aoChildren;
1184 : }
1185 :
1186 : json_object_iter it;
1187 12538 : it.key = nullptr;
1188 12538 : it.val = nullptr;
1189 12538 : it.entry = nullptr;
1190 : // cppcheck-suppress cstyleCast
1191 60519 : json_object_object_foreachC(TO_JSONOBJ(m_poJsonObject), it)
1192 : {
1193 47981 : aoChildren.push_back(CPLJSONObject(it.key, it.val));
1194 : }
1195 :
1196 12538 : return aoChildren;
1197 : }
1198 :
1199 : /**
1200 : * Get value.
1201 : * @param bDefault Default value.
1202 : * @return Boolean value.
1203 : *
1204 : * @since GDAL 2.3
1205 : */
1206 120 : bool CPLJSONObject::ToBool(bool bDefault) const
1207 : {
1208 120 : if (!m_osKeyForSet.empty())
1209 0 : return bDefault;
1210 120 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1211 : json_type_boolean*/ )
1212 40 : return json_object_get_boolean(TO_JSONOBJ(m_poJsonObject)) == 1;
1213 80 : return bDefault;
1214 : }
1215 :
1216 : /**
1217 : * Get value.
1218 : * @return Array
1219 : *
1220 : * @since GDAL 2.3
1221 : */
1222 8570 : CPLJSONArray CPLJSONObject::ToArray() const
1223 : {
1224 16198 : if (m_osKeyForSet.empty() && m_poJsonObject &&
1225 7628 : json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_array)
1226 7624 : return CPLJSONArray("", TO_JSONOBJ(m_poJsonObject));
1227 946 : return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
1228 : }
1229 :
1230 : /**
1231 : * Stringify object to json format.
1232 : * @param eFormat Format type,
1233 : * @return A string in JSON format.
1234 : *
1235 : * @since GDAL 2.3
1236 : */
1237 28129 : std::string CPLJSONObject::Format(PrettyFormat eFormat) const
1238 : {
1239 28129 : if (m_poJsonObject)
1240 : {
1241 28129 : const char *pszFormatString = nullptr;
1242 28129 : switch (eFormat)
1243 : {
1244 1 : case PrettyFormat::Spaced:
1245 2 : pszFormatString = json_object_to_json_string_ext(
1246 1 : TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_SPACED);
1247 1 : break;
1248 232 : case PrettyFormat::Pretty:
1249 464 : pszFormatString = json_object_to_json_string_ext(
1250 232 : TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PRETTY);
1251 232 : break;
1252 27896 : default:
1253 27896 : pszFormatString = json_object_to_json_string_ext(
1254 27896 : TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PLAIN);
1255 : }
1256 28129 : if (nullptr != pszFormatString)
1257 : {
1258 28129 : return pszFormatString;
1259 : }
1260 : }
1261 0 : return "";
1262 : }
1263 :
1264 : /*! @cond Doxygen_Suppress */
1265 928882 : CPLJSONObject CPLJSONObject::GetObjectByPath(const std::string &osPath,
1266 : std::string &osName) const
1267 : {
1268 928882 : json_object *poVal = nullptr;
1269 :
1270 : // Typically for keys that contain / character
1271 928882 : if (json_object_object_get_ex(TO_JSONOBJ(GetInternalHandle()),
1272 928882 : osPath.c_str(), &poVal))
1273 : {
1274 694315 : osName = osPath;
1275 694315 : return *this;
1276 : }
1277 :
1278 : CPLStringList pathPortions(
1279 469134 : CSLTokenizeString2(osPath.c_str(), JSON_PATH_DELIMITER, 0));
1280 234567 : int portionsCount = pathPortions.size();
1281 234567 : if (portionsCount > 100)
1282 : {
1283 0 : CPLError(CE_Failure, CPLE_NotSupported, "Too many components in path");
1284 0 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1285 : }
1286 234567 : if (0 == portionsCount)
1287 0 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1288 469134 : CPLJSONObject object = *this;
1289 236907 : for (int i = 0; i < portionsCount - 1; ++i)
1290 : {
1291 : // TODO: check array index in path - i.e.
1292 : // settings/catalog/root/id:1/name if EQUALN(pathPortions[i+1], "id:",
1293 : // 3) -> getArray
1294 2340 : if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
1295 4680 : pathPortions[i], &poVal))
1296 : {
1297 1519 : object = CPLJSONObject(pathPortions[i], poVal);
1298 : }
1299 : else
1300 : {
1301 821 : if (json_object_get_type(TO_JSONOBJ(object.m_poJsonObject)) !=
1302 : json_type_object)
1303 : {
1304 0 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1305 : }
1306 821 : object = CPLJSONObject(pathPortions[i], object);
1307 : }
1308 : }
1309 :
1310 : // // Check if such object already exists
1311 : // if(json_object_object_get_ex(object.m_jsonObject,
1312 : // pathPortions[portionsCount - 1], &poVal))
1313 : // return JSONObject(nullptr);
1314 : //
1315 234567 : osName = pathPortions[portionsCount - 1];
1316 234567 : return object;
1317 : }
1318 :
1319 : /*! @endcond */
1320 :
1321 : /**
1322 : * Get json object type.
1323 : * @return Json object type.
1324 : *
1325 : * @since GDAL 2.3
1326 : */
1327 91029 : CPLJSONObject::Type CPLJSONObject::GetType() const
1328 : {
1329 91029 : if (!m_osKeyForSet.empty())
1330 5162 : return CPLJSONObject::Type::Unknown;
1331 :
1332 85867 : if (nullptr == m_poJsonObject)
1333 : {
1334 8023 : if (m_osKey == INVALID_OBJ_KEY)
1335 4184 : return CPLJSONObject::Type::Unknown;
1336 3839 : return CPLJSONObject::Type::Null;
1337 : }
1338 77844 : auto jsonObj(TO_JSONOBJ(m_poJsonObject));
1339 77844 : switch (json_object_get_type(jsonObj))
1340 : {
1341 21 : case json_type_boolean:
1342 21 : return CPLJSONObject::Type::Boolean;
1343 3017 : case json_type_double:
1344 3017 : return CPLJSONObject::Type::Double;
1345 15448 : case json_type_int:
1346 : {
1347 15448 : if (CPL_INT64_FITS_ON_INT32(json_object_get_int64(jsonObj)))
1348 15330 : return CPLJSONObject::Type::Integer;
1349 : else
1350 118 : return CPLJSONObject::Type::Long;
1351 : }
1352 9938 : case json_type_object:
1353 9938 : return CPLJSONObject::Type::Object;
1354 5757 : case json_type_array:
1355 5757 : return CPLJSONObject::Type::Array;
1356 43663 : case json_type_string:
1357 43663 : return CPLJSONObject::Type::String;
1358 0 : default:
1359 0 : break;
1360 : }
1361 0 : return CPLJSONObject::Type::Unknown;
1362 : }
1363 :
1364 : /**
1365 : * Check if json object valid.
1366 : * @return true if json object valid.
1367 : *
1368 : * @since GDAL 2.3
1369 : */
1370 1097510 : bool CPLJSONObject::IsValid() const
1371 : {
1372 1097510 : return m_osKeyForSet.empty() && m_osKey != INVALID_OBJ_KEY;
1373 : }
1374 :
1375 : /**
1376 : * Decrement reference counter and make pointer NULL.
1377 : * A json object will become invalid.
1378 : *
1379 : * @since GDAL 2.3
1380 : */
1381 8807 : void CPLJSONObject::Deinit()
1382 : {
1383 8807 : if (m_poJsonObject)
1384 : {
1385 6608 : json_object_put(TO_JSONOBJ(m_poJsonObject));
1386 6608 : m_poJsonObject = nullptr;
1387 : }
1388 8807 : m_osKey = INVALID_OBJ_KEY;
1389 8807 : }
1390 :
1391 : //------------------------------------------------------------------------------
1392 : // JSONArray
1393 : //------------------------------------------------------------------------------
1394 : /*! @cond Doxygen_Suppress */
1395 37028 : CPLJSONArray::CPLJSONArray()
1396 : {
1397 37028 : json_object_put(TO_JSONOBJ(m_poJsonObject));
1398 37028 : m_poJsonObject = json_object_new_array();
1399 37028 : }
1400 :
1401 1 : CPLJSONArray::CPLJSONArray(const std::string &osName)
1402 1 : : CPLJSONObject(osName, json_object_new_array())
1403 : {
1404 1 : json_object_put(TO_JSONOBJ(m_poJsonObject));
1405 1 : }
1406 :
1407 118520 : CPLJSONArray::CPLJSONArray(const std::string &osName, JSONObjectH poJsonObject)
1408 118520 : : CPLJSONObject(osName, poJsonObject)
1409 : {
1410 118520 : }
1411 :
1412 9 : CPLJSONArray::CPLJSONArray(const CPLJSONObject &other) : CPLJSONObject(other)
1413 : {
1414 9 : }
1415 :
1416 : /*! @endcond */
1417 :
1418 : /**
1419 : * Get array size.
1420 : * @return Array size.
1421 : *
1422 : * @since GDAL 2.3
1423 : */
1424 322504 : int CPLJSONArray::Size() const
1425 : {
1426 322504 : if (m_poJsonObject)
1427 : return static_cast<int>(
1428 320334 : json_object_array_length(TO_JSONOBJ(m_poJsonObject)));
1429 2170 : return 0;
1430 : }
1431 :
1432 : /**
1433 : * Add null object to array.
1434 : *
1435 : * @since GDAL 3.8
1436 : */
1437 2365 : void CPLJSONArray::AddNull()
1438 : {
1439 2365 : if (m_poJsonObject)
1440 2365 : json_object_array_add(TO_JSONOBJ(m_poJsonObject), nullptr);
1441 2365 : }
1442 :
1443 : /**
1444 : * Add json object to array.
1445 : * @param oValue Json array.
1446 : *
1447 : * @since GDAL 2.3
1448 : */
1449 10079 : void CPLJSONArray::Add(const CPLJSONObject &oValue)
1450 : {
1451 10079 : if (m_poJsonObject && oValue.m_poJsonObject)
1452 20158 : json_object_array_add(
1453 10079 : TO_JSONOBJ(m_poJsonObject),
1454 10079 : json_object_get(TO_JSONOBJ(oValue.m_poJsonObject)));
1455 10079 : }
1456 :
1457 : /**
1458 : * Add value to array
1459 : * @param osValue Value to add.
1460 : *
1461 : * @since GDAL 2.3
1462 : */
1463 11832 : void CPLJSONArray::Add(const std::string &osValue)
1464 : {
1465 11832 : if (m_poJsonObject)
1466 11832 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1467 : json_object_new_string(osValue.c_str()));
1468 11832 : }
1469 :
1470 : /**
1471 : * Add value to array
1472 : * @param pszValue Value to add.
1473 : *
1474 : * @since GDAL 2.3
1475 : */
1476 5702 : void CPLJSONArray::Add(const char *pszValue)
1477 : {
1478 5702 : if (nullptr == pszValue)
1479 0 : return;
1480 5702 : if (m_poJsonObject)
1481 5702 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1482 : json_object_new_string(pszValue));
1483 : }
1484 :
1485 : /**
1486 : * Add value to array
1487 : * @param dfValue Value to add.
1488 : *
1489 : * @since GDAL 2.3
1490 : */
1491 3087 : void CPLJSONArray::Add(double dfValue)
1492 : {
1493 3087 : if (m_poJsonObject)
1494 3087 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1495 : json_object_new_double(dfValue));
1496 3087 : }
1497 :
1498 : /**
1499 : * Add value to array
1500 : * @param nValue Value to add.
1501 : *
1502 : * @since GDAL 2.3
1503 : */
1504 393 : void CPLJSONArray::Add(int nValue)
1505 : {
1506 393 : if (m_poJsonObject)
1507 393 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1508 : json_object_new_int(nValue));
1509 393 : }
1510 :
1511 : /**
1512 : * Add value to array
1513 : * @param nValue Value to add.
1514 : *
1515 : * @since GDAL 2.3
1516 : */
1517 1474 : void CPLJSONArray::Add(GInt64 nValue)
1518 : {
1519 1474 : if (m_poJsonObject)
1520 1474 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1521 : json_object_new_int64(nValue));
1522 1474 : }
1523 :
1524 : /**
1525 : * Add value to array
1526 : * @param nValue Value to add.
1527 : *
1528 : * @since GDAL 3.8
1529 : */
1530 40 : void CPLJSONArray::Add(uint64_t nValue)
1531 : {
1532 40 : if (m_poJsonObject)
1533 : {
1534 40 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1535 : json_object_new_uint64(nValue));
1536 : }
1537 40 : }
1538 :
1539 : /**
1540 : * Add value to array
1541 : * @param bValue Value to add.
1542 : *
1543 : * @since GDAL 2.3
1544 : */
1545 18 : void CPLJSONArray::Add(bool bValue)
1546 : {
1547 18 : if (m_poJsonObject)
1548 18 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1549 : json_object_new_boolean(bValue));
1550 18 : }
1551 :
1552 : /**
1553 : * Get array item by index.
1554 : * @param nIndex Item index.
1555 : * @return Json object.
1556 : *
1557 : * @since GDAL 2.3
1558 : */
1559 3128 : CPLJSONObject CPLJSONArray::operator[](int nIndex)
1560 : {
1561 : return CPLJSONObject(
1562 : CPLSPrintf("id:%d", nIndex),
1563 3128 : json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
1564 : }
1565 :
1566 : /**
1567 : * Get array const item by index.
1568 : * @param nIndex Item index.
1569 : * @return Json object.
1570 : *
1571 : * @since GDAL 2.3
1572 : */
1573 430152 : const CPLJSONObject CPLJSONArray::operator[](int nIndex) const
1574 : {
1575 : return CPLJSONObject(
1576 : CPLSPrintf("id:%d", nIndex),
1577 430152 : json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
1578 : }
1579 :
1580 : /************************************************************************/
1581 : /* CPLParseKeyValueJson() */
1582 : /************************************************************************/
1583 :
1584 : /** Return a string list of key/value pairs extracted from a JSON doc.
1585 :
1586 : We are expecting simple documents with key:value pairs, like the
1587 : following with no hierarchy or complex structure.
1588 : \verbatim
1589 : {
1590 : "Code" : "Success",
1591 : "LastUpdated" : "2017-07-03T16:20:17Z",
1592 : "Type" : "AWS-HMAC",
1593 : "AccessKeyId" : "bla",
1594 : "SecretAccessKey" : "bla",
1595 : "Token" : "bla",
1596 : "Expiration" : "2017-07-03T22:42:58Z"
1597 : }
1598 : \endverbatim
1599 : @since GDAL 3.7
1600 : */
1601 37 : CPLStringList CPLParseKeyValueJson(const char *pszJson)
1602 : {
1603 74 : CPLJSONDocument oDoc;
1604 37 : CPLStringList oNameValue;
1605 37 : if (pszJson != nullptr && oDoc.LoadMemory(pszJson))
1606 : {
1607 134 : for (const auto &obj : oDoc.GetRoot().GetChildren())
1608 : {
1609 97 : const auto eType = obj.GetType();
1610 97 : if (eType == CPLJSONObject::Type::String ||
1611 0 : eType == CPLJSONObject::Type::Integer ||
1612 : eType == CPLJSONObject::Type::Double)
1613 : {
1614 194 : oNameValue.SetNameValue(obj.GetName().c_str(),
1615 291 : obj.ToString().c_str());
1616 : }
1617 : }
1618 : }
1619 74 : return oNameValue;
1620 : }
|