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