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 17826 : CPLJSONDocument::CPLJSONDocument() : m_poRootJsonObject(nullptr)
59 : {
60 17826 : }
61 :
62 35666 : CPLJSONDocument::~CPLJSONDocument()
63 : {
64 17833 : if (m_poRootJsonObject)
65 12997 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
66 17833 : }
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 1367 : bool CPLJSONDocument::Save(const std::string &osPath) const
114 : {
115 1367 : VSILFILE *fp = VSIFOpenL(osPath.c_str(), "wt");
116 1367 : 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 2706 : const char *pabyData = json_object_to_json_string_ext(
124 1353 : TO_JSONOBJ(m_poRootJsonObject), JSON_C_TO_STRING_PRETTY);
125 1353 : bool bRet = VSIFWriteL(pabyData, strlen(pabyData), 1, fp) == 1;
126 :
127 1353 : bRet = VSIFCloseL(fp) == 0 && bRet;
128 :
129 1353 : return bRet;
130 : }
131 :
132 : /**
133 : * Return the json document as a serialized string.
134 : * @return serialized document.
135 : *
136 : */
137 2163 : std::string CPLJSONDocument::SaveAsString() const
138 : {
139 2163 : return json_object_to_json_string_ext(TO_JSONOBJ(m_poRootJsonObject),
140 2163 : 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 19211 : CPLJSONObject CPLJSONDocument::GetRoot()
160 : {
161 19211 : if (nullptr == m_poRootJsonObject)
162 : {
163 1535 : m_poRootJsonObject = json_object_new_object();
164 : }
165 :
166 19211 : if (json_object_get_type(TO_JSONOBJ(m_poRootJsonObject)) == json_type_array)
167 : {
168 680 : return CPLJSONArray("", m_poRootJsonObject);
169 : }
170 : else
171 : {
172 18871 : 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 2163 : void CPLJSONDocument::SetRoot(const CPLJSONObject &oRoot)
183 : {
184 2163 : if (m_poRootJsonObject)
185 0 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
186 2163 : m_poRootJsonObject = json_object_get(TO_JSONOBJ(oRoot.m_poJsonObject));
187 2163 : }
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 6205 : bool CPLJSONDocument::Load(const std::string &osPath)
197 : {
198 6205 : GByte *pabyOut = nullptr;
199 6205 : vsi_l_offset nSize = 0;
200 :
201 6205 : GIntBig nMaxSize = 0;
202 6205 : if (CPLParseMemorySize(CPLGetConfigOption("CPL_JSON_MAX_SIZE", "100MB"),
203 12410 : &nMaxSize, nullptr) != CE_None ||
204 6205 : nMaxSize <= 0)
205 0 : return false;
206 :
207 6205 : if (!VSIIngestFile(nullptr, osPath.c_str(), &pabyOut, &nSize, nMaxSize))
208 : {
209 816 : CPLError(CE_Failure, CPLE_FileIO, "Load json file %s failed",
210 : osPath.c_str());
211 816 : return false;
212 : }
213 :
214 5389 : bool bResult = LoadMemory(pabyOut, static_cast<int>(nSize));
215 5389 : VSIFree(pabyOut);
216 5389 : 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 10929 : bool CPLJSONDocument::LoadMemory(const GByte *pabyData, int nLength)
228 : {
229 10929 : if (nullptr == pabyData)
230 : {
231 1 : return false;
232 : }
233 :
234 10928 : if (m_poRootJsonObject)
235 1587 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
236 :
237 10928 : 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 10923 : if (nLength == 5 &&
245 5 : 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 10920 : json_tokener *jstok = json_tokener_new();
252 10920 : m_poRootJsonObject = json_tokener_parse_ex(
253 : jstok, reinterpret_cast<const char *>(pabyData), nLength);
254 10920 : bool bParsed = jstok->err == json_tokener_success;
255 10920 : if (!bParsed)
256 : {
257 25 : CPLError(CE_Failure, CPLE_AppDefined,
258 : "JSON parsing error: %s (at offset %d)",
259 : json_tokener_error_desc(jstok->err), jstok->char_offset);
260 25 : json_tokener_free(jstok);
261 25 : return false;
262 : }
263 10895 : json_tokener_free(jstok);
264 10895 : 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 5437 : bool CPLJSONDocument::LoadMemory(const std::string &osStr)
275 : {
276 5437 : if (osStr.empty())
277 3 : return false;
278 5434 : return LoadMemory(reinterpret_cast<const GByte *>(osStr.data()),
279 10868 : 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 151714 : CPLJSONObject::CPLJSONObject() : m_poJsonObject(json_object_new_object())
465 : {
466 151714 : }
467 :
468 1 : CPLJSONObject::CPLJSONObject(std::nullptr_t) : m_poJsonObject(nullptr)
469 : {
470 1 : }
471 :
472 1 : CPLJSONObject::CPLJSONObject(const std::string &osVal)
473 1 : : m_poJsonObject(json_object_new_string(osVal.c_str()))
474 : {
475 1 : }
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 1 : CPLJSONObject::CPLJSONObject(int nVal)
488 1 : : m_poJsonObject(json_object_new_int(nVal))
489 : {
490 1 : }
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 1 : CPLJSONObject::CPLJSONObject(double dfVal)
503 1 : : m_poJsonObject(json_object_new_double(dfVal))
504 : {
505 1 : }
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 1433540 : CPLJSONObject::CPLJSONObject(const std::string &osName,
516 1433540 : JSONObjectH poJsonObject)
517 1433540 : : m_poJsonObject(json_object_get(TO_JSONOBJ(poJsonObject))), m_osKey(osName)
518 : {
519 1433540 : }
520 :
521 813 : CPLJSONObject CPLJSONObject::Clone() const
522 : {
523 813 : CPLJSONObject oRet;
524 813 : if (IsValid())
525 : {
526 1604 : CPLJSONDocument oTmpDoc;
527 802 : oTmpDoc.SetRoot(*this);
528 802 : std::string osStr = oTmpDoc.SaveAsString();
529 802 : CPL_IGNORE_RET_VAL(oTmpDoc.LoadMemory(osStr));
530 802 : oRet = oTmpDoc.GetRoot();
531 : }
532 813 : return oRet;
533 : }
534 :
535 2980800 : CPLJSONObject::~CPLJSONObject()
536 : {
537 : // Should delete m_poJsonObject only if CPLJSONObject has no parent
538 2980800 : if (m_poJsonObject)
539 : {
540 2519240 : json_object_put(TO_JSONOBJ(m_poJsonObject));
541 2519240 : m_poJsonObject = nullptr;
542 : }
543 2980800 : }
544 :
545 1064190 : CPLJSONObject::CPLJSONObject(const CPLJSONObject &other)
546 1064190 : : m_poJsonObject(json_object_get(TO_JSONOBJ(other.m_poJsonObject))),
547 1064190 : m_osKey(other.m_osKey), m_osKeyForSet(other.m_osKeyForSet)
548 : {
549 1064190 : }
550 :
551 330514 : CPLJSONObject::CPLJSONObject(CPLJSONObject &&other)
552 330514 : : m_poJsonObject(other.m_poJsonObject), m_osKey(std::move(other.m_osKey)),
553 330514 : m_osKeyForSet(std::move(other.m_osKeyForSet))
554 : {
555 330514 : other.m_poJsonObject = nullptr;
556 330514 : }
557 :
558 102609 : CPLJSONObject &CPLJSONObject::operator=(const CPLJSONObject &other)
559 : {
560 102609 : if (this == &other)
561 1 : return *this;
562 :
563 102608 : if (!m_osKeyForSet.empty())
564 : {
565 240 : std::string osKeyForSet = m_osKeyForSet;
566 120 : m_osKeyForSet.clear();
567 120 : Set(osKeyForSet, other);
568 : }
569 : else
570 : {
571 102488 : m_osKey = other.m_osKey;
572 102488 : if (m_poJsonObject)
573 101668 : json_object_put(TO_JSONOBJ(m_poJsonObject));
574 102488 : m_poJsonObject = json_object_get(TO_JSONOBJ(other.m_poJsonObject));
575 : }
576 102608 : return *this;
577 : }
578 :
579 12716 : CPLJSONObject &CPLJSONObject::operator=(CPLJSONObject &&other)
580 : {
581 12716 : if (this == &other)
582 0 : return *this;
583 :
584 12716 : if (!m_osKeyForSet.empty())
585 : {
586 677 : if (other.m_poJsonObject)
587 : {
588 677 : json_object_object_add(TO_JSONOBJ(GetInternalHandle()),
589 : m_osKeyForSet.c_str(),
590 677 : TO_JSONOBJ(other.m_poJsonObject));
591 677 : other.m_poJsonObject = nullptr;
592 : }
593 677 : other.m_osKey = INVALID_OBJ_KEY;
594 677 : m_osKeyForSet.clear();
595 : }
596 : else
597 : {
598 12039 : m_osKey = std::move(other.m_osKey);
599 12039 : if (m_poJsonObject)
600 7494 : json_object_put(TO_JSONOBJ(m_poJsonObject));
601 12039 : m_poJsonObject = other.m_poJsonObject;
602 12039 : other.m_poJsonObject = nullptr;
603 : }
604 12716 : return *this;
605 : }
606 :
607 337 : CPLJSONObject &CPLJSONObject::operator=(CPLJSONArray &&other)
608 : {
609 337 : 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 29595 : void CPLJSONObject::Add(const std::string &osName, const std::string &osValue)
621 : {
622 59190 : std::string objectName;
623 29595 : if (m_osKey == INVALID_OBJ_KEY)
624 0 : m_osKey.clear();
625 59190 : CPLJSONObject object = GetObjectByPath(osName, objectName);
626 29595 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
627 : object.m_poJsonObject)) == json_type_object)
628 : {
629 29595 : json_object *poVal = json_object_new_string(osValue.c_str());
630 29595 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
631 : objectName.c_str(), poVal);
632 : }
633 29595 : }
634 :
635 : /**
636 : * Add new key - value pair to json object.
637 : * @param osName Key name.
638 : * @param pszValue String value.
639 : *
640 : */
641 20449 : void CPLJSONObject::Add(const std::string &osName, const char *pszValue)
642 : {
643 20449 : if (nullptr == pszValue)
644 : {
645 2 : return;
646 : }
647 20447 : if (m_osKey == INVALID_OBJ_KEY)
648 0 : m_osKey.clear();
649 40894 : std::string objectName;
650 40894 : CPLJSONObject object = GetObjectByPath(osName, objectName);
651 20447 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
652 : object.m_poJsonObject)) == json_type_object)
653 : {
654 20447 : json_object *poVal = json_object_new_string(pszValue);
655 20447 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
656 : objectName.c_str(), poVal);
657 : }
658 : }
659 :
660 : // defined in ogr/ogrsf_frmts/geojson/ogrgeojsonwriter.cpp
661 : CPL_C_START
662 : /* %.XXXg formatting */
663 : json_object CPL_DLL *
664 : json_object_new_double_with_significant_figures(double dfVal,
665 : int nSignificantFigures);
666 : CPL_C_END
667 :
668 : /**
669 : * Add new key - value pair to json object.
670 : * @param osName Key name.
671 : * @param dfValue Double value.
672 : *
673 : */
674 11675 : void CPLJSONObject::Add(const std::string &osName, double dfValue)
675 : {
676 23350 : std::string objectName;
677 11675 : if (m_osKey == INVALID_OBJ_KEY)
678 0 : m_osKey.clear();
679 23350 : CPLJSONObject object = GetObjectByPath(osName, objectName);
680 11675 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
681 : object.m_poJsonObject)) == json_type_object)
682 : {
683 : json_object *poVal =
684 11675 : json_object_new_double_with_significant_figures(dfValue, -1);
685 11675 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
686 : objectName.c_str(), poVal);
687 : }
688 11675 : }
689 :
690 : /**
691 : * Add new key - value pair to json object.
692 : * @param osName Key name.
693 : * @param nValue Integer value.
694 : *
695 : */
696 17452 : void CPLJSONObject::Add(const std::string &osName, int nValue)
697 : {
698 34904 : std::string objectName;
699 17452 : if (m_osKey == INVALID_OBJ_KEY)
700 0 : m_osKey.clear();
701 34904 : CPLJSONObject object = GetObjectByPath(osName, objectName);
702 17452 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
703 : object.m_poJsonObject)) == json_type_object)
704 : {
705 17452 : json_object *poVal = json_object_new_int(nValue);
706 17452 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
707 : objectName.c_str(), poVal);
708 : }
709 17452 : }
710 :
711 : /**
712 : * Add new key - value pair to json object.
713 : * @param osName Key name.
714 : * @param nValue Long value.
715 : *
716 : */
717 5717 : void CPLJSONObject::Add(const std::string &osName, GInt64 nValue)
718 : {
719 11434 : std::string objectName;
720 5717 : if (m_osKey == INVALID_OBJ_KEY)
721 0 : m_osKey.clear();
722 11434 : CPLJSONObject object = GetObjectByPath(osName, objectName);
723 5717 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
724 : object.m_poJsonObject)) == json_type_object)
725 : {
726 : json_object *poVal =
727 5717 : json_object_new_int64(static_cast<int64_t>(nValue));
728 5717 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
729 : objectName.c_str(), poVal);
730 : }
731 5717 : }
732 :
733 : /**
734 : * Add new key - value pair to json object.
735 : * @param osName Key name.
736 : * @param nValue uint64_t value.
737 : *
738 : * @since GDAL 3.8
739 : */
740 832 : void CPLJSONObject::Add(const std::string &osName, uint64_t nValue)
741 : {
742 1664 : std::string objectName;
743 832 : if (m_osKey == INVALID_OBJ_KEY)
744 0 : m_osKey.clear();
745 1664 : CPLJSONObject object = GetObjectByPath(osName, objectName);
746 832 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
747 : object.m_poJsonObject)) == json_type_object)
748 : {
749 832 : json_object *poVal = json_object_new_uint64(nValue);
750 832 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
751 : objectName.c_str(), poVal);
752 : }
753 832 : }
754 :
755 : /**
756 : * Add new key - value pair to json object.
757 : * @param osName Key name.
758 : * @param oValue Array value.
759 : *
760 : */
761 11029 : void CPLJSONObject::Add(const std::string &osName, const CPLJSONArray &oValue)
762 : {
763 22058 : std::string objectName;
764 11029 : if (m_osKey == INVALID_OBJ_KEY)
765 0 : m_osKey.clear();
766 22058 : CPLJSONObject object = GetObjectByPath(osName, objectName);
767 11029 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
768 : object.m_poJsonObject)) == json_type_object)
769 : {
770 22058 : json_object_object_add(
771 11029 : TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
772 11029 : json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
773 : }
774 11029 : }
775 :
776 : /**
777 : * Add new key - value pair to json object.
778 : * @param osName Key name.
779 : * @param oValue Json object value.
780 : *
781 : */
782 14491 : void CPLJSONObject::Add(const std::string &osName, const CPLJSONObject &oValue)
783 : {
784 14491 : std::string objectName;
785 14491 : if (m_osKey == INVALID_OBJ_KEY)
786 0 : m_osKey.clear();
787 14491 : if (osName.empty())
788 : {
789 34 : json_object_object_add(
790 17 : TO_JSONOBJ(GetInternalHandle()), "",
791 17 : json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
792 17 : return;
793 : }
794 28948 : CPLJSONObject object = GetObjectByPath(osName, objectName);
795 14474 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
796 : object.m_poJsonObject)) == json_type_object)
797 : {
798 28948 : json_object_object_add(
799 14474 : TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
800 14474 : json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
801 : }
802 : }
803 :
804 : /**
805 : * Add new key - value pair to json object.
806 : * @param osName Key name (do not split it on '/')
807 : * @param oValue Json object value.
808 : *
809 : * @since GDAL 3.2
810 : */
811 878 : void CPLJSONObject::AddNoSplitName(const std::string &osName,
812 : const CPLJSONObject &oValue)
813 : {
814 878 : if (m_osKey == INVALID_OBJ_KEY)
815 0 : m_osKey.clear();
816 1756 : if (IsValid() &&
817 878 : json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_object)
818 : {
819 1756 : json_object_object_add(
820 878 : TO_JSONOBJ(GetInternalHandle()), osName.c_str(),
821 878 : json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
822 : }
823 878 : }
824 :
825 : /**
826 : * Add new key - value pair to json object.
827 : * @param osName Key name.
828 : * @param bValue Boolean value.
829 : *
830 : */
831 9420 : void CPLJSONObject::Add(const std::string &osName, bool bValue)
832 : {
833 18840 : std::string objectName;
834 9420 : if (m_osKey == INVALID_OBJ_KEY)
835 0 : m_osKey.clear();
836 18840 : CPLJSONObject object = GetObjectByPath(osName, objectName);
837 9420 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
838 : object.m_poJsonObject)) == json_type_object)
839 : {
840 9420 : json_object *poVal = json_object_new_boolean(bValue);
841 9420 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
842 : objectName.c_str(), poVal);
843 : }
844 9420 : }
845 :
846 : /**
847 : * Add new key - null pair to json object.
848 : * @param osName Key name.
849 : *
850 : */
851 11528 : void CPLJSONObject::AddNull(const std::string &osName)
852 : {
853 23056 : std::string objectName;
854 11528 : if (m_osKey == INVALID_OBJ_KEY)
855 0 : m_osKey.clear();
856 23056 : CPLJSONObject object = GetObjectByPath(osName, objectName);
857 11528 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
858 : object.m_poJsonObject)) == json_type_object)
859 : {
860 11528 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
861 : objectName.c_str(), nullptr);
862 : }
863 11528 : }
864 :
865 : /**
866 : * Change value by key.
867 : * @param osName Key name.
868 : *
869 : */
870 14 : void CPLJSONObject::SetNull(const std::string &osName)
871 : {
872 14 : Delete(osName);
873 14 : AddNull(osName);
874 14 : }
875 :
876 : /**
877 : * Get value by key.
878 : * @param osName Key name.
879 : * @return Json array object.
880 : *
881 : */
882 119774 : CPLJSONArray CPLJSONObject::GetArray(const std::string &osName) const
883 : {
884 239548 : std::string objectName;
885 239548 : CPLJSONObject object = GetObjectByPath(osName, objectName);
886 119774 : if (object.IsValid())
887 : {
888 119774 : json_object *poVal = nullptr;
889 119774 : if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
890 119774 : objectName.c_str(), &poVal))
891 : {
892 66847 : if (poVal && json_object_get_type(poVal) == json_type_array)
893 : {
894 66804 : return CPLJSONArray(objectName, poVal);
895 : }
896 : }
897 : }
898 52970 : return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
899 : }
900 :
901 : /**
902 : * Get value by key.
903 : * @param osName Key name.
904 : * @return Json object.
905 : *
906 : */
907 737142 : CPLJSONObject CPLJSONObject::GetObj(const std::string &osName) const
908 : {
909 1474280 : std::string objectName;
910 1474280 : CPLJSONObject object = GetObjectByPath(osName, objectName);
911 737142 : if (object.IsValid())
912 : {
913 736219 : json_object *poVal = nullptr;
914 736219 : if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
915 736219 : objectName.c_str(), &poVal))
916 : {
917 680080 : return CPLJSONObject(objectName, poVal);
918 : }
919 : }
920 57062 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
921 : }
922 :
923 : /**
924 : * Get value by key.
925 : * @param osName Key name.
926 : * @return Json object.
927 : *
928 : */
929 91290 : CPLJSONObject CPLJSONObject::operator[](const std::string &osName) const
930 : {
931 91290 : return GetObj(osName);
932 : }
933 :
934 : /** Change value by key.
935 : *
936 : * e.g.: ``oObj["type"] = "MyType"``
937 : *
938 : * @since 3.12
939 : */
940 19714 : CPLJSONObject CPLJSONObject::operator[](const std::string &osName)
941 : {
942 39428 : auto oObj = GetObj(osName);
943 19714 : if (oObj.IsValid())
944 4080 : return oObj;
945 31268 : CPLJSONObject oClone(*this);
946 15634 : oClone.m_osKey = INVALID_OBJ_KEY;
947 15634 : oClone.m_osKeyForSet = osName;
948 15634 : return oClone;
949 : }
950 :
951 : /**
952 : * Delete json object by key.
953 : * @param osName Key name.
954 : *
955 : */
956 12887 : void CPLJSONObject::Delete(const std::string &osName)
957 : {
958 25774 : std::string objectName;
959 12887 : if (m_osKey == INVALID_OBJ_KEY)
960 2074 : m_osKey.clear();
961 25774 : CPLJSONObject object = GetObjectByPath(osName, objectName);
962 12887 : if (object.IsValid())
963 : {
964 12887 : json_object_object_del(TO_JSONOBJ(object.GetInternalHandle()),
965 : objectName.c_str());
966 : }
967 12887 : }
968 :
969 : /**
970 : * Delete json object by key (without splitting on /)
971 : * @param osName Key name.
972 : *
973 : * @since GDAL 3.4
974 : */
975 891 : void CPLJSONObject::DeleteNoSplitName(const std::string &osName)
976 : {
977 891 : if (m_osKey == INVALID_OBJ_KEY)
978 0 : m_osKey.clear();
979 891 : if (m_poJsonObject)
980 : {
981 891 : json_object_object_del(TO_JSONOBJ(m_poJsonObject), osName.c_str());
982 : }
983 891 : }
984 :
985 : /**
986 : * Get value by key.
987 : * @param osName Key name.
988 : * @param osDefault Default value.
989 : * @return String value.
990 : *
991 : */
992 306888 : std::string CPLJSONObject::GetString(const std::string &osName,
993 : const std::string &osDefault) const
994 : {
995 306888 : if (!m_osKeyForSet.empty())
996 0 : return osDefault;
997 613776 : CPLJSONObject object = GetObj(osName);
998 306888 : return object.ToString(osDefault);
999 : }
1000 :
1001 : /**
1002 : * Get value.
1003 : * @param osDefault Default value.
1004 : * @return String value.
1005 : *
1006 : */
1007 463897 : std::string CPLJSONObject::ToString(const std::string &osDefault) const
1008 : {
1009 463897 : if (!m_osKeyForSet.empty())
1010 155 : return osDefault;
1011 463742 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1012 : json_type_string*/ )
1013 : {
1014 : const char *pszString =
1015 444800 : json_object_get_string(TO_JSONOBJ(m_poJsonObject));
1016 444800 : if (nullptr != pszString)
1017 : {
1018 444800 : return pszString;
1019 : }
1020 : }
1021 18942 : return osDefault;
1022 : }
1023 :
1024 : /**
1025 : * Get value by key.
1026 : * @param osName Key name.
1027 : * @param dfDefault Default value.
1028 : * @return Double value.
1029 : *
1030 : */
1031 52942 : double CPLJSONObject::GetDouble(const std::string &osName,
1032 : double dfDefault) const
1033 : {
1034 52942 : if (!m_osKeyForSet.empty())
1035 0 : return dfDefault;
1036 105884 : CPLJSONObject object = GetObj(osName);
1037 52942 : return object.ToDouble(dfDefault);
1038 : }
1039 :
1040 : /**
1041 : * Get value
1042 : * @param dfDefault Default value.
1043 : * @return Double value.
1044 : *
1045 : */
1046 165438 : double CPLJSONObject::ToDouble(double dfDefault) const
1047 : {
1048 165438 : if (!m_osKeyForSet.empty())
1049 0 : return dfDefault;
1050 165438 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1051 : json_type_double*/ )
1052 164762 : return json_object_get_double(TO_JSONOBJ(m_poJsonObject));
1053 676 : return dfDefault;
1054 : }
1055 :
1056 : /**
1057 : * Get value by key.
1058 : * @param osName Key name.
1059 : * @param nDefault Default value.
1060 : * @return Integer value.
1061 : *
1062 : */
1063 210513 : int CPLJSONObject::GetInteger(const std::string &osName, int nDefault) const
1064 : {
1065 210513 : if (!m_osKeyForSet.empty())
1066 0 : return nDefault;
1067 421026 : CPLJSONObject object = GetObj(osName);
1068 210513 : return object.ToInteger(nDefault);
1069 : }
1070 :
1071 : /**
1072 : * Get value.
1073 : * @param nDefault Default value.
1074 : * @return Integer value.
1075 : *
1076 : */
1077 212732 : int CPLJSONObject::ToInteger(int nDefault) const
1078 : {
1079 212732 : if (!m_osKeyForSet.empty())
1080 0 : return nDefault;
1081 212732 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1082 : json_type_int*/ )
1083 211846 : return json_object_get_int(TO_JSONOBJ(m_poJsonObject));
1084 886 : return nDefault;
1085 : }
1086 :
1087 : /**
1088 : * Get value by key.
1089 : * @param osName Key name.
1090 : * @param nDefault Default value.
1091 : * @return Long value.
1092 : *
1093 : */
1094 126 : GInt64 CPLJSONObject::GetLong(const std::string &osName, GInt64 nDefault) const
1095 : {
1096 126 : if (!m_osKeyForSet.empty())
1097 0 : return nDefault;
1098 252 : CPLJSONObject object = GetObj(osName);
1099 126 : return object.ToLong(nDefault);
1100 : }
1101 :
1102 : /**
1103 : * Get value.
1104 : * @param nDefault Default value.
1105 : * @return Long value.
1106 : *
1107 : */
1108 3080 : GInt64 CPLJSONObject::ToLong(GInt64 nDefault) const
1109 : {
1110 3080 : if (!m_osKeyForSet.empty())
1111 0 : return nDefault;
1112 3080 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1113 : json_type_int*/ )
1114 : return static_cast<GInt64>(
1115 3007 : json_object_get_int64(TO_JSONOBJ(m_poJsonObject)));
1116 73 : return nDefault;
1117 : }
1118 :
1119 : /**
1120 : * Get value by key.
1121 : * @param osName Key name.
1122 : * @param bDefault Default value.
1123 : * @return Boolean value.
1124 : *
1125 : */
1126 128 : bool CPLJSONObject::GetBool(const std::string &osName, bool bDefault) const
1127 : {
1128 128 : if (!m_osKeyForSet.empty())
1129 0 : return bDefault;
1130 256 : CPLJSONObject object = GetObj(osName);
1131 128 : return object.ToBool(bDefault);
1132 : }
1133 :
1134 : /**
1135 : * \brief Get json object children.
1136 : *
1137 : * This function is useful when keys is not know and need to
1138 : * iterate over json object items and get keys and values.
1139 : *
1140 : * @return Array of CPLJSONObject class instance.
1141 : *
1142 : */
1143 13482 : std::vector<CPLJSONObject> CPLJSONObject::GetChildren() const
1144 : {
1145 13482 : std::vector<CPLJSONObject> aoChildren;
1146 13482 : if (!m_osKeyForSet.empty())
1147 0 : return aoChildren;
1148 26964 : if (nullptr == m_poJsonObject ||
1149 13482 : json_object_get_type(TO_JSONOBJ(m_poJsonObject)) != json_type_object)
1150 : {
1151 1 : return aoChildren;
1152 : }
1153 :
1154 : json_object_iter it;
1155 13481 : it.key = nullptr;
1156 13481 : it.val = nullptr;
1157 13481 : it.entry = nullptr;
1158 : // cppcheck-suppress cstyleCast
1159 64708 : json_object_object_foreachC(TO_JSONOBJ(m_poJsonObject), it)
1160 : {
1161 51227 : aoChildren.push_back(CPLJSONObject(it.key, it.val));
1162 : }
1163 :
1164 13481 : return aoChildren;
1165 : }
1166 :
1167 : /**
1168 : * Get value.
1169 : * @param bDefault Default value.
1170 : * @return Boolean value.
1171 : *
1172 : */
1173 144 : bool CPLJSONObject::ToBool(bool bDefault) const
1174 : {
1175 144 : if (!m_osKeyForSet.empty())
1176 0 : return bDefault;
1177 144 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1178 : json_type_boolean*/ )
1179 62 : return json_object_get_boolean(TO_JSONOBJ(m_poJsonObject)) == 1;
1180 82 : return bDefault;
1181 : }
1182 :
1183 : /**
1184 : * Get value.
1185 : * @return Array
1186 : *
1187 : */
1188 15374 : CPLJSONArray CPLJSONObject::ToArray() const
1189 : {
1190 29792 : if (m_osKeyForSet.empty() && m_poJsonObject &&
1191 14418 : json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_array)
1192 14414 : return CPLJSONArray("", TO_JSONOBJ(m_poJsonObject));
1193 960 : return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
1194 : }
1195 :
1196 : /**
1197 : * Stringify object to json format.
1198 : * @param eFormat Format type,
1199 : * @return A string in JSON format.
1200 : *
1201 : */
1202 28591 : std::string CPLJSONObject::Format(PrettyFormat eFormat) const
1203 : {
1204 28591 : if (m_poJsonObject)
1205 : {
1206 28591 : const char *pszFormatString = nullptr;
1207 28591 : switch (eFormat)
1208 : {
1209 1 : case PrettyFormat::Spaced:
1210 2 : pszFormatString = json_object_to_json_string_ext(
1211 1 : TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_SPACED);
1212 1 : break;
1213 276 : case PrettyFormat::Pretty:
1214 552 : pszFormatString = json_object_to_json_string_ext(
1215 276 : TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PRETTY);
1216 276 : break;
1217 28314 : default:
1218 28314 : pszFormatString = json_object_to_json_string_ext(
1219 28314 : TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PLAIN);
1220 : }
1221 28591 : if (nullptr != pszFormatString)
1222 : {
1223 28591 : return pszFormatString;
1224 : }
1225 : }
1226 0 : return "";
1227 : }
1228 :
1229 : /*! @cond Doxygen_Suppress */
1230 1001970 : CPLJSONObject CPLJSONObject::GetObjectByPath(const std::string &osPath,
1231 : std::string &osName) const
1232 : {
1233 1001970 : json_object *poVal = nullptr;
1234 :
1235 : // Typically for keys that contain / character
1236 1001970 : if (json_object_object_get_ex(TO_JSONOBJ(GetInternalHandle()),
1237 1001970 : osPath.c_str(), &poVal))
1238 : {
1239 747406 : osName = osPath;
1240 747406 : return *this;
1241 : }
1242 :
1243 : CPLStringList pathPortions(
1244 509132 : CSLTokenizeString2(osPath.c_str(), JSON_PATH_DELIMITER, 0));
1245 254566 : int portionsCount = pathPortions.size();
1246 254566 : if (portionsCount > 100)
1247 : {
1248 0 : CPLError(CE_Failure, CPLE_NotSupported, "Too many components in path");
1249 0 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1250 : }
1251 254566 : if (0 == portionsCount)
1252 0 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1253 509132 : CPLJSONObject object = *this;
1254 256706 : for (int i = 0; i < portionsCount - 1; ++i)
1255 : {
1256 : // TODO: check array index in path - i.e.
1257 : // settings/catalog/root/id:1/name if EQUALN(pathPortions[i+1], "id:",
1258 : // 3) -> getArray
1259 2140 : if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
1260 4280 : pathPortions[i], &poVal))
1261 : {
1262 1305 : object = CPLJSONObject(pathPortions[i], poVal);
1263 : }
1264 : else
1265 : {
1266 835 : if (json_object_get_type(TO_JSONOBJ(object.m_poJsonObject)) !=
1267 : json_type_object)
1268 : {
1269 0 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1270 : }
1271 835 : object = CPLJSONObject(pathPortions[i], object);
1272 : }
1273 : }
1274 :
1275 : // // Check if such object already exists
1276 : // if(json_object_object_get_ex(object.m_jsonObject,
1277 : // pathPortions[portionsCount - 1], &poVal))
1278 : // return JSONObject(nullptr);
1279 : //
1280 254566 : osName = pathPortions[portionsCount - 1];
1281 254566 : return object;
1282 : }
1283 :
1284 : /*! @endcond */
1285 :
1286 : /**
1287 : * Get json object type.
1288 : * @return Json object type.
1289 : *
1290 : */
1291 133234 : CPLJSONObject::Type CPLJSONObject::GetType() const
1292 : {
1293 133234 : if (!m_osKeyForSet.empty())
1294 8959 : return CPLJSONObject::Type::Unknown;
1295 :
1296 124275 : if (nullptr == m_poJsonObject)
1297 : {
1298 8236 : if (m_osKey == INVALID_OBJ_KEY)
1299 4335 : return CPLJSONObject::Type::Unknown;
1300 3901 : return CPLJSONObject::Type::Null;
1301 : }
1302 116039 : auto jsonObj(TO_JSONOBJ(m_poJsonObject));
1303 116039 : switch (json_object_get_type(jsonObj))
1304 : {
1305 22 : case json_type_boolean:
1306 22 : return CPLJSONObject::Type::Boolean;
1307 3210 : case json_type_double:
1308 3210 : return CPLJSONObject::Type::Double;
1309 41017 : case json_type_int:
1310 : {
1311 41017 : if (CPL_INT64_FITS_ON_INT32(json_object_get_int64(jsonObj)))
1312 40884 : return CPLJSONObject::Type::Integer;
1313 : else
1314 133 : return CPLJSONObject::Type::Long;
1315 : }
1316 11562 : case json_type_object:
1317 11562 : return CPLJSONObject::Type::Object;
1318 12670 : case json_type_array:
1319 12670 : return CPLJSONObject::Type::Array;
1320 47558 : case json_type_string:
1321 47558 : return CPLJSONObject::Type::String;
1322 0 : default:
1323 0 : break;
1324 : }
1325 0 : return CPLJSONObject::Type::Unknown;
1326 : }
1327 :
1328 : /**
1329 : * Check if json object valid.
1330 : * @return true if json object valid.
1331 : *
1332 : */
1333 1184840 : bool CPLJSONObject::IsValid() const
1334 : {
1335 1184840 : return m_osKeyForSet.empty() && m_osKey != INVALID_OBJ_KEY;
1336 : }
1337 :
1338 : /**
1339 : * Decrement reference counter and make pointer NULL.
1340 : * A json object will become invalid.
1341 : *
1342 : */
1343 9120 : void CPLJSONObject::Deinit()
1344 : {
1345 9120 : if (m_poJsonObject)
1346 : {
1347 6871 : json_object_put(TO_JSONOBJ(m_poJsonObject));
1348 6871 : m_poJsonObject = nullptr;
1349 : }
1350 9120 : m_osKey = INVALID_OBJ_KEY;
1351 9120 : }
1352 :
1353 : //------------------------------------------------------------------------------
1354 : // JSONArray
1355 : //------------------------------------------------------------------------------
1356 : /*! @cond Doxygen_Suppress */
1357 38845 : CPLJSONArray::CPLJSONArray()
1358 : {
1359 38845 : json_object_put(TO_JSONOBJ(m_poJsonObject));
1360 38845 : m_poJsonObject = json_object_new_array();
1361 38845 : }
1362 :
1363 1 : CPLJSONArray::CPLJSONArray(const std::string &osName)
1364 1 : : CPLJSONObject(osName, json_object_new_array())
1365 : {
1366 1 : json_object_put(TO_JSONOBJ(m_poJsonObject));
1367 1 : }
1368 :
1369 135488 : CPLJSONArray::CPLJSONArray(const std::string &osName, JSONObjectH poJsonObject)
1370 135488 : : CPLJSONObject(osName, poJsonObject)
1371 : {
1372 135488 : }
1373 :
1374 9 : CPLJSONArray::CPLJSONArray(const CPLJSONObject &other) : CPLJSONObject(other)
1375 : {
1376 9 : }
1377 :
1378 : /*! @endcond */
1379 :
1380 : /**
1381 : * Get array size.
1382 : * @return Array size.
1383 : *
1384 : */
1385 367820 : int CPLJSONArray::Size() const
1386 : {
1387 367820 : if (m_poJsonObject)
1388 : return static_cast<int>(
1389 365556 : json_object_array_length(TO_JSONOBJ(m_poJsonObject)));
1390 2264 : return 0;
1391 : }
1392 :
1393 : /**
1394 : * Add null object to array.
1395 : *
1396 : * @since GDAL 3.8
1397 : */
1398 2389 : void CPLJSONArray::AddNull()
1399 : {
1400 2389 : if (m_poJsonObject)
1401 2389 : json_object_array_add(TO_JSONOBJ(m_poJsonObject), nullptr);
1402 2389 : }
1403 :
1404 : /**
1405 : * Add json object to array.
1406 : * @param oValue Json array.
1407 : *
1408 : */
1409 11285 : void CPLJSONArray::Add(const CPLJSONObject &oValue)
1410 : {
1411 11285 : if (m_poJsonObject && oValue.m_poJsonObject)
1412 22570 : json_object_array_add(
1413 11285 : TO_JSONOBJ(m_poJsonObject),
1414 11285 : json_object_get(TO_JSONOBJ(oValue.m_poJsonObject)));
1415 11285 : }
1416 :
1417 : /**
1418 : * Add value to array
1419 : * @param osValue Value to add.
1420 : *
1421 : */
1422 12838 : void CPLJSONArray::Add(const std::string &osValue)
1423 : {
1424 12838 : if (m_poJsonObject)
1425 12838 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1426 : json_object_new_string(osValue.c_str()));
1427 12838 : }
1428 :
1429 : /**
1430 : * Add value to array
1431 : * @param pszValue Value to add.
1432 : *
1433 : */
1434 6083 : void CPLJSONArray::Add(const char *pszValue)
1435 : {
1436 6083 : if (nullptr == pszValue)
1437 0 : return;
1438 6083 : if (m_poJsonObject)
1439 6083 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1440 : json_object_new_string(pszValue));
1441 : }
1442 :
1443 : /**
1444 : * Add value to array
1445 : * @param dfValue Value to add.
1446 : *
1447 : */
1448 3635 : void CPLJSONArray::Add(double dfValue)
1449 : {
1450 3635 : if (m_poJsonObject)
1451 3635 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1452 : json_object_new_double(dfValue));
1453 3635 : }
1454 :
1455 : /**
1456 : * Add value to array
1457 : * @param nValue Value to add.
1458 : *
1459 : */
1460 557 : void CPLJSONArray::Add(int nValue)
1461 : {
1462 557 : if (m_poJsonObject)
1463 557 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1464 : json_object_new_int(nValue));
1465 557 : }
1466 :
1467 : /**
1468 : * Add value to array
1469 : * @param nValue Value to add.
1470 : *
1471 : */
1472 1576 : void CPLJSONArray::Add(GInt64 nValue)
1473 : {
1474 1576 : if (m_poJsonObject)
1475 1576 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1476 : json_object_new_int64(nValue));
1477 1576 : }
1478 :
1479 : /**
1480 : * Add value to array
1481 : * @param nValue Value to add.
1482 : *
1483 : * @since GDAL 3.8
1484 : */
1485 40 : void CPLJSONArray::Add(uint64_t nValue)
1486 : {
1487 40 : if (m_poJsonObject)
1488 : {
1489 40 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1490 : json_object_new_uint64(nValue));
1491 : }
1492 40 : }
1493 :
1494 : /**
1495 : * Add value to array
1496 : * @param bValue Value to add.
1497 : *
1498 : */
1499 18 : void CPLJSONArray::Add(bool bValue)
1500 : {
1501 18 : if (m_poJsonObject)
1502 18 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1503 : json_object_new_boolean(bValue));
1504 18 : }
1505 :
1506 : /**
1507 : * Get array item by index.
1508 : * @param nIndex Item index.
1509 : * @return Json object.
1510 : *
1511 : */
1512 3186 : CPLJSONObject CPLJSONArray::operator[](int nIndex)
1513 : {
1514 : return CPLJSONObject(
1515 : CPLSPrintf("id:%d", nIndex),
1516 3186 : json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
1517 : }
1518 :
1519 : /**
1520 : * Get array const item by index.
1521 : * @param nIndex Item index.
1522 : * @return Json object.
1523 : *
1524 : */
1525 486321 : const CPLJSONObject CPLJSONArray::operator[](int nIndex) const
1526 : {
1527 : return CPLJSONObject(
1528 : CPLSPrintf("id:%d", nIndex),
1529 486321 : json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
1530 : }
1531 :
1532 : /************************************************************************/
1533 : /* CPLParseKeyValueJson() */
1534 : /************************************************************************/
1535 :
1536 : /** Return a string list of key/value pairs extracted from a JSON doc.
1537 :
1538 : We are expecting simple documents with key:value pairs, like the
1539 : following with no hierarchy or complex structure.
1540 : \verbatim
1541 : {
1542 : "Code" : "Success",
1543 : "LastUpdated" : "2017-07-03T16:20:17Z",
1544 : "Type" : "AWS-HMAC",
1545 : "AccessKeyId" : "bla",
1546 : "SecretAccessKey" : "bla",
1547 : "Token" : "bla",
1548 : "Expiration" : "2017-07-03T22:42:58Z"
1549 : }
1550 : \endverbatim
1551 : @since GDAL 3.7
1552 : */
1553 37 : CPLStringList CPLParseKeyValueJson(const char *pszJson)
1554 : {
1555 74 : CPLJSONDocument oDoc;
1556 37 : CPLStringList oNameValue;
1557 37 : if (pszJson != nullptr && oDoc.LoadMemory(pszJson))
1558 : {
1559 134 : for (const auto &obj : oDoc.GetRoot().GetChildren())
1560 : {
1561 97 : const auto eType = obj.GetType();
1562 97 : if (eType == CPLJSONObject::Type::String ||
1563 0 : eType == CPLJSONObject::Type::Integer ||
1564 : eType == CPLJSONObject::Type::Double)
1565 : {
1566 194 : oNameValue.SetNameValue(obj.GetName().c_str(),
1567 291 : obj.ToString().c_str());
1568 : }
1569 : }
1570 : }
1571 74 : return oNameValue;
1572 : }
|