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