Line data Source code
1 : // SPDX-License-Identifier: MIT
2 : // Copyright 2007, Mateusz Loskot
3 : // Copyright 2008-2024, Even Rouault <even.rouault at spatialys.com>
4 :
5 : /*! @cond Doxygen_Suppress */
6 :
7 : #include "ogrlibjsonutils.h"
8 :
9 : #include "cpl_string.h"
10 : #include "ogr_geometry.h"
11 : #include "ogr_p.h"
12 :
13 : #include <cmath>
14 :
15 : /************************************************************************/
16 : /* OGRJSonParse() */
17 : /************************************************************************/
18 :
19 1564 : bool OGRJSonParse(const char *pszText, json_object **ppoObj, bool bVerboseError,
20 : int nInputLength)
21 : {
22 1564 : if (ppoObj == nullptr)
23 0 : return false;
24 1564 : json_tokener *jstok = json_tokener_new();
25 1564 : const int nLen =
26 : nInputLength != -1
27 3092 : ? nInputLength
28 1528 : : (pszText == nullptr ? 0 : static_cast<int>(strlen(pszText)));
29 1564 : *ppoObj = json_tokener_parse_ex(jstok, pszText, nLen);
30 1564 : if (jstok->err != json_tokener_success)
31 : {
32 91 : if (bVerboseError)
33 : {
34 86 : CPLError(CE_Failure, CPLE_AppDefined,
35 : "JSON parsing error: %s (at offset %d)",
36 : json_tokener_error_desc(jstok->err), jstok->char_offset);
37 : }
38 :
39 91 : json_tokener_free(jstok);
40 91 : *ppoObj = nullptr;
41 91 : return false;
42 : }
43 1473 : json_tokener_free(jstok);
44 1473 : return true;
45 : }
46 :
47 : /************************************************************************/
48 : /* CPL_json_object_object_get() */
49 : /************************************************************************/
50 :
51 : // This is the same as json_object_object_get() except it will not raise
52 : // deprecation warning.
53 :
54 55353 : json_object *CPL_json_object_object_get(struct json_object *obj,
55 : const char *key)
56 : {
57 55353 : json_object *poRet = nullptr;
58 55353 : CPL_IGNORE_RET_VAL(json_object_object_get_ex(obj, key, &poRet));
59 55353 : return poRet;
60 : }
61 :
62 : /************************************************************************/
63 : /* json_ex_get_object_by_path() */
64 : /************************************************************************/
65 :
66 166 : json_object *json_ex_get_object_by_path(json_object *poObj, const char *pszPath)
67 : {
68 152 : if (poObj == nullptr || json_object_get_type(poObj) != json_type_object ||
69 318 : pszPath == nullptr || *pszPath == '\0')
70 : {
71 14 : return nullptr;
72 : }
73 152 : char **papszTokens = CSLTokenizeString2(pszPath, ".", 0);
74 373 : for (int i = 0; papszTokens[i] != nullptr; i++)
75 : {
76 262 : poObj = CPL_json_object_object_get(poObj, papszTokens[i]);
77 262 : if (poObj == nullptr)
78 41 : break;
79 221 : if (papszTokens[i + 1] != nullptr)
80 : {
81 110 : if (json_object_get_type(poObj) != json_type_object)
82 : {
83 0 : poObj = nullptr;
84 0 : break;
85 : }
86 : }
87 : }
88 152 : CSLDestroy(papszTokens);
89 152 : return poObj;
90 : }
91 :
92 : /************************************************************************/
93 : /* OGRGeoJSONFindMemberByName */
94 : /************************************************************************/
95 :
96 29080 : lh_entry *OGRGeoJSONFindMemberEntryByName(json_object *poObj,
97 : const char *pszName)
98 : {
99 29080 : if (nullptr == pszName || nullptr == poObj)
100 4 : return nullptr;
101 :
102 29076 : if (nullptr != json_object_get_object(poObj))
103 : {
104 29070 : lh_entry *entry = json_object_get_object(poObj)->head;
105 72412 : while (entry != nullptr)
106 : {
107 63848 : if (EQUAL(static_cast<const char *>(entry->k), pszName))
108 20506 : return entry;
109 43342 : entry = entry->next;
110 : }
111 : }
112 :
113 8570 : return nullptr;
114 : }
115 :
116 21850 : json_object *OGRGeoJSONFindMemberByName(json_object *poObj, const char *pszName)
117 : {
118 21850 : lh_entry *entry = OGRGeoJSONFindMemberEntryByName(poObj, pszName);
119 21850 : if (nullptr == entry)
120 6163 : return nullptr;
121 15687 : return static_cast<json_object *>(const_cast<void *>(entry->v));
122 : }
123 :
124 : /************************************************************************/
125 : /* OGR_json_double_with_precision_to_string() */
126 : /************************************************************************/
127 :
128 34060 : static int OGR_json_double_with_precision_to_string(struct json_object *jso,
129 : struct printbuf *pb,
130 : int /* level */,
131 : int /* flags */)
132 : {
133 : const void *userData =
134 : #if (!defined(JSON_C_VERSION_NUM)) || (JSON_C_VERSION_NUM < JSON_C_VER_013)
135 : jso->_userdata;
136 : #else
137 34060 : json_object_get_userdata(jso);
138 : #endif
139 : // Precision is stored as a uintptr_t content casted to void*
140 34060 : const uintptr_t nPrecisionIn = reinterpret_cast<uintptr_t>(userData);
141 34060 : const double dfVal = json_object_get_double(jso);
142 34060 : if (fabs(dfVal) > 1e50 && !std::isinf(dfVal))
143 : {
144 2 : char szBuffer[75] = {};
145 : const size_t nLen =
146 2 : CPLsnprintf(szBuffer, sizeof(szBuffer), "%.17g", dfVal);
147 2 : return printbuf_memappend(pb, szBuffer, static_cast<int>(nLen));
148 : }
149 : else
150 : {
151 34058 : const bool bPrecisionIsNegative =
152 34058 : (nPrecisionIn >> (8 * sizeof(nPrecisionIn) - 1)) != 0;
153 34058 : const int nPrecision =
154 34058 : bPrecisionIsNegative ? 15 : static_cast<int>(nPrecisionIn);
155 34058 : OGRWktOptions opts(nPrecision, /* round = */ true);
156 34058 : opts.format = OGRWktFormat::F;
157 :
158 68116 : const std::string s = OGRFormatDouble(dfVal, opts, 1);
159 :
160 34058 : return printbuf_memappend(pb, s.data(), static_cast<int>(s.size()));
161 : }
162 : }
163 :
164 : /************************************************************************/
165 : /* json_object_new_double_with_precision() */
166 : /************************************************************************/
167 :
168 34258 : json_object *json_object_new_double_with_precision(double dfVal,
169 : int nCoordPrecision)
170 : {
171 34258 : json_object *jso = json_object_new_double(dfVal);
172 34258 : json_object_set_serializer(
173 : jso, OGR_json_double_with_precision_to_string,
174 34258 : reinterpret_cast<void *>(static_cast<uintptr_t>(nCoordPrecision)),
175 : nullptr);
176 34258 : return jso;
177 : }
178 :
179 : /************************************************************************/
180 : /* OGR_json_double_with_significant_figures_to_string() */
181 : /************************************************************************/
182 :
183 8548 : static int OGR_json_double_with_significant_figures_to_string(
184 : struct json_object *jso, struct printbuf *pb, int /* level */,
185 : int /* flags */)
186 : {
187 8548 : char szBuffer[75] = {};
188 8548 : int nSize = 0;
189 8548 : const double dfVal = json_object_get_double(jso);
190 8548 : if (std::isnan(dfVal))
191 1 : nSize = CPLsnprintf(szBuffer, sizeof(szBuffer), "NaN");
192 8547 : else if (std::isinf(dfVal))
193 : {
194 4 : if (dfVal > 0)
195 3 : nSize = CPLsnprintf(szBuffer, sizeof(szBuffer), "Infinity");
196 : else
197 1 : nSize = CPLsnprintf(szBuffer, sizeof(szBuffer), "-Infinity");
198 : }
199 : else
200 : {
201 8543 : char szFormatting[32] = {};
202 : const void *userData =
203 : #if (!defined(JSON_C_VERSION_NUM)) || (JSON_C_VERSION_NUM < JSON_C_VER_013)
204 : jso->_userdata;
205 : #else
206 8543 : json_object_get_userdata(jso);
207 : #endif
208 8543 : const uintptr_t nSignificantFigures =
209 : reinterpret_cast<uintptr_t>(userData);
210 8543 : const bool bSignificantFiguresIsNegative =
211 8543 : (nSignificantFigures >> (8 * sizeof(nSignificantFigures) - 1)) != 0;
212 8543 : const int nInitialSignificantFigures =
213 : bSignificantFiguresIsNegative
214 8543 : ? 17
215 : : static_cast<int>(nSignificantFigures);
216 8543 : CPLsnprintf(szFormatting, sizeof(szFormatting), "%%.%dg",
217 : nInitialSignificantFigures);
218 8543 : nSize = CPLsnprintf(szBuffer, sizeof(szBuffer), szFormatting, dfVal);
219 8543 : const char *pszDot = strchr(szBuffer, '.');
220 :
221 : // Try to avoid .xxxx999999y or .xxxx000000y rounding issues by
222 : // decreasing a bit precision.
223 8543 : if (nInitialSignificantFigures > 10 && pszDot != nullptr &&
224 6865 : (strstr(pszDot, "999999") != nullptr ||
225 6721 : strstr(pszDot, "000000") != nullptr))
226 : {
227 249 : bool bOK = false;
228 280 : for (int i = 1; i <= 3; i++)
229 : {
230 271 : CPLsnprintf(szFormatting, sizeof(szFormatting), "%%.%dg",
231 : nInitialSignificantFigures - i);
232 271 : nSize = CPLsnprintf(szBuffer, sizeof(szBuffer), szFormatting,
233 : dfVal);
234 271 : pszDot = strchr(szBuffer, '.');
235 271 : if (pszDot != nullptr && strstr(pszDot, "999999") == nullptr &&
236 243 : strstr(pszDot, "000000") == nullptr)
237 : {
238 240 : bOK = true;
239 240 : break;
240 : }
241 : }
242 249 : if (!bOK)
243 : {
244 9 : CPLsnprintf(szFormatting, sizeof(szFormatting), "%%.%dg",
245 : nInitialSignificantFigures);
246 9 : nSize = CPLsnprintf(szBuffer, sizeof(szBuffer), szFormatting,
247 : dfVal);
248 : }
249 : }
250 :
251 8543 : if (nSize + 2 < static_cast<int>(sizeof(szBuffer)) &&
252 8543 : strchr(szBuffer, '.') == nullptr &&
253 1678 : strchr(szBuffer, 'e') == nullptr)
254 : {
255 1653 : nSize +=
256 1653 : CPLsnprintf(szBuffer + nSize, sizeof(szBuffer) - nSize, ".0");
257 : }
258 : }
259 :
260 17096 : return printbuf_memappend(pb, szBuffer, nSize);
261 : }
262 :
263 : /************************************************************************/
264 : /* json_object_new_double_with_significant_figures() */
265 : /************************************************************************/
266 :
267 : json_object *
268 10800 : json_object_new_double_with_significant_figures(double dfVal,
269 : int nSignificantFigures)
270 : {
271 10800 : json_object *jso = json_object_new_double(dfVal);
272 10800 : json_object_set_serializer(
273 : jso, OGR_json_double_with_significant_figures_to_string,
274 10800 : reinterpret_cast<void *>(static_cast<uintptr_t>(nSignificantFigures)),
275 : nullptr);
276 10800 : return jso;
277 : }
278 :
279 : /************************************************************************/
280 : /* GeoJSONPropertyToFieldType() */
281 : /************************************************************************/
282 :
283 : constexpr GIntBig MY_INT64_MAX =
284 : (static_cast<GIntBig>(0x7FFFFFFF) << 32) | 0xFFFFFFFF;
285 : constexpr GIntBig MY_INT64_MIN = static_cast<GIntBig>(0x80000000) << 32;
286 :
287 20784 : OGRFieldType GeoJSONPropertyToFieldType(json_object *poObject,
288 : OGRFieldSubType &eSubType,
289 : bool bArrayAsString)
290 : {
291 20784 : eSubType = OFSTNone;
292 :
293 20784 : if (poObject == nullptr)
294 : {
295 14 : return OFTString;
296 : }
297 :
298 20770 : json_type type = json_object_get_type(poObject);
299 :
300 20770 : if (json_type_boolean == type)
301 : {
302 31 : eSubType = OFSTBoolean;
303 31 : return OFTInteger;
304 : }
305 20739 : else if (json_type_double == type)
306 636 : return OFTReal;
307 20103 : else if (json_type_int == type)
308 : {
309 13330 : GIntBig nVal = json_object_get_int64(poObject);
310 13330 : if (!CPL_INT64_FITS_ON_INT32(nVal))
311 : {
312 34 : if (nVal == MY_INT64_MIN || nVal == MY_INT64_MAX)
313 : {
314 : static bool bWarned = false;
315 1 : if (!bWarned)
316 : {
317 1 : bWarned = true;
318 1 : CPLError(
319 : CE_Warning, CPLE_AppDefined,
320 : "Integer values probably ranging out of 64bit integer "
321 : "range have been found. Will be clamped to "
322 : "INT64_MIN/INT64_MAX");
323 : }
324 : }
325 34 : return OFTInteger64;
326 : }
327 : else
328 : {
329 13296 : return OFTInteger;
330 : }
331 : }
332 6773 : else if (json_type_string == type)
333 6317 : return OFTString;
334 456 : else if (json_type_array == type)
335 : {
336 419 : if (bArrayAsString)
337 : {
338 1 : eSubType = OFSTJSON;
339 1 : return OFTString;
340 : }
341 418 : const auto nSize = json_object_array_length(poObject);
342 418 : if (nSize == 0)
343 : {
344 1 : eSubType = OFSTJSON;
345 1 : return OFTString;
346 : }
347 417 : OGRFieldType eType = OFTIntegerList;
348 973 : for (auto i = decltype(nSize){0}; i < nSize; i++)
349 : {
350 604 : json_object *poRow = json_object_array_get_idx(poObject, i);
351 604 : if (poRow != nullptr)
352 : {
353 604 : type = json_object_get_type(poRow);
354 604 : if (type == json_type_string)
355 : {
356 125 : if (i == 0 || eType == OFTStringList)
357 : {
358 122 : eType = OFTStringList;
359 : }
360 : else
361 : {
362 3 : eSubType = OFSTJSON;
363 3 : return OFTString;
364 : }
365 : }
366 479 : else if (type == json_type_double)
367 : {
368 97 : if (eSubType == OFSTNone &&
369 30 : (i == 0 || eType == OFTRealList ||
370 2 : eType == OFTIntegerList || eType == OFTInteger64List))
371 : {
372 97 : eType = OFTRealList;
373 : }
374 : else
375 : {
376 0 : eSubType = OFSTJSON;
377 0 : return OFTString;
378 : }
379 : }
380 382 : else if (type == json_type_int)
381 : {
382 302 : if (eSubType == OFSTNone && eType == OFTIntegerList)
383 : {
384 265 : GIntBig nVal = json_object_get_int64(poRow);
385 265 : if (!CPL_INT64_FITS_ON_INT32(nVal))
386 265 : eType = OFTInteger64List;
387 : }
388 37 : else if (eSubType == OFSTNone &&
389 5 : (eType == OFTInteger64List ||
390 : eType == OFTRealList))
391 : {
392 : // ok
393 : }
394 : else
395 : {
396 3 : eSubType = OFSTJSON;
397 3 : return OFTString;
398 : }
399 : }
400 80 : else if (type == json_type_boolean)
401 : {
402 39 : if (i == 0 ||
403 4 : (eType == OFTIntegerList && eSubType == OFSTBoolean))
404 : {
405 38 : eSubType = OFSTBoolean;
406 : }
407 : else
408 : {
409 1 : eSubType = OFSTJSON;
410 1 : return OFTString;
411 : }
412 : }
413 : else
414 : {
415 41 : eSubType = OFSTJSON;
416 41 : return OFTString;
417 : }
418 : }
419 : else
420 : {
421 0 : eSubType = OFSTJSON;
422 0 : return OFTString;
423 : }
424 : }
425 :
426 369 : return eType;
427 : }
428 37 : else if (json_type_object == type)
429 : {
430 37 : eSubType = OFSTJSON;
431 37 : return OFTString;
432 : }
433 :
434 0 : return OFTString; // null
435 : }
436 :
437 : /*! @endcond */
|