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