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