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 31525 : CPLJSONDocument::CPLJSONDocument() : m_poRootJsonObject(nullptr)
59 : {
60 31525 : }
61 :
62 63064 : CPLJSONDocument::~CPLJSONDocument()
63 : {
64 31532 : if (m_poRootJsonObject)
65 25682 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
66 31532 : }
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 1576 : bool CPLJSONDocument::Save(const std::string &osPath) const
114 : {
115 1576 : VSILFILE *fp = VSIFOpenL(osPath.c_str(), "wt");
116 1576 : 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 3124 : const char *pabyData = json_object_to_json_string_ext(
124 1562 : TO_JSONOBJ(m_poRootJsonObject), JSON_C_TO_STRING_PRETTY);
125 1562 : bool bRet = VSIFWriteL(pabyData, strlen(pabyData), 1, fp) == 1;
126 :
127 1562 : bRet = VSIFCloseL(fp) == 0 && bRet;
128 :
129 1562 : return bRet;
130 : }
131 :
132 : /**
133 : * Return the json document as a serialized string.
134 : * @return serialized document.
135 : *
136 : */
137 10016 : std::string CPLJSONDocument::SaveAsString() const
138 : {
139 10016 : return json_object_to_json_string_ext(TO_JSONOBJ(m_poRootJsonObject),
140 10016 : 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 32271 : CPLJSONObject CPLJSONDocument::GetRoot()
160 : {
161 32271 : if (nullptr == m_poRootJsonObject)
162 : {
163 1867 : m_poRootJsonObject = json_object_new_object();
164 : }
165 :
166 32271 : if (json_object_get_type(TO_JSONOBJ(m_poRootJsonObject)) == json_type_array)
167 : {
168 7028 : return CPLJSONArray("", m_poRootJsonObject);
169 : }
170 : else
171 : {
172 28757 : 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 9658 : void CPLJSONDocument::SetRoot(const CPLJSONObject &oRoot)
183 : {
184 9658 : if (m_poRootJsonObject)
185 0 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
186 9658 : m_poRootJsonObject = json_object_get(TO_JSONOBJ(oRoot.m_poJsonObject));
187 9658 : }
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 7919 : bool CPLJSONDocument::Load(const std::string &osPath)
197 : {
198 7919 : GByte *pabyOut = nullptr;
199 7919 : vsi_l_offset nSize = 0;
200 :
201 7919 : GIntBig nMaxSize = 0;
202 7919 : if (CPLParseMemorySize(CPLGetConfigOption("CPL_JSON_MAX_SIZE", "100MB"),
203 15838 : &nMaxSize, nullptr) != CE_None ||
204 7919 : nMaxSize <= 0)
205 0 : return false;
206 :
207 7919 : if (!VSIIngestFile(nullptr, osPath.c_str(), &pabyOut, &nSize, nMaxSize))
208 : {
209 755 : CPLError(CE_Failure, CPLE_FileIO, "Load json file %s failed",
210 : osPath.c_str());
211 755 : return false;
212 : }
213 :
214 7164 : bool bResult = LoadMemory(pabyOut, static_cast<int>(nSize));
215 7164 : VSIFree(pabyOut);
216 7164 : 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 23576 : bool CPLJSONDocument::LoadMemory(const GByte *pabyData, int nLength)
228 : {
229 23576 : if (nullptr == pabyData)
230 : {
231 1 : return false;
232 : }
233 :
234 23575 : if (m_poRootJsonObject)
235 9366 : json_object_put(TO_JSONOBJ(m_poRootJsonObject));
236 :
237 23575 : 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 23570 : 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 23567 : json_tokener *jstok = json_tokener_new();
252 23567 : m_poRootJsonObject = json_tokener_parse_ex(
253 : jstok, reinterpret_cast<const char *>(pabyData), nLength);
254 23567 : bool bParsed = jstok->err == json_tokener_success;
255 23567 : if (!bParsed)
256 : {
257 35 : CPLError(CE_Failure, CPLE_AppDefined,
258 : "JSON parsing error: %s (at offset %d)",
259 : json_tokener_error_desc(jstok->err), jstok->char_offset);
260 35 : json_tokener_free(jstok);
261 35 : return false;
262 : }
263 23532 : json_tokener_free(jstok);
264 23531 : 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 16307 : bool CPLJSONDocument::LoadMemory(const std::string &osStr)
275 : {
276 16307 : if (osStr.empty())
277 3 : return false;
278 16304 : return LoadMemory(reinterpret_cast<const GByte *>(osStr.data()),
279 32607 : 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 251508 : CPLJSONObject::CPLJSONObject() : m_poJsonObject(json_object_new_object())
465 : {
466 251502 : }
467 :
468 1 : CPLJSONObject::CPLJSONObject(std::nullptr_t) : m_poJsonObject(nullptr)
469 : {
470 1 : }
471 :
472 4358 : CPLJSONObject::CPLJSONObject(const std::string &osVal)
473 4358 : : m_poJsonObject(json_object_new_string(osVal.c_str()))
474 : {
475 4358 : }
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 2981 : CPLJSONObject::CPLJSONObject(int nVal)
488 2981 : : m_poJsonObject(json_object_new_int(nVal))
489 : {
490 2981 : }
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 1784 : CPLJSONObject::CPLJSONObject(double dfVal)
503 1784 : : m_poJsonObject(json_object_new_double(dfVal))
504 : {
505 1784 : }
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 1709040 : CPLJSONObject::CPLJSONObject(const std::string &osName,
516 1709040 : JSONObjectH poJsonObject)
517 1709040 : : m_poJsonObject(json_object_get(TO_JSONOBJ(poJsonObject))), m_osKey(osName)
518 : {
519 1709020 : }
520 :
521 9270 : CPLJSONObject CPLJSONObject::Clone() const
522 : {
523 9270 : CPLJSONObject oRet;
524 9270 : if (IsValid())
525 : {
526 17050 : CPLJSONDocument oTmpDoc;
527 8525 : oTmpDoc.SetRoot(*this);
528 8525 : std::string osStr = oTmpDoc.SaveAsString();
529 8525 : CPL_IGNORE_RET_VAL(oTmpDoc.LoadMemory(osStr));
530 8525 : oRet = oTmpDoc.GetRoot();
531 : }
532 9270 : return oRet;
533 : }
534 :
535 3649600 : CPLJSONObject::~CPLJSONObject()
536 : {
537 : // Should delete m_poJsonObject only if CPLJSONObject has no parent
538 3649600 : if (m_poJsonObject)
539 : {
540 3013190 : json_object_put(TO_JSONOBJ(m_poJsonObject));
541 3013190 : m_poJsonObject = nullptr;
542 : }
543 3649590 : }
544 :
545 1277360 : CPLJSONObject::CPLJSONObject(const CPLJSONObject &other)
546 1277360 : : m_poJsonObject(json_object_get(TO_JSONOBJ(other.m_poJsonObject))),
547 1277330 : m_osKey(other.m_osKey), m_osKeyForSet(other.m_osKeyForSet)
548 : {
549 1277360 : }
550 :
551 401740 : CPLJSONObject::CPLJSONObject(CPLJSONObject &&other)
552 401740 : : m_poJsonObject(other.m_poJsonObject), m_osKey(std::move(other.m_osKey)),
553 401740 : m_osKeyForSet(std::move(other.m_osKeyForSet))
554 : {
555 401735 : other.m_poJsonObject = nullptr;
556 401735 : }
557 :
558 124258 : CPLJSONObject &CPLJSONObject::operator=(const CPLJSONObject &other)
559 : {
560 124258 : if (this == &other)
561 1 : return *this;
562 :
563 124257 : if (!m_osKeyForSet.empty())
564 : {
565 360 : std::string osKeyForSet = m_osKeyForSet;
566 180 : m_osKeyForSet.clear();
567 180 : Set(osKeyForSet, other);
568 : }
569 : else
570 : {
571 124077 : m_osKey = other.m_osKey;
572 124077 : if (m_poJsonObject)
573 122974 : json_object_put(TO_JSONOBJ(m_poJsonObject));
574 124077 : m_poJsonObject = json_object_get(TO_JSONOBJ(other.m_poJsonObject));
575 : }
576 124257 : return *this;
577 : }
578 :
579 39668 : CPLJSONObject &CPLJSONObject::operator=(CPLJSONObject &&other)
580 : {
581 39668 : if (this == &other)
582 0 : return *this;
583 :
584 39668 : if (!m_osKeyForSet.empty())
585 : {
586 997 : if (other.m_poJsonObject)
587 : {
588 997 : json_object_object_add(TO_JSONOBJ(GetInternalHandle()),
589 : m_osKeyForSet.c_str(),
590 997 : TO_JSONOBJ(other.m_poJsonObject));
591 997 : other.m_poJsonObject = nullptr;
592 : }
593 997 : other.m_osKey = INVALID_OBJ_KEY;
594 997 : m_osKeyForSet.clear();
595 : }
596 : else
597 : {
598 38671 : m_osKey = std::move(other.m_osKey);
599 38671 : if (m_poJsonObject)
600 33578 : json_object_put(TO_JSONOBJ(m_poJsonObject));
601 38671 : m_poJsonObject = other.m_poJsonObject;
602 38671 : other.m_poJsonObject = nullptr;
603 : }
604 39668 : return *this;
605 : }
606 :
607 487 : CPLJSONObject &CPLJSONObject::operator=(CPLJSONArray &&other)
608 : {
609 487 : 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 30780 : void CPLJSONObject::Add(const std::string &osName, const std::string &osValue)
621 : {
622 61560 : std::string objectName;
623 30780 : if (m_osKey == INVALID_OBJ_KEY)
624 0 : m_osKey.clear();
625 61560 : CPLJSONObject object = GetObjectByPath(osName, objectName);
626 30780 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
627 : object.m_poJsonObject)) == json_type_object)
628 : {
629 30780 : json_object *poVal = json_object_new_string(osValue.c_str());
630 30780 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
631 : objectName.c_str(), poVal);
632 : }
633 30780 : }
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 25428 : void CPLJSONObject::Add(const std::string &osName, const char *pszValue)
669 : {
670 25428 : if (nullptr == pszValue)
671 : {
672 2 : return;
673 : }
674 25426 : if (m_osKey == INVALID_OBJ_KEY)
675 0 : m_osKey.clear();
676 50852 : std::string objectName;
677 50852 : CPLJSONObject object = GetObjectByPath(osName, objectName);
678 25426 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
679 : object.m_poJsonObject)) == json_type_object)
680 : {
681 25426 : json_object *poVal = json_object_new_string(pszValue);
682 25426 : 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 10419 : void CPLJSONObject::Add(const std::string &osName, double dfValue)
702 : {
703 20838 : std::string objectName;
704 10419 : if (m_osKey == INVALID_OBJ_KEY)
705 0 : m_osKey.clear();
706 20838 : CPLJSONObject object = GetObjectByPath(osName, objectName);
707 10419 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
708 : object.m_poJsonObject)) == json_type_object)
709 : {
710 : json_object *poVal =
711 10419 : json_object_new_double_with_significant_figures(dfValue, -1);
712 10419 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
713 : objectName.c_str(), poVal);
714 : }
715 10419 : }
716 :
717 : /**
718 : * Add new key - value pair to json object.
719 : * @param osName Key name.
720 : * @param nValue Integer value.
721 : *
722 : */
723 14974 : void CPLJSONObject::Add(const std::string &osName, int nValue)
724 : {
725 29948 : std::string objectName;
726 14974 : if (m_osKey == INVALID_OBJ_KEY)
727 0 : m_osKey.clear();
728 29948 : CPLJSONObject object = GetObjectByPath(osName, objectName);
729 14974 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
730 : object.m_poJsonObject)) == json_type_object)
731 : {
732 14974 : json_object *poVal = json_object_new_int(nValue);
733 14974 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
734 : objectName.c_str(), poVal);
735 : }
736 14974 : }
737 :
738 : /**
739 : * Add new key - value pair to json object.
740 : * @param osName Key name.
741 : * @param nValue Long value.
742 : *
743 : */
744 5780 : void CPLJSONObject::Add(const std::string &osName, GInt64 nValue)
745 : {
746 11560 : std::string objectName;
747 5780 : if (m_osKey == INVALID_OBJ_KEY)
748 0 : m_osKey.clear();
749 11560 : CPLJSONObject object = GetObjectByPath(osName, objectName);
750 5780 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
751 : object.m_poJsonObject)) == json_type_object)
752 : {
753 : json_object *poVal =
754 5780 : json_object_new_int64(static_cast<int64_t>(nValue));
755 5780 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
756 : objectName.c_str(), poVal);
757 : }
758 5780 : }
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 841 : void CPLJSONObject::Add(const std::string &osName, uint64_t nValue)
768 : {
769 1682 : std::string objectName;
770 841 : if (m_osKey == INVALID_OBJ_KEY)
771 0 : m_osKey.clear();
772 1682 : CPLJSONObject object = GetObjectByPath(osName, objectName);
773 841 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
774 : object.m_poJsonObject)) == json_type_object)
775 : {
776 841 : json_object *poVal = json_object_new_uint64(nValue);
777 841 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
778 : objectName.c_str(), poVal);
779 : }
780 841 : }
781 :
782 : /**
783 : * Add new key - value pair to json object.
784 : * @param osName Key name.
785 : * @param oValue Array value.
786 : *
787 : */
788 12755 : void CPLJSONObject::Add(const std::string &osName, const CPLJSONArray &oValue)
789 : {
790 25510 : std::string objectName;
791 12755 : if (m_osKey == INVALID_OBJ_KEY)
792 0 : m_osKey.clear();
793 25510 : CPLJSONObject object = GetObjectByPath(osName, objectName);
794 12755 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
795 : object.m_poJsonObject)) == json_type_object)
796 : {
797 25510 : json_object_object_add(
798 12755 : TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
799 12755 : json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
800 : }
801 12755 : }
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 14071 : void CPLJSONObject::Add(const std::string &osName, const CPLJSONObject &oValue)
810 : {
811 14071 : std::string objectName;
812 14071 : if (m_osKey == INVALID_OBJ_KEY)
813 0 : m_osKey.clear();
814 14071 : if (osName.empty())
815 : {
816 40 : json_object_object_add(
817 20 : TO_JSONOBJ(GetInternalHandle()), "",
818 20 : json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
819 20 : return;
820 : }
821 28102 : CPLJSONObject object = GetObjectByPath(osName, objectName);
822 14051 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
823 : object.m_poJsonObject)) == json_type_object)
824 : {
825 28102 : json_object_object_add(
826 14051 : TO_JSONOBJ(object.GetInternalHandle()), objectName.c_str(),
827 14051 : 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 13766 : void CPLJSONObject::AddNoSplitName(const std::string &osName,
839 : const CPLJSONObject &oValue)
840 : {
841 13766 : if (m_osKey == INVALID_OBJ_KEY)
842 0 : m_osKey.clear();
843 27532 : if (IsValid() &&
844 13766 : json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_object)
845 : {
846 27532 : json_object_object_add(
847 13766 : TO_JSONOBJ(GetInternalHandle()), osName.c_str(),
848 13766 : json_object_get(TO_JSONOBJ(oValue.GetInternalHandle())));
849 : }
850 13766 : }
851 :
852 : /**
853 : * Add new key - value pair to json object.
854 : * @param osName Key name.
855 : * @param bValue Boolean value.
856 : *
857 : */
858 13208 : void CPLJSONObject::Add(const std::string &osName, bool bValue)
859 : {
860 26416 : std::string objectName;
861 13208 : if (m_osKey == INVALID_OBJ_KEY)
862 0 : m_osKey.clear();
863 26416 : CPLJSONObject object = GetObjectByPath(osName, objectName);
864 13208 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
865 : object.m_poJsonObject)) == json_type_object)
866 : {
867 13208 : json_object *poVal = json_object_new_boolean(bValue);
868 13208 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
869 : objectName.c_str(), poVal);
870 : }
871 13208 : }
872 :
873 : /**
874 : * Add new key - null pair to json object.
875 : * @param osName Key name.
876 : *
877 : */
878 11680 : void CPLJSONObject::AddNull(const std::string &osName)
879 : {
880 23360 : std::string objectName;
881 11680 : if (m_osKey == INVALID_OBJ_KEY)
882 0 : m_osKey.clear();
883 23360 : CPLJSONObject object = GetObjectByPath(osName, objectName);
884 11680 : if (object.IsValid() && json_object_get_type(TO_JSONOBJ(
885 : object.m_poJsonObject)) == json_type_object)
886 : {
887 11680 : json_object_object_add(TO_JSONOBJ(object.GetInternalHandle()),
888 : objectName.c_str(), nullptr);
889 : }
890 11680 : }
891 :
892 : /**
893 : * Change value by key.
894 : * @param osName Key name.
895 : *
896 : */
897 18 : void CPLJSONObject::SetNull(const std::string &osName)
898 : {
899 18 : Delete(osName);
900 18 : AddNull(osName);
901 18 : }
902 :
903 : /**
904 : * Get value by key.
905 : * @param osName Key name.
906 : * @return Json array object.
907 : *
908 : */
909 140826 : CPLJSONArray CPLJSONObject::GetArray(const std::string &osName) const
910 : {
911 281652 : std::string objectName;
912 281652 : CPLJSONObject object = GetObjectByPath(osName, objectName);
913 140826 : if (object.IsValid())
914 : {
915 140826 : json_object *poVal = nullptr;
916 140826 : if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
917 140826 : objectName.c_str(), &poVal))
918 : {
919 77890 : if (poVal && json_object_get_type(poVal) == json_type_array)
920 : {
921 77847 : return CPLJSONArray(objectName, poVal);
922 : }
923 : }
924 : }
925 62979 : 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 876497 : CPLJSONObject CPLJSONObject::GetObj(const std::string &osName) const
935 : {
936 1752980 : std::string objectName;
937 1752970 : CPLJSONObject object = GetObjectByPath(osName, objectName);
938 876492 : if (object.IsValid())
939 : {
940 875450 : json_object *poVal = nullptr;
941 875450 : if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
942 875471 : objectName.c_str(), &poVal))
943 : {
944 801858 : return CPLJSONObject(objectName, poVal);
945 : }
946 : }
947 74633 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
948 : }
949 :
950 : /**
951 : * Get value by key (without splitting on /).
952 : * @param osName Key name.
953 : * @return Json object.
954 : * @since 3.13
955 : *
956 : */
957 10361 : CPLJSONObject CPLJSONObject::GetObjNoSplitName(const std::string &osName) const
958 : {
959 10361 : json_object *poVal = nullptr;
960 :
961 : // Typically for keys that contain / character
962 10361 : if (json_object_object_get_ex(TO_JSONOBJ(GetInternalHandle()),
963 10361 : osName.c_str(), &poVal))
964 : {
965 10 : return CPLJSONObject(osName, poVal);
966 : }
967 10351 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
968 : }
969 :
970 : /**
971 : * Get value by key.
972 : * @param osName Key name.
973 : * @return Json object.
974 : *
975 : */
976 127932 : CPLJSONObject CPLJSONObject::operator[](const std::string &osName) const
977 : {
978 127932 : return GetObj(osName);
979 : }
980 :
981 : /** Change value by key.
982 : *
983 : * e.g.: ``oObj["type"] = "MyType"``
984 : *
985 : * @since 3.12
986 : */
987 29729 : CPLJSONObject CPLJSONObject::operator[](const std::string &osName)
988 : {
989 59458 : auto oObj = GetObj(osName);
990 29729 : if (oObj.IsValid())
991 6846 : return oObj;
992 45766 : CPLJSONObject oClone(*this);
993 22883 : oClone.m_osKey = INVALID_OBJ_KEY;
994 22883 : oClone.m_osKeyForSet = osName;
995 22883 : return oClone;
996 : }
997 :
998 : /**
999 : * Delete json object by key.
1000 : * @param osName Key name.
1001 : *
1002 : */
1003 14576 : void CPLJSONObject::Delete(const std::string &osName)
1004 : {
1005 29152 : std::string objectName;
1006 14576 : if (m_osKey == INVALID_OBJ_KEY)
1007 3014 : m_osKey.clear();
1008 29152 : CPLJSONObject object = GetObjectByPath(osName, objectName);
1009 14576 : if (object.IsValid())
1010 : {
1011 14576 : json_object_object_del(TO_JSONOBJ(object.GetInternalHandle()),
1012 : objectName.c_str());
1013 : }
1014 14576 : }
1015 :
1016 : /**
1017 : * Delete json object by key (without splitting on /)
1018 : * @param osName Key name.
1019 : *
1020 : * @since GDAL 3.4
1021 : */
1022 932 : void CPLJSONObject::DeleteNoSplitName(const std::string &osName)
1023 : {
1024 932 : if (m_osKey == INVALID_OBJ_KEY)
1025 0 : m_osKey.clear();
1026 932 : if (m_poJsonObject)
1027 : {
1028 932 : json_object_object_del(TO_JSONOBJ(m_poJsonObject), osName.c_str());
1029 : }
1030 932 : }
1031 :
1032 : /**
1033 : * Get value by key.
1034 : * @param osName Key name.
1035 : * @param osDefault Default value.
1036 : * @return String value.
1037 : *
1038 : */
1039 330965 : std::string CPLJSONObject::GetString(const std::string &osName,
1040 : const std::string &osDefault) const
1041 : {
1042 330965 : if (!m_osKeyForSet.empty())
1043 0 : return osDefault;
1044 661912 : CPLJSONObject object = GetObj(osName);
1045 330956 : return object.ToString(osDefault);
1046 : }
1047 :
1048 : /**
1049 : * Get value.
1050 : * @param osDefault Default value.
1051 : * @return String value.
1052 : *
1053 : */
1054 510404 : std::string CPLJSONObject::ToString(const std::string &osDefault) const
1055 : {
1056 510404 : if (!m_osKeyForSet.empty())
1057 252 : return osDefault;
1058 510150 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1059 : json_type_string*/ )
1060 : {
1061 : const char *pszString =
1062 489326 : json_object_get_string(TO_JSONOBJ(m_poJsonObject));
1063 489324 : if (nullptr != pszString)
1064 : {
1065 489325 : return pszString;
1066 : }
1067 : }
1068 20823 : return osDefault;
1069 : }
1070 :
1071 : /**
1072 : * Get value by key.
1073 : * @param osName Key name.
1074 : * @param dfDefault Default value.
1075 : * @return Double value.
1076 : *
1077 : */
1078 62879 : double CPLJSONObject::GetDouble(const std::string &osName,
1079 : double dfDefault) const
1080 : {
1081 62879 : if (!m_osKeyForSet.empty())
1082 0 : return dfDefault;
1083 125758 : CPLJSONObject object = GetObj(osName);
1084 62879 : return object.ToDouble(dfDefault);
1085 : }
1086 :
1087 : /**
1088 : * Get value
1089 : * @param dfDefault Default value.
1090 : * @return Double value.
1091 : *
1092 : */
1093 198262 : double CPLJSONObject::ToDouble(double dfDefault) const
1094 : {
1095 198262 : if (!m_osKeyForSet.empty())
1096 0 : return dfDefault;
1097 198262 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1098 : json_type_double*/ )
1099 197544 : return json_object_get_double(TO_JSONOBJ(m_poJsonObject));
1100 718 : return dfDefault;
1101 : }
1102 :
1103 : /**
1104 : * Get value by key.
1105 : * @param osName Key name.
1106 : * @param nDefault Default value.
1107 : * @return Integer value.
1108 : *
1109 : */
1110 251441 : int CPLJSONObject::GetInteger(const std::string &osName, int nDefault) const
1111 : {
1112 251441 : if (!m_osKeyForSet.empty())
1113 0 : return nDefault;
1114 502882 : CPLJSONObject object = GetObj(osName);
1115 251441 : return object.ToInteger(nDefault);
1116 : }
1117 :
1118 : /**
1119 : * Get value.
1120 : * @param nDefault Default value.
1121 : * @return Integer value.
1122 : *
1123 : */
1124 254444 : int CPLJSONObject::ToInteger(int nDefault) const
1125 : {
1126 254444 : if (!m_osKeyForSet.empty())
1127 0 : return nDefault;
1128 254444 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1129 : json_type_int*/ )
1130 253474 : return json_object_get_int(TO_JSONOBJ(m_poJsonObject));
1131 970 : return nDefault;
1132 : }
1133 :
1134 : /**
1135 : * Get value by key.
1136 : * @param osName Key name.
1137 : * @param nDefault Default value.
1138 : * @return Long value.
1139 : *
1140 : */
1141 126 : GInt64 CPLJSONObject::GetLong(const std::string &osName, GInt64 nDefault) const
1142 : {
1143 126 : if (!m_osKeyForSet.empty())
1144 0 : return nDefault;
1145 252 : CPLJSONObject object = GetObj(osName);
1146 126 : return object.ToLong(nDefault);
1147 : }
1148 :
1149 : /**
1150 : * Get value.
1151 : * @param nDefault Default value.
1152 : * @return Long value.
1153 : *
1154 : */
1155 9202 : GInt64 CPLJSONObject::ToLong(GInt64 nDefault) const
1156 : {
1157 9202 : if (!m_osKeyForSet.empty())
1158 0 : return nDefault;
1159 9202 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1160 : json_type_int*/ )
1161 : return static_cast<GInt64>(
1162 9129 : json_object_get_int64(TO_JSONOBJ(m_poJsonObject)));
1163 73 : return nDefault;
1164 : }
1165 :
1166 : /**
1167 : * Get value by key.
1168 : * @param osName Key name.
1169 : * @param nDefault Default value.
1170 : * @return uint64_t value.
1171 : *
1172 : */
1173 0 : uint64_t CPLJSONObject::GetUInt64(const std::string &osName,
1174 : uint64_t nDefault) const
1175 : {
1176 0 : if (!m_osKeyForSet.empty())
1177 0 : return nDefault;
1178 0 : CPLJSONObject object = GetObj(osName);
1179 0 : return object.ToUInt64(nDefault);
1180 : }
1181 :
1182 : /**
1183 : * Get value.
1184 : * @param nDefault Default value.
1185 : * @return uint64_t value.
1186 : *
1187 : */
1188 6 : uint64_t CPLJSONObject::ToUInt64(uint64_t nDefault) const
1189 : {
1190 6 : if (!m_osKeyForSet.empty())
1191 0 : return nDefault;
1192 6 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1193 : json_type_int*/ )
1194 : {
1195 : #if (!defined(JSON_C_VERSION_NUM)) || (JSON_C_VERSION_NUM < JSON_C_VER_014)
1196 : // We can't do much better without json_object_get_uint64
1197 : const double v = json_object_get_double(TO_JSONOBJ(m_poJsonObject));
1198 : if (v > 0)
1199 : {
1200 : return static_cast<uint64_t>(
1201 : json_object_get_int64(TO_JSONOBJ(m_poJsonObject)));
1202 : }
1203 : #else
1204 6 : return json_object_get_uint64(TO_JSONOBJ(m_poJsonObject));
1205 : #endif
1206 : }
1207 0 : return nDefault;
1208 : }
1209 :
1210 : /**
1211 : * Get value by key.
1212 : * @param osName Key name.
1213 : * @param bDefault Default value.
1214 : * @return Boolean value.
1215 : *
1216 : */
1217 5184 : bool CPLJSONObject::GetBool(const std::string &osName, bool bDefault) const
1218 : {
1219 5184 : if (!m_osKeyForSet.empty())
1220 0 : return bDefault;
1221 10368 : CPLJSONObject object = GetObj(osName);
1222 5184 : return object.ToBool(bDefault);
1223 : }
1224 :
1225 : /**
1226 : * \brief Get json object children.
1227 : *
1228 : * This function is useful when keys is not know and need to
1229 : * iterate over json object items and get keys and values.
1230 : *
1231 : * @return Array of CPLJSONObject class instance.
1232 : *
1233 : */
1234 23828 : std::vector<CPLJSONObject> CPLJSONObject::GetChildren() const
1235 : {
1236 23828 : std::vector<CPLJSONObject> aoChildren;
1237 23819 : if (!m_osKeyForSet.empty())
1238 0 : return aoChildren;
1239 47636 : if (nullptr == m_poJsonObject ||
1240 23819 : json_object_get_type(TO_JSONOBJ(m_poJsonObject)) != json_type_object)
1241 : {
1242 1 : return aoChildren;
1243 : }
1244 :
1245 : json_object_iter it;
1246 23816 : it.key = nullptr;
1247 23816 : it.val = nullptr;
1248 23816 : it.entry = nullptr;
1249 : // cppcheck-suppress cstyleCast
1250 96003 : json_object_object_foreachC(TO_JSONOBJ(m_poJsonObject), it)
1251 : {
1252 72193 : aoChildren.push_back(CPLJSONObject(it.key, it.val));
1253 : }
1254 :
1255 23815 : return aoChildren;
1256 : }
1257 :
1258 : /**
1259 : * Get value.
1260 : * @param bDefault Default value.
1261 : * @return Boolean value.
1262 : *
1263 : */
1264 5731 : bool CPLJSONObject::ToBool(bool bDefault) const
1265 : {
1266 5731 : if (!m_osKeyForSet.empty())
1267 0 : return bDefault;
1268 5731 : if( m_poJsonObject /*&& json_object_get_type( TO_JSONOBJ(m_poJsonObject) ) ==
1269 : json_type_boolean*/ )
1270 4948 : return json_object_get_boolean(TO_JSONOBJ(m_poJsonObject)) == 1;
1271 783 : return bDefault;
1272 : }
1273 :
1274 : /**
1275 : * Get value.
1276 : * @return Array
1277 : *
1278 : */
1279 28500 : CPLJSONArray CPLJSONObject::ToArray() const
1280 : {
1281 55753 : if (m_osKeyForSet.empty() && m_poJsonObject &&
1282 27253 : json_object_get_type(TO_JSONOBJ(m_poJsonObject)) == json_type_array)
1283 27248 : return CPLJSONArray("", TO_JSONOBJ(m_poJsonObject));
1284 1252 : return CPLJSONArray(INVALID_OBJ_KEY, nullptr);
1285 : }
1286 :
1287 : /**
1288 : * Stringify object to json format.
1289 : * @param eFormat Format type,
1290 : * @return A string in JSON format.
1291 : *
1292 : */
1293 29205 : std::string CPLJSONObject::Format(PrettyFormat eFormat) const
1294 : {
1295 29205 : if (m_poJsonObject)
1296 : {
1297 29205 : const char *pszFormatString = nullptr;
1298 29205 : switch (eFormat)
1299 : {
1300 1 : case PrettyFormat::Spaced:
1301 2 : pszFormatString = json_object_to_json_string_ext(
1302 1 : TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_SPACED);
1303 1 : break;
1304 322 : case PrettyFormat::Pretty:
1305 644 : pszFormatString = json_object_to_json_string_ext(
1306 322 : TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PRETTY);
1307 322 : break;
1308 28882 : default:
1309 28882 : pszFormatString = json_object_to_json_string_ext(
1310 28882 : TO_JSONOBJ(m_poJsonObject), JSON_C_TO_STRING_PLAIN);
1311 : }
1312 29205 : if (nullptr != pszFormatString)
1313 : {
1314 29205 : return pszFormatString;
1315 : }
1316 : }
1317 0 : return "";
1318 : }
1319 :
1320 : /*! @cond Doxygen_Suppress */
1321 1171830 : CPLJSONObject CPLJSONObject::GetObjectByPath(const std::string &osPath,
1322 : std::string &osName) const
1323 : {
1324 1171830 : json_object *poVal = nullptr;
1325 :
1326 : // Typically for keys that contain / character
1327 1171830 : if (json_object_object_get_ex(TO_JSONOBJ(GetInternalHandle()),
1328 1171810 : osPath.c_str(), &poVal))
1329 : {
1330 880230 : osName = osPath;
1331 880236 : return *this;
1332 : }
1333 :
1334 : CPLStringList pathPortions(
1335 583168 : CSLTokenizeString2(osPath.c_str(), JSON_PATH_DELIMITER, 0));
1336 291584 : int portionsCount = pathPortions.size();
1337 291584 : if (portionsCount > 100)
1338 : {
1339 0 : CPLError(CE_Failure, CPLE_NotSupported, "Too many components in path");
1340 0 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1341 : }
1342 291584 : if (0 == portionsCount)
1343 0 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1344 583168 : CPLJSONObject object = *this;
1345 293753 : for (int i = 0; i < portionsCount - 1; ++i)
1346 : {
1347 : // TODO: check array index in path - i.e.
1348 : // settings/catalog/root/id:1/name if EQUALN(pathPortions[i+1], "id:",
1349 : // 3) -> getArray
1350 2169 : if (json_object_object_get_ex(TO_JSONOBJ(object.GetInternalHandle()),
1351 4338 : pathPortions[i], &poVal))
1352 : {
1353 1334 : object = CPLJSONObject(pathPortions[i], poVal);
1354 : }
1355 : else
1356 : {
1357 835 : if (json_object_get_type(TO_JSONOBJ(object.m_poJsonObject)) !=
1358 : json_type_object)
1359 : {
1360 0 : return CPLJSONObject(INVALID_OBJ_KEY, nullptr);
1361 : }
1362 835 : object = CPLJSONObject(pathPortions[i], object);
1363 : }
1364 : }
1365 :
1366 : // // Check if such object already exists
1367 : // if(json_object_object_get_ex(object.m_jsonObject,
1368 : // pathPortions[portionsCount - 1], &poVal))
1369 : // return JSONObject(nullptr);
1370 : //
1371 291584 : osName = pathPortions[portionsCount - 1];
1372 291584 : return object;
1373 : }
1374 :
1375 : /*! @endcond */
1376 :
1377 : /**
1378 : * Get json object type.
1379 : * @return Json object type.
1380 : *
1381 : */
1382 191868 : CPLJSONObject::Type CPLJSONObject::GetType() const
1383 : {
1384 191868 : if (!m_osKeyForSet.empty())
1385 13541 : return CPLJSONObject::Type::Unknown;
1386 :
1387 178317 : if (nullptr == m_poJsonObject)
1388 : {
1389 12747 : if (m_osKey == INVALID_OBJ_KEY)
1390 8341 : return CPLJSONObject::Type::Unknown;
1391 4406 : return CPLJSONObject::Type::Null;
1392 : }
1393 165570 : auto jsonObj(TO_JSONOBJ(m_poJsonObject));
1394 165570 : switch (json_object_get_type(jsonObj))
1395 : {
1396 555 : case json_type_boolean:
1397 555 : return CPLJSONObject::Type::Boolean;
1398 4848 : case json_type_double:
1399 4848 : return CPLJSONObject::Type::Double;
1400 43649 : case json_type_int:
1401 : {
1402 43649 : if (CPL_INT64_FITS_ON_INT32(json_object_get_int64(jsonObj)))
1403 43453 : return CPLJSONObject::Type::Integer;
1404 : else
1405 201 : return CPLJSONObject::Type::Long;
1406 : }
1407 34877 : case json_type_object:
1408 34877 : return CPLJSONObject::Type::Object;
1409 20529 : case json_type_array:
1410 20529 : return CPLJSONObject::Type::Array;
1411 61116 : case json_type_string:
1412 61116 : return CPLJSONObject::Type::String;
1413 0 : default:
1414 0 : break;
1415 : }
1416 0 : return CPLJSONObject::Type::Unknown;
1417 : }
1418 :
1419 : /**
1420 : * Check if json object valid.
1421 : * @return true if json object valid.
1422 : *
1423 : */
1424 1446000 : bool CPLJSONObject::IsValid() const
1425 : {
1426 1446000 : return m_osKeyForSet.empty() && m_osKey != INVALID_OBJ_KEY;
1427 : }
1428 :
1429 : /**
1430 : * Decrement reference counter and make pointer NULL.
1431 : * A json object will become invalid.
1432 : *
1433 : */
1434 47908 : void CPLJSONObject::Deinit()
1435 : {
1436 47908 : if (m_poJsonObject)
1437 : {
1438 45580 : json_object_put(TO_JSONOBJ(m_poJsonObject));
1439 45570 : m_poJsonObject = nullptr;
1440 : }
1441 47898 : m_osKey = INVALID_OBJ_KEY;
1442 47900 : }
1443 :
1444 : //------------------------------------------------------------------------------
1445 : // JSONArray
1446 : //------------------------------------------------------------------------------
1447 : /*! @cond Doxygen_Suppress */
1448 49413 : CPLJSONArray::CPLJSONArray()
1449 : {
1450 49413 : json_object_put(TO_JSONOBJ(m_poJsonObject));
1451 49413 : m_poJsonObject = json_object_new_array();
1452 49413 : }
1453 :
1454 1 : CPLJSONArray::CPLJSONArray(const std::string &osName)
1455 1 : : CPLJSONObject(osName, json_object_new_array())
1456 : {
1457 1 : json_object_put(TO_JSONOBJ(m_poJsonObject));
1458 1 : }
1459 :
1460 172840 : CPLJSONArray::CPLJSONArray(const std::string &osName, JSONObjectH poJsonObject)
1461 172840 : : CPLJSONObject(osName, poJsonObject)
1462 : {
1463 172840 : }
1464 :
1465 12 : CPLJSONArray::CPLJSONArray(const CPLJSONObject &other) : CPLJSONObject(other)
1466 : {
1467 12 : }
1468 :
1469 : /*! @endcond */
1470 :
1471 : /**
1472 : * Get array size.
1473 : * @return Array size.
1474 : *
1475 : */
1476 412631 : int CPLJSONArray::Size() const
1477 : {
1478 412631 : if (m_poJsonObject)
1479 : return static_cast<int>(
1480 410090 : json_object_array_length(TO_JSONOBJ(m_poJsonObject)));
1481 2541 : return 0;
1482 : }
1483 :
1484 : /**
1485 : * Add null object to array.
1486 : *
1487 : * @since GDAL 3.8
1488 : */
1489 2459 : void CPLJSONArray::AddNull()
1490 : {
1491 2459 : if (m_poJsonObject)
1492 2459 : json_object_array_add(TO_JSONOBJ(m_poJsonObject), nullptr);
1493 2459 : }
1494 :
1495 : /**
1496 : * Add json object to array.
1497 : * @param oValue Json array.
1498 : *
1499 : */
1500 13292 : void CPLJSONArray::Add(const CPLJSONObject &oValue)
1501 : {
1502 13292 : if (m_poJsonObject && oValue.m_poJsonObject)
1503 26584 : json_object_array_add(
1504 13292 : TO_JSONOBJ(m_poJsonObject),
1505 13292 : json_object_get(TO_JSONOBJ(oValue.m_poJsonObject)));
1506 13292 : }
1507 :
1508 : /**
1509 : * Add value to array
1510 : * @param osValue Value to add.
1511 : *
1512 : */
1513 12938 : void CPLJSONArray::Add(const std::string &osValue)
1514 : {
1515 12938 : if (m_poJsonObject)
1516 12938 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1517 : json_object_new_string(osValue.c_str()));
1518 12938 : }
1519 :
1520 : /**
1521 : * Add value to array
1522 : * @param svValue Value to add.
1523 : * @since 3.13
1524 : *
1525 : */
1526 17 : void CPLJSONArray::Add(std::string_view svValue)
1527 : {
1528 17 : if (svValue.size() > static_cast<size_t>(INT_MAX - 1))
1529 : {
1530 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too long string view");
1531 0 : return;
1532 : }
1533 17 : if (m_poJsonObject)
1534 : {
1535 17 : json_object_array_add(
1536 17 : TO_JSONOBJ(m_poJsonObject),
1537 : json_object_new_string_len(svValue.data(),
1538 17 : static_cast<int>(svValue.size())));
1539 : }
1540 : }
1541 :
1542 : /**
1543 : * Add value to array
1544 : * @param pszValue Value to add.
1545 : *
1546 : */
1547 6830 : void CPLJSONArray::Add(const char *pszValue)
1548 : {
1549 6830 : if (nullptr == pszValue)
1550 0 : return;
1551 6830 : if (m_poJsonObject)
1552 6830 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1553 : json_object_new_string(pszValue));
1554 : }
1555 :
1556 : /**
1557 : * Add value to array
1558 : * @param dfValue Value to add.
1559 : *
1560 : */
1561 4743 : void CPLJSONArray::Add(double dfValue)
1562 : {
1563 4743 : if (m_poJsonObject)
1564 4743 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1565 : json_object_new_double(dfValue));
1566 4743 : }
1567 :
1568 : /**
1569 : * Add value to array
1570 : * @param nValue Value to add.
1571 : *
1572 : */
1573 767 : void CPLJSONArray::Add(int nValue)
1574 : {
1575 767 : if (m_poJsonObject)
1576 767 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1577 : json_object_new_int(nValue));
1578 767 : }
1579 :
1580 : /**
1581 : * Add value to array
1582 : * @param nValue Value to add.
1583 : *
1584 : */
1585 2347 : void CPLJSONArray::Add(GInt64 nValue)
1586 : {
1587 2347 : if (m_poJsonObject)
1588 2347 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1589 : json_object_new_int64(nValue));
1590 2347 : }
1591 :
1592 : /**
1593 : * Add value to array
1594 : * @param nValue Value to add.
1595 : *
1596 : * @since GDAL 3.8
1597 : */
1598 91 : void CPLJSONArray::Add(uint64_t nValue)
1599 : {
1600 91 : if (m_poJsonObject)
1601 : {
1602 91 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1603 : json_object_new_uint64(nValue));
1604 : }
1605 91 : }
1606 :
1607 : /**
1608 : * Add value to array
1609 : * @param bValue Value to add.
1610 : *
1611 : */
1612 38 : void CPLJSONArray::Add(bool bValue)
1613 : {
1614 38 : if (m_poJsonObject)
1615 38 : json_object_array_add(TO_JSONOBJ(m_poJsonObject),
1616 : json_object_new_boolean(bValue));
1617 38 : }
1618 :
1619 : /**
1620 : * Get array item by index.
1621 : * @param nIndex Item index.
1622 : * @return Json object.
1623 : *
1624 : */
1625 3568 : CPLJSONObject CPLJSONArray::operator[](int nIndex)
1626 : {
1627 : return CPLJSONObject(
1628 : CPLSPrintf("id:%d", nIndex),
1629 3568 : json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
1630 : }
1631 :
1632 : /**
1633 : * Get array const item by index.
1634 : * @param nIndex Item index.
1635 : * @return Json object.
1636 : *
1637 : */
1638 543461 : const CPLJSONObject CPLJSONArray::operator[](int nIndex) const
1639 : {
1640 : return CPLJSONObject(
1641 : CPLSPrintf("id:%d", nIndex),
1642 543461 : json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject), nIndex));
1643 : }
1644 :
1645 : /**
1646 : * Get array item by index.
1647 : * @param nIndex Item index.
1648 : * @return Json object.
1649 : *
1650 : */
1651 0 : CPLJSONObject CPLJSONArray::operator[](size_t nIndex)
1652 : {
1653 : return CPLJSONObject(CPLSPrintf("id:%d", static_cast<int>(nIndex)),
1654 0 : json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject),
1655 0 : static_cast<int>(nIndex)));
1656 : }
1657 :
1658 : /**
1659 : * Get array const item by index.
1660 : * @param nIndex Item index.
1661 : * @return Json object.
1662 : *
1663 : */
1664 34 : const CPLJSONObject CPLJSONArray::operator[](size_t nIndex) const
1665 : {
1666 : return CPLJSONObject(CPLSPrintf("id:%d", static_cast<int>(nIndex)),
1667 34 : json_object_array_get_idx(TO_JSONOBJ(m_poJsonObject),
1668 34 : static_cast<int>(nIndex)));
1669 : }
1670 :
1671 : /************************************************************************/
1672 : /* CPLParseKeyValueJson() */
1673 : /************************************************************************/
1674 :
1675 : /** Return a string list of key/value pairs extracted from a JSON doc.
1676 :
1677 : We are expecting simple documents with key:value pairs, like the
1678 : following with no hierarchy or complex structure.
1679 : \verbatim
1680 : {
1681 : "Code" : "Success",
1682 : "LastUpdated" : "2017-07-03T16:20:17Z",
1683 : "Type" : "AWS-HMAC",
1684 : "AccessKeyId" : "bla",
1685 : "SecretAccessKey" : "bla",
1686 : "Token" : "bla",
1687 : "Expiration" : "2017-07-03T22:42:58Z"
1688 : }
1689 : \endverbatim
1690 : @since GDAL 3.7
1691 : */
1692 64 : CPLStringList CPLParseKeyValueJson(const char *pszJson)
1693 : {
1694 128 : CPLJSONDocument oDoc;
1695 64 : CPLStringList oNameValue;
1696 64 : if (pszJson != nullptr && oDoc.LoadMemory(pszJson))
1697 : {
1698 211 : for (const auto &obj : oDoc.GetRoot().GetChildren())
1699 : {
1700 154 : const auto eType = obj.GetType();
1701 154 : if (eType == CPLJSONObject::Type::String ||
1702 0 : eType == CPLJSONObject::Type::Integer ||
1703 : eType == CPLJSONObject::Type::Double)
1704 : {
1705 308 : oNameValue.SetNameValue(obj.GetName().c_str(),
1706 462 : obj.ToString().c_str());
1707 : }
1708 : }
1709 : }
1710 128 : return oNameValue;
1711 : }
|